web-dev-qa-db-ja.com

ライフサイクル所有者としてビューホルダーを使用してlivedataとviewmodelを使用するにはどうすればよいですか?

垂直方向にスクロールするrecyclerview(verticalRV)があります。このrecyclerview(horizo​​ntalRV)の各アイテムは、Horizo​​ntalrecyclerviewです。

VerticalRV itemViewHodler imの内部で、ビューモデルからデータをフェッチし、変更を監視し、それに応じてhorizo​​ntalRVアダプターを更新しようとしています。

しかし、オブザーバーはonChangedメソッドが呼び出されていません。

ライブデータを使用してビューホルダーのライフサイクルを管理し、それに応じてverticalRVのアダプターから状態を設定するために、LifecycleOwnerインターフェイスを実装しました。

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;
    }

}

ここで何が欠けているのか教えてください。

3
Hari

私の見解では、データをfragmentまたはactivityに観察し、データをrecyclerviewに渡し、RecyclerviewでメソッドgetItemViewTypegetItemViewTypeから、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
   }
}

フラグメントクラス

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);
           }
        }
      });
    }
}

RecyclerViewAdapter

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

これに基づいて、recyclerViewコードを書くことができます

2
Shyak Das

この問題には2つのアプローチがあります。1つはShyakの答えです。これは、アダプターの外部の変更を監視し、リストを裏付けるデータの変更を通じて変更を通知します。これは、実際にはリサイクラービューとアダプターのパターンを尊重しています。

ただし、モデルからのデータだけでなく、外部イベントやデータも観察して、recylerviewに表示したい場合があります。集約されたデータを含む新しいモデルでこれらすべての情報を組み合わせる代わりに、アダプター自体で直接変更の一部を観察すると便利な場合があります。

この場合、ViewHolderにオブザーバーを追加し、次のように変更に対応できます。

1)アダプタクラスのコンストラクタにLiveDataを渡します。

class MyAdapter(private var data: LiveData<Int>) :
RecyclerView.Adapter<MyViewHolder>() {

2)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
}

3)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

注意事項:holder.itemView.context as LifecycleOwnerこれは基本的に、recyclerviewがライフサイクル所有者であるフラグメント内にあることを意味します。

ViewHolderが再利用されるため、このアプローチは効率的である可能性があるため、リストのさまざまな要素に対して新しいオブザーバーを作成する必要はありません。

1
AndrewBloom