i am doing movies app so i am using recycler view to list all the movies list and i need to show the details of the movie in bottomsheetdialog when user click on the movie list the bottom sheet crash the app please help me what is the error here i post my code this is my code with nested recyclerview and bottomsheet with it please help me
this is recycleradapter
class ListMoviesAdapter(
private val movies: MutableList<Item>,
) :
RecyclerView.Adapter<ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var contentImage: ImageView? = itemView.findViewById(R.id.contentImage)
var contentTitle: TextView? = itemView.findViewById(R.id.contentTitle)
var contentSubTitle1: TextView? = itemView.findViewById(R.id.contentSubtitle1)
}
interface onItemClickListener {
fun onItemCLick(position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.item_6, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val MoviesData: Item = movies.get(position)
holder.contentImage?.let {
Glide.with(it)
.load(MoviesData.media.thumbnail)
.fitCenter()
.into(holder.contentImage!!)
}
holder.contentImage?.setOnClickListener {
val moviesFragment = MoviesFragment()
val bottomsheet = DetailsFragment()
bottomsheet.show(moviesFragment.requireActivity().supportFragmentManager,"Bottomsheet")
Toast.makeText(holder.itemView.context, MoviesData.text.title, Toast.LENGTH_LONG).show()
}
holder.contentTitle?.text = MoviesData.text.title
holder.contentSubTitle1?.text = MoviesData.text.subtitle1
}
override fun getItemCount(): Int {
return movies.size
}
}
this is bottom sheet
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
// override fun onAttach(context: Context) {
// adapter = ImageSliderAdapter(context)
// super.onAttach(context)
// }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_movies, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val imageslider = view.findViewById<SliderView>(R.id.image_slider)
val slider: MutableList<Item> = mutableListOf()
adapter = ImageSliderAdapter(requireContext())
movie_recycle = view.findViewById(R.id.movie_recycle)
imageslider.setSliderAdapter(adapter)
partner_recycle = view.findViewById(R.id.partnets_scroll)
imageslider.setIndicatorAnimation(IndicatorAnimationType.WORM) //set indicator animation by using SliderLayout.IndicatorAnimations. :WORM or THIN_WORM or COLOR or DROP or FILL or NONE or SCALE or SCALE_DOWN or SLIDE and SWAP!!
imageslider.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION)
imageslider.autoCycleDirection = SliderView.AUTO_CYCLE_DIRECTION_BACK_AND_FORTH
imageslider.scrollTimeInSec = 3
imageslider.isAutoCycle = true
imageslider.startAutoCycle()
setupView()
getMovieList()
adapter.addImageslider(slider)
super.onViewCreated(view, savedInstanceState)
}
fun addmovielist(movies: MutableList<Item>) {
adapter.addImageslider(movies)
}
private fun getMovieList() {
val apicall = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build()
.create(Api::class.java)
val moviedata = apicall.GetMovieList()
moviedata.enqueue(object : Callback<ImageSLider> {
override fun onResponse(call: Call<ImageSLider>, response: Response<ImageSLider>) {
val responeBody = response.body()!!
val page = responeBody.page.body.rows[0].items
addmovielist(page)
partner_list(responeBody.page.body.rows[1].items)
val size = responeBody.page.body.rows.size - 1
for (data in 3..size) {
list_movies.add(responeBody.page.body.rows[data])
}
movies_list(list_movies)
}
override fun onFailure(call: Call<ImageSLider>, t: Throwable) {
Toast.makeText(requireActivity(), t.toString(), Toast.LENGTH_LONG).show()
}
})
}
#SuppressLint("NotifyDataSetChanged")
fun partner_list(part_list: MutableList<Item>) {
all_partner.addAll(part_list)
partner_adapter = PartnerAdapter(all_partner)
partner_recycle.adapter?.notifyDataSetChanged()
}
#SuppressLint("NotifyDataSetChanged")
fun movies_list(movie_lst: MutableList<Rows>) {
all_movies.addAll(movie_lst)
ContentAdapter(all_movies)
movie_recycle.adapter?.notifyDataSetChanged()
}
fun setupView() {
partner_recycle.adapter = PartnerAdapter(all_partner)
partner_recycle.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
movie_recycle.adapter = ContentAdapter(all_movies)
movie_recycle.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
}
this is nested recyclerview
class ContentAdapter(val item: MutableList<Rows>) :
RecyclerView.Adapter<ContentAdapter.ContentAdapterVH>() {
var itemlist: MutableList<Item> = mutableListOf()
class ContentAdapterVH(itemView: View?) : RecyclerView.ViewHolder(itemView!!) {
val recycleMovie: RecyclerView? = itemView?.findViewById(R.id.movie_scroll)
val categoryText: TextView? = itemView?.findViewById(R.id.title_movie_txt)
val dashboardScreen = DashboardScreen()
val moviesFragment = MoviesFragment()
fun bind(data: Rows) {
recycleMovie?.apply {
recycleMovie.adapter = ListMoviesAdapter(data.items, moviesFragment)
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentAdapterVH {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.item_6_list, parent, false)
return ContentAdapterVH(view)
}
override fun onBindViewHolder(holder: ContentAdapterVH, position: Int) {
val contentData: Rows = item.get(position)
holder.categoryText?.text = contentData.text.title
holder.bind(contentData)
}
override fun getItemCount(): Int {
return item.size
}
}
please help to solve this or give any link to refer this thank you
Just create a object class and create a method for bottom sheet and pass the context to this method. And from adapter, call this method on click on the item or where you want to display the bottom sheet
Simple way is that you have to set click listener on onBindViewHolder method in adapter and directly call this showBottomSheet method. And pass the required data to it for displaying is in bottom sheet
object BottomSheetUtils {
fun showBottomSheet(
context:Context
) {
val bottomSheetDialog = BottomSheetDialog(context)
bottomSheetDialog.setContentView(R.layout.your_custom_bottom_sheet_layout)
// Just update UI and set click listeners etc...
bottomSheetDialog.textviewName.text = "Example"
bottomSheetDialog.show()
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val MoviesData: Item = movies.get(position)
holder.contentImage?.let {
Glide.with(it)
.load(MoviesData.media.thumbnail)
.fitCenter()
.into(holder.contentImage!!)
}
holder.contentImage?.setOnClickListener {
val moviesFragment = MoviesFragment()
val bottomsheet = DetailsFragment()
bottomsheet.show(appcompActivity.supportFragmentManager,"Bottomsheet")
Toast.makeText(holder.itemView.context, MoviesData.text.title, Toast.LENGTH_LONG).show()
}
holder.contentTitle?.text = MoviesData.text.title
holder.contentSubTitle1?.text = MoviesData.text.subtitle1
}
I Pass appcompactivity to the bottom adapter and trigger the bottom sheet using support fragment manager thank you all
Related
I have a RecyclerView and my Fragment. I am getting data from Firebase Realtime Database into a RecyclerView.
I need to make it so that while the data is loading, I see some kind of loading effect. How can i do this?
Code from my Fragment:
private var _binding: FragmentDayDetailBinding? = null
private val binding get() = _binding!!
private var ref: DatabaseReference? = null
private lateinit var adapter: DayDetailAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDayDetailBinding.inflate(inflater, container, false)
setupRecyclerView()
initDatabase()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
readFromDatabase()
}
private fun setupRecyclerView() {
adapter = DayDetailAdapter()
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerView.adapter = adapter
}
private fun initDatabase() {
FirebaseApp.initializeApp(requireContext())
ref = FirebaseDatabase.getInstance()
.getReference("IMIT")
.child("groups")
}
private fun readFromDatabase() {
ref?.addValueEventListener(object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
val list = ArrayList<Day>()
for (daySnapshot in snapshot.children) {
val day = daySnapshot.getValue(Day::class.java)
list.add(day!!)
}
adapter.submitList(list)
} else {
binding.apply {
lrDbEmpty.visibility = View.VISIBLE
recyclerView.visibility = View.INVISIBLE
}
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
Code from RecyclerView Adapter:
class ViewHolder(private val binding: ItemSubjectDetailBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(day: Day) = with(binding) {
tvSubject.text = day.subject
tvInfo.text = "${day.teacher}, ${day.type}"
tvTime.text = day.time
tvAud.text = day.classroom
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemSubjectDetailBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder.from(parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
bind(getItem(position))
}
}
class ItemComparator: DiffUtil.ItemCallback<Day>() {
override fun areItemsTheSame(oldItem: Day, newItem: Day): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Day, newItem: Day): Boolean {
return oldItem == newItem
}
}
You already in half the way
Create a progressBar in the center of the fragment
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
Keep it visible until the data fetched (onDataChange Called) then hide the progressBar
override fun onDataChange(snapshot: DataSnapshot) {
binding.progressBar.visibility = View.GONE
if (snapshot.exists()) {
// rest of your code
}
}
I prefer a dynamic add view.
I use the lottie player for the show wait animation. There are two approaches for adding the show wait. In this way, you can add animation or any type of view from the non-activity class. It helps you to better implement in the MVVM form.
This is both methods implementation.
1- Create and remove by Id
2- Create and remove by LiveData
class AddViewNonActivity(
private val viewGroup: ViewGroup
) {
fun addCustomWait(): Int {
val relativeLayout =
RelativeLayout(viewGroup.context)
val relativeParams =
RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
val lottieParams =
RelativeLayout.LayoutParams(600, 600)
relativeLayout.setBackgroundColor(
viewGroup.context.getColor(R.color.wait_transparent)
)
relativeLayout.gravity = CENTER
val lottieLoading = LottieAnimationView(viewGroup.context)
lottieLoading.setAnimation("lottie/space-runner.json")
lottieLoading.repeatCount = INFINITE
lottieLoading.speed = 1f
lottieLoading.playAnimation()
relativeLayout.addView(lottieLoading, lottieParams)
val viewId = View.generateViewId()
viewGroup.addView(relativeLayout, relativeParams)
relativeLayout.id = viewId
relativeLayout.isClickable = true
return viewId
}
fun removeCustomWait(
waitViewId: Int
) {
for (view in viewGroup) {
if (view.id == waitViewId)
viewGroup.removeView(view)
}
}
fun addLiveCustomWait(
lifecycleOwner: LifecycleOwner,
liveData: LiveData<Boolean>) {
var viewId = 0
liveData.observe(lifecycleOwner) {
if (it) {
removeCustomWait(viewId)
viewId = addCustomWait()
} else {
removeCustomWait(viewId)
}
}
}
}
Activity call method
class DynamicViewActivity : AppCompatActivity() {
private lateinit var binding : ActivityDynamicViewBinding
private val liveShowWait =MutableLiveData(false)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDynamicViewBinding.inflate(layoutInflater)
setContentView(binding.root)
var waitId = 0
initialWait()
binding.btnAddView.setOnClickListener {
waitId = AddViewNonActivity(binding.root).addCustomWait()
}
binding.btnRemoveView.setOnClickListener {
AddViewNonActivity(binding.root).removeCustomWait(waitId)
}
binding.btnLiveAddView.setOnClickListener {
liveShowWait.postValue(true)
}
binding.btnLiveRemoveView.setOnClickListener {
liveShowWait.postValue(false)
}
}
private fun initialWait() =
AddViewNonActivity(binding.root).addLiveCustomWait(this as
LifecycleOwner, liveShowWait)
}
Github link
I implemented SelectionTracker for RecycleView and it works fine until I navigate to another fragment and press the back button. After navigation, it stops working correctly and after selection I can't deselect item anymore.
I created a sample project on github and I can reproduce bug there:
https://github.com/alborozd/RecycleViewSelectionProblem
Here is my code from that sample project:
Adapter and ViewHolder:
class MyListAdapter()
: ListAdapter<MyModel, MyListAdapter.MyItemViewHolder>(DiffCallback()) {
init {
setHasStableIds(true)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
private var tracker: SelectionTracker<String>? = null
fun setTracker(tracker: SelectionTracker<String>?) {
this.tracker = tracker
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyItemViewHolder {
return MyItemViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false),
this
)
}
override fun onBindViewHolder(holder: MyItemViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item, tracker!!.isSelected(item.id))
}
class MyItemViewHolder(itemView: View, private val adapter: MyListAdapter) : RecyclerView.ViewHolder(itemView) {
private var text: TextView? = null
private var container: View? = null
init {
text = itemView.findViewById(R.id.text)
container = itemView.findViewById(R.id.itemContainer)
}
fun bind(item: MyModel, selected: Boolean) {
text?.text = item.name
if (selected) {
val theme = itemView.context!!.theme
container?.setBackgroundColor(
itemView.context!!.resources.getColor(
android.R.color.darker_gray,
theme
)
)
} else {
container?.setBackgroundColor(0)
}
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<String> =
object : ItemDetailsLookup.ItemDetails<String>() {
override fun getPosition(): Int = adapterPosition
override fun getSelectionKey(): String? = adapter.getItem(adapterPosition).id
override fun inSelectionHotspot(e: MotionEvent): Boolean {
return true
}
}
}
class DiffCallback : DiffUtil.ItemCallback<MyModel>() {
override fun areItemsTheSame(oldItem: MyModel, newItem: MyModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: MyModel, newItem: MyModel): Boolean {
return oldItem == newItem
}
}
}
ItemIdKeyProvider:
class ItemIdKeyProvider(
private val adapter: MyListAdapter
) : ItemKeyProvider<String>(SCOPE_MAPPED) {
override fun getKey(position: Int): String? {
return adapter.currentList[position].id
}
override fun getPosition(key: String): Int {
return adapter.currentList.indexOfFirst { c -> c.id == key }
}
}
ItemLookup:
class ItemLookup(private val rv: RecyclerView) : ItemDetailsLookup<String>() {
override fun getItemDetails(event: MotionEvent)
: ItemDetails<String>? {
val view = rv.findChildViewUnder(event.x, event.y)
if (view != null) {
return (rv.getChildViewHolder(view) as MyListAdapter.MyItemViewHolder)
.getItemDetails()
}
return null
}
}
And here is how I initialize all of this in my fragment:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
viewModel = createViewModel()
binding = DataBindingUtil.inflate(inflater, R.layout.main_fragment, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = this
viewModel.initViewModel()
viewModel.items.observe(this, Observer { items ->
val adapter = MyListAdapter()
adapter.submitList(items)
binding.recycleView.adapter = adapter
trackSelectedItems(adapter, binding.recycleView)
adapter.notifyDataSetChanged()
})
binding.btnGoToNextFragment.setOnClickListener {
val action = MainFragmentDirections.actionMainFragmentToOtherFragment()
findNavController().navigate(action)
}
return binding.root
}
private fun trackSelectedItems(
adapter: MyListAdapter,
recyclerView: RecyclerView
) {
tracker = SelectionTracker.Builder<String>(
"selectionTracker",
recyclerView,
ItemIdKeyProvider(adapter),
ItemLookup(recyclerView),
StorageStrategy.createStringStorage()
).withSelectionPredicate(SelectionPredicates.createSelectAnything())
.build()
adapter.setTracker(tracker)
tracker.addObserver(object : SelectionTracker.SelectionObserver<String>() {
override fun onSelectionChanged() {
super.onSelectionChanged()
}
})
}
Steps to reproduce:
Open first fragment with recycleview, try to select/deselect items. Everything works fine
Go to another fragment, then press back button
Try to select/deselect items again and you'll see that deselection doesn't work anymore
Don't initialize adapter inside live data's observer. Because Live Data might be observed n number of times, so if you initialize adapter inside that, adapter will be initialized many times.
To resolve issue use below code
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
viewModel = createViewModel()
binding = DataBindingUtil.inflate(inflater, R.layout.main_fragment, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = this
viewModel.initViewModel()
val adapter = MyListAdapter()
binding.recycleView.adapter = adapter
trackSelectedItems(adapter, binding.recycleView)
//adapter.notifyDataSetChanged()
viewModel.items.observe(this, Observer { items ->
adapter.submitList(items)
})
binding.btnGoToNextFragment.setOnClickListener {
val action = MainFragmentDirections.actionMainFragmentToOtherFragment()
findNavController().navigate(action)
}
return binding.root
}
I'm using a RecyclerView to show some info from Firebase, with kotlin in Android Studio.
But when I click on the RecyclerView, it return the position as -1, so the page that opens that item is always empty...
This is my code from setOnClickListener on the ViewHolder:
class CustomViewHolder(view: View): RecyclerView.ViewHolder(view){
val titulo = view.findViewById<TextView>(R.id.txtTitle)
val localizacao = view.findViewById<TextView>(R.id.txtDescription)
//val urlPag = view.findViewById<TextView>(R.id.record_amount)
//val descricao = view.findViewById<TextView>(R.id.record_date)
val img = view.findViewById<ImageView>(R.id.imageItem)
init {
view.setOnClickListener{
val position: String = CustomViewHolder(it).bindingAdapterPosition.toString()
val intent = Intent(view.context, NotificationActivity::class.java).apply {
putExtra("id", position)
println(position)
}
view.context.startActivity(intent)
}
}
}
This is the fragment were the recyclerView is:
class InboxFragment : Fragment() {
private var listData: List<Notifications>? = null
private var adapter: MainAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_inbox, container, false)
val rv = view.findViewById<RecyclerView>(R.id.recyclerView)
rv.setHasFixedSize(true)
rv.layoutManager = LinearLayoutManager(context)
listData = ArrayList()
val nm = FirebaseDatabase.getInstance().getReference("notifications")
nm.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
for (npsnapshot in dataSnapshot.children) {
val l: Notifications? = npsnapshot.getValue(Notifications::class.java)
if (l != null) {
(listData as ArrayList<Notifications>).add(l)
}
}
adapter = MainAdapter(listData)
rv.adapter = adapter
}
}
override fun onCancelled(databaseError: DatabaseError) {}
})
return view
}
}
This is the adapter:
class MainAdapter(var listData: List<Notifications>?) : RecyclerView.Adapter<CustomViewHolder>(){
override fun getItemCount(): Int {
return listData!!.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
//create view
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.inforow, parent, false)
return CustomViewHolder(cellForRow)
}
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val ld: Notifications = listData!![position]
holder.titulo.text = ld.titulo
holder.localizacao.text = ld.localizacao
Picasso.get().load(ld.img).into(holder.img)
}
}
Can someone please help?
Not sure why is this behaviour, but almost tried everything, please let me know in case you are aware of the fix for the issue
When I return from SellerAddNewProductActivity by clicking back button then RecyclerView always scroll to beginning
class SellerHomeFragment : Fragment() {
private var searchInputText:String = ""
private var sellerProductsViewListRecyclerView: RecyclerView? = null
private var layoutManager: RecyclerView.LayoutManager? = null
private var scroll_state: Parcelable? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_seller_home, container, false)
sellerProductsViewListRecyclerView = root.findViewById(R.id.seller_products_view_list)
layoutManager = LinearLayoutManager(this.context)
sellerProductsViewListRecyclerView?.layoutManager = layoutManager
val searchText: EditText = root.findViewById(R.id.seller_search_product_name)
val searchProductsBtn: Button = root.findViewById(R.id.seller_search_products_btn)
val sellerViewByProductState: Spinner = root.findViewById(R.id.seller_view_by_product_state)
sellerViewByProductState.setSelection(0)
searchProductsBtn.setOnClickListener {
searchInputText = searchText.text.toString()
createProductRecyclerView()
}
sellerViewByProductState?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
createProductRecyclerView()
}
}
return root
}
override fun onResume() {
super.onResume()
if(scroll_state!=null){
sellerProductsViewListRecyclerView!!.layoutManager!!.onRestoreInstanceState(scroll_state)
}
}
override fun onPause() {
super.onPause()
scroll_state = sellerProductsViewListRecyclerView!!.layoutManager!!.onSaveInstanceState()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
createProductRecyclerView()
}
private fun createProductRecyclerView() {
var productRef: DatabaseReference = FirebaseDatabase.getInstance().reference.child(
PRODUCTS_DB_NAME
)
var options: FirebaseRecyclerOptions<Products>? = null
val sellerViewByProductState: Spinner =
requireView().findViewById(R.id.seller_view_by_product_state)
val selectedProductState = sellerViewByProductState.selectedItem.toString()
options = FirebaseRecyclerOptions.Builder<Products>().setQuery(
productRef.child(selectedProductState).orderByChild(SID_PROPERTY)
.equalTo(FirebaseAuth.getInstance().currentUser!!.uid), Products::class.java
).setLifecycleOwner(this).build()
val adapter = object : FirebaseRecyclerAdapter<Products, ProductViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.product_items_layout, parent, false)
)
}
protected override fun onBindViewHolder(
holder: ProductViewHolder,
position: Int,
model: Products
) {
holder.txtProductName.text = model.pname
holder.txtProductDescription.text = model.description
holder.txtProductPrice.text = "Price = ₹ " + model.price.toString()
val context = holder.itemView.context
Picasso.with(this#SellerHomeFragment.context).load(model.image).networkPolicy(
NetworkPolicy.OFFLINE
).tag(context).into(holder.imageView,
object : Callback {
override fun onSuccess() {
}
override fun onError() {
Picasso.with(this#SellerHomeFragment.context).load(model.image)
.into(holder.imageView)
}
})
holder.itemView.setOnClickListener {
val intent: Intent = Intent(
this#SellerHomeFragment.context,
SellerAddNewProductActivity::class.java
)
intent.putExtra("category", model.category)
intent.putExtra("pid", model.pid)
val sellerViewByProductState: Spinner =
requireView().findViewById(R.id.seller_view_by_product_state)
val existingProductState = sellerViewByProductState.selectedItem.toString()
intent.putExtra("existingProductState", existingProductState)
startActivity(intent)
}
}
}
sellerProductsViewListRecyclerView?.setAdapter(adapter)
adapter.startListening()
}
}
I'm not sure I understand your code, but I think if you call function setAdapter(adapter) after added product you reload adapter.
When you add item to adapter use function notifyItemInserted() or notifyItemRangeInserted(position, range) on adapter.
I am using MVVM with Room persistence and livedata. I am fetching the data from local database and want to show in the form of list in the recyclerView and my recyclerView is not showing anything.
My adapter is like any other regular adapter
RecyclerView Code
class MyInformationAdapter : RecyclerView.Adapter<MyInformationAdapter.ViewHolder>() {
private var myList: List<PersonInformation> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.my_adapter_data, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int = myList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
var myDataClass: PersonInformation = myList[position]
holder.name.text = myDataClass.name
holder.fName.text = myDataClass.fatherName
holder.email.text = myDataClass.email
holder.contact.text = myDataClass.contactNo.toString()
}
fun updateTheState(myList: List<PersonInformation>){
this.myList = myList
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name: TextView = itemView.findViewById(R.id.yourName)
var fName: TextView = itemView.findViewById(R.id.yourFatherName)
var email: TextView = itemView.findViewById(R.id.yourEmail)
var contact: TextView = itemView.findViewById(R.id.yourContact)
}
}
RecyclerView Activity Code
class FinalActivity : AppCompatActivity() {
private var myDataList : List<PersonInformation> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_final)
setAdapter()
}
private fun setAdapter() {
val adapter = MyInformationAdapter()
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = adapter
adapter.updateTheState(myDataList)
}
}
*Fragment as a View of MVVM *
class PersonalInformationFragment : Fragment() {
private var viewModel: PersonInformationViewModel? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_personal_information, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
btn.setOnClickListener {
viewModel = ViewModelProviders.of(this)[PersonInformationViewModel::class.java]
viewModel?.getAllData()?.observe(this, Observer {
this.setAllData(it)
})
val intent = Intent(activity, FinalActivity::class.java)
startActivity(intent)
}
}
private fun setAllData(personInformation: List<PersonInformation>) {
val setData = PersonInformation(
name.text.toString(),
fName.text.toString(),
email.text.toString(),
contact.text.toString().toInt()
)
viewModel?.setTheData(setData)
}
}