如何将 livedata 和 viewmodel 与 Viewholder 作为生命周期所有者一起使用?

Har*_*ari 13 android mvvm viewmodel android-recyclerview android-livedata

我有一个垂直滚动的回收视图(verticalRV)。此回收站视图(horizo​​ntalRV)中的每个项目都是一个水平回收站视图。

在 verticalRV itemViewHodler 内部,我试图从视图模型中获取数据并观察是否有任何变化并相应地更新 horizo​​ntalRV 适配器。

但是观察者是onChanged方法没有被调用。

我已经实现了 LifecycleOwner 接口来管理带有 livedata 的视图持有者的生命周期,并相应地从 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

请让我知道我在这里缺少什么。

And*_*oom 11

有两种方法可以解决这个问题,一种是 Shyak 的答案,它设法观察适配器外部的更改,并通过支持列表的数据更改来通知更改。这实际上是在尊重回收者视图和适配器的模式。

但有时,我们希望在 recylerview 上观察并显示来自模型的一些数据,以及一些外部事件和/或数据。与其在包含聚合数据的新模型上组合所有这些信息,不如直接在适配器本身上观察一些变化。

在这种情况下,您可以将观察者添加到 ViewHolder 并以这种方式对更改做出反应:

  1. 在适配器类的构造函数上传递 LiveData:
class MyAdapter(private var data: LiveData<Int>) : RecyclerView.Adapter<MyViewHolder>() {
Run Code Online (Sandbox Code Playgroud)
  1. 在 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
}
Run Code Online (Sandbox Code Playgroud)
  1. 当 viewHolder 与模型元素关联时,为 viewHolder 设置正确的视觉状态
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
    }
}
Run Code Online (Sandbox Code Playgroud)

需要注意的事情:holder.itemView.context as LifecycleOwner这基本上意味着 recyclerview 位于作为生命周期所有者的片段中。

这种方法很有效,因为 ViewHolder 被重用,所以我们不必为列表的各种元素创建新的观察者。


小智 2

从我的角度来看,最好将数据观察到您的FragmentActivity类中并将数据传递到Recyclerview. 在Recyclerview重写方法getItemViewType来处理vertical项目和horizontal项目。

例子:

视图模型

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
    }
}
Run Code Online (Sandbox Code Playgroud)

片段类

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);
                }
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

回收器视图适配器

class RecyclerViewAdater extend Adapter<ViewHolder>{
    @Override
    public int getItemViewType(int position) {
        return mDataList.get(position).getContainerType();
    }
}
Run Code Online (Sandbox Code Playgroud)

在此基础上你可以编写你的RecyclerView代码