Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use livedata and viewmodel with a viewholder as Lifecycle Owner?

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.

like image 231
Hari Avatar asked Feb 22 '19 10:02

Hari


People also ask

How do you make a ViewModel lifecycle aware?

Lifecycle Aware Components ViewModel already responds to lifecycle events via its onCleared callback. The ViewModel's lifecycle differs from the View yet gets notified when it will no longer be needed. To further empower its lifecycle awareness, we can rely on Google's Jetpack library androidx. lifecycle .

What is view lifecycle owner?

viewLifeCycleOwner is LifecycleOwner that represents the Fragment's View lifecycle. In most cases, this mirrors the lifecycle of the Fragment itself, but in cases of detached Fragments, the lifecycle of the Fragment can be considerably longer than the lifecycle of the View itself.

Is LiveData lifecycle aware?

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services.


1 Answers

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:

  1. Pass the LiveData on the constructor of your adapter class:
class MyAdapter(private var data: LiveData<Int>) : RecyclerView.Adapter<MyViewHolder>() {
  1. add an observer at the creation fo the viewHolder:
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
}
  1. Set the right visual state for the viewHolder when the viewHolder is associated with a model element
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.

like image 169
AndrewBloom Avatar answered Sep 20 '22 15:09

AndrewBloom