Reputation: 442
I'm having a recyclerview (verticalRV) which scrolls vertically. Each item in this recyclerview(horizontalRV) is a Horizontal recyclerview.
Inside the verticalRV itemViewHodler im trying to fetch data from the viewmodel and observe for any chages and update the horizontalRV adapter accordingly.
But the observers is onChanged
method is not getting called.
I have implemented the LifecycleOwner interface to manage the the lifecyle of the view holder with livedata and setting the state accordingly form the adapter of verticalRV
public class VeritcalRVHolderItem implements LifecycleOwner {
private static final String TAG = LDFeedListAdapterHolder.class.getSimpleName();
private final FragmentActivity activity;
private final RvHorizontalListAdapter adapter;
private RecyclerView rvHorizontalList;
public VeritcalRVHolderItem(Context context, View itemView, FragmentActivity activity) {
super(context, itemView);
this.activity = activity;
rvHorizontalList = itemView.findViewById(R.id.rvHorizontalList);
LinearLayoutManager layout = new LinearLayoutManager(getContext(), LinearLayout.HORIZONTAL, false);
rvHorizontalList.setLayoutManager(layout);
adapter = new RvHorizontalListAdapter(this.activity);
rvHorizontalList.setAdapter(adapter);
LDViewModel LDViewModel = ViewModelProviders.of(activity).get(LDViewModel.class);
LDViewModel.getTopicsForFeed().observe(this, new Observer<List<Topic>>() {
@Override
public void onChanged(List<Topic> topics) {
//adding live discussion model at first position
adapter.updateLiveList(topics);
adapter.notifyItemChanged(0);
Log.d(TAG, "discussion model calls");
}
});
}
private LifecycleRegistry lifecycleRegistry;
public void onAppear() {
lifecycleRegistry.markState(Lifecycle.State.CREATED);
}
public void onDisappear() {
lifecycleRegistry.markState(Lifecycle.State.DESTROYED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}
Please let me know what am I missing here.
Upvotes: 14
Views: 18581
Reputation: 2428
There are 2 approaches to the problem, one is the Shyak's answer, that manages to observe the changes outside the adapter and notifies the change through a change of the data backing the list. This is actually respecting the pattern of the recycler views and adapters.
Sometimes though, we want to observe and show on the recylerview some data from a model, but also some external events and/or data. Instead of combining all these informations on a new model that comprises the aggregated data, it could be handy to observe some of the changes directly on the adapter itself.
In this case you can add an observer to the ViewHolder and react to the changes in this way:
class MyAdapter(private var data: LiveData<Int>) : RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val holder = MyViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.my_layout, parent,
false
)
)
data.observe(holder.itemView.context as LifecycleOwner, Observer {
// action to be performed by the observer
})
return holder
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
if (data.value!! >= 0 && data.value == position) {
holder.setSelected(true) // or whatever is visually necessary
} else {
holder.setSelected(false) // or whatever is visually necessary
}
}
Things to watch out: holder.itemView.context as LifecycleOwner
this basically means that the recyclerview is inside a fragment that is a lifecycle owner.
This approach can be efficient cause ViewHolder are reused, so we don't have to create new observers for the various elements of the list.
Upvotes: 15
Reputation: 21
From my perspective, it's better to observe the data into your Fragment
or Activity
class and pass the data to Recyclerview
.
In Recyclerview
override the method getItemViewType
to handle the vertical
item and horizontal
item.
Example:
ViewModel
public class ViewModel extends AndroidViewModel {
private MutableLiveData<Model> modelMutableLiveData;
public ViewModel(@NonNull Application application) {
super(application);
modelMutableLiveData = new MutableLiveData<>();
}
public MutableLiveData<Model> getModelMutableLiveData() {
return modelMutableLiveData;
}
public final void yourMethod(Model model) {
// Do something
}
}
Fragment class
public class Fragment extend BaseFragment {
private void initViewModelData() {
viewModel.getModelMutableLiveData().observe(this, new Observer<Model>() {
@Override
public void onChanged(@Nullable Model model) {
if (model != null) {
modelList.add(model);
adapter.notifyItemInserted(modelList.size()- 1);
}
}
});
}
}
RecyclerViewAdater
class RecyclerViewAdater extend Adapter<ViewHolder>{
@Override
public int getItemViewType(int position) {
return mDataList.get(position).getContainerType();
}
}
Based on this you can write your RecyclerView
code
Upvotes: 2