android - 将 LifeCycleOwner 传递给 RecyclerView.Adapter 是否安全

标签 android android-layout android-recyclerview lifecycleowner

考虑绑定(bind)到 viewModel 的布局数据。更具体地说,布局使用布局变量来访问这个底层 View 模型。每当绑定(bind)膨胀时,它的 viewModel 和 lifeCycleOwner 将被设置 . (当然 viewModel 包含一些 liveData,直接绑定(bind)到一些 View 属性)。
向 RecyclerView(在 Activity 中创建和设置)传递一个 viewModel 列表。对于每个 View 模型,一个 ViewHolder 是通过扩展一个新的布局副本及其数据绑定(bind)来创建的。onBindViewHolder策略是

  • 不要触摸 View 模型
  • 设置ViewHolder.dataBinding.setViewModel(viewModels[position])
  • 但是如何设置 LifeCycleOwner?
  • 将 LifeCycleOwner 作为参数传递给适配器好吗?毕竟,适配器只会与 RecyclerView 一样长,而 RecyclerView 则只会与父 Activity 一样长。
  • 这是在 RecyclerView 的上下文中使用 dataBinding 的明智方式吗?

  • 图。1。 layout_counter.xml :添加到 recyclerView 的单个组件的布局。
    layout
    代码(如果需要)
  • MainViewModel.java
  • 适配器.java
  • MainActivity.java
  • layout_counter.xml
  • layout_main.xml

  • MainViewModel.java
    package com.gmail.example.rough;
    
    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.UUID;
    
    public class MainViewModel extends androidx.lifecycle.ViewModel {
    
        private MutableLiveData<String> date, time, name;
    
        public MainViewModel() {
            this.date = new MutableLiveData<>(LocalDateTime.now().toString());
            this.time = new MutableLiveData<>(LocalTime.now().toString());
            this.name = new MutableLiveData<>(UUID.randomUUID().toString().substring(0,10));
            Timer t=new Timer();
            t.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    date.postValue(LocalDateTime.now().toString());
                    time.postValue(LocalTime.now().toString());
                    }
            }, 0, 1000);
        }
    
        public LiveData<String> getDate() {
            return date;
        }
    
        public LiveData<String> getTime() {
            return time;
        }
    
        public LiveData<String> getName() {
            return name;
        }
    }
    
    
    适配器.java
    package com.gmail.example.rough;
    
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import androidx.annotation.NonNull;
    import androidx.databinding.DataBindingUtil;
    import androidx.recyclerview.widget.RecyclerView;
    import com.gmail.example.rough.databinding.LayoutCounterBinding;
    import java.util.List;
    
    public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
    
            private LayoutCounterBinding binding;
    
            public ViewHolder(@NonNull View itemView, LayoutCounterBinding binding) {
                super(itemView);
                this.binding = binding;
            }
    
            public LayoutCounterBinding getBinding() {
                return binding;
            }
        }
    
        List<MainViewModel> vms;
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View view = inflater.inflate(R.layout.layout_counter, parent, false);
            LayoutCounterBinding binding = DataBindingUtil.inflate(inflater, R.layout.layout_counter, parent, false);
            return new ViewHolder(view, binding);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.getBinding().setVm(vms.get(position));
            //how to set the LifeCycleOwner?
    //        holder.getBinding().setLifecycleOwner(???);
        }
    
        @Override
        public int getItemCount() {
            return vms.size();
        }
    
       
    
        public Adapter(List<MainViewModel> vms) {
            this.vms = vms;
        }
    }
    
    
    MainActivity.java
    package com.gmail.example.rough;
    
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.recyclerview.widget.LinearLayoutManager;
    
    import android.os.Bundle;
    
    import com.gmail.example.rough.databinding.LayoutMainBinding;
    
    import java.util.ArrayList;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.layout_main);
            LayoutMainBinding binding = LayoutMainBinding.inflate(getLayoutInflater());
            setContentView(binding.getRoot());
            ArrayList<MainViewModel> vms = new ArrayList<>();
            vms.add(new MainViewModel());
            vms.add(new MainViewModel());
            vms.add(new MainViewModel());
            binding.recyclerView.setAdapter(new Adapter(vms));
            binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
    
    
        }
    
    
    }
    
    layout_counter.xml
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools">
    
        <data>
    
            <variable
                    name="vm"
                    type="com.gmail.example.rough.MainViewModel" />
    
    
    
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".logger.android.MainActivity">
    
            <TextView
                    android:id="@+id/tvName"
                    android:layout_width="wrap_content"
                    android:layout_height="19dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:text="@{vm.name}"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
            <RelativeLayout
                    android:id="@+id/layoutRealtive"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    android:gravity="center"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/tvName">
    
                <TextView
                        android:id="@+id/tvTs"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignStart="@id/tvTime"
                        android:layout_alignTop="@id/tvTime"
                        android:text="@{vm.date}" />
    
                <TextView
                        android:id="@+id/tvTime"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
    
                        android:background="?selectableItemBackground"
                        android:gravity="center"
                        android:textAlignment="center"
                        android:textSize="36sp"
                        android:textStyle="bold"
    
                        />
    
    
                <ImageView
                        android:id="@+id/ivReset"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignTop="@id/tvTime"
                        android:layout_alignBottom="@id/tvTime"
                        android:layout_alignParentEnd="true"
    
                        android:src="@drawable/ic_launcher_foreground"
                         />
    
            </RelativeLayout>
    
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    
    layout_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools">
    
        <data>
    
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">
    
            <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/recyclerView"
                    android:layout_width="409dp"
                    android:layout_height="729dp"
                    android:layout_marginStart="1dp"
                    android:layout_marginTop="1dp"
                    android:layout_marginEnd="1dp"
                    android:layout_marginBottom="1dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    
    

    最佳答案

    您可以引用以下示例代码:

    class SampleAdapter(private var list: List<String>,
                    private val viewmodel: SampleViewModel,
                    private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<SampleAdapter.ViewHolder>() {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding: ItemRowBinding = DataBindingUtil.inflate(
                LayoutInflater.from(parent.context),
                R.layout.item_row, parent, false)
        val holder= ViewHolder(binding, lifecycleOwner)
        binding.lifecycleOwner=holder
        holder.lifecycleCreate()
        return holder
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind()
    }
    
    override fun getItemCount(): Int {
        return list.size
    }
    
    override fun onViewAttachedToWindow(holder: ViewHolder) {
        super.onViewAttachedToWindow(holder)
        holder.attachToWindow()
    }
    
    inner class ViewHolder(private val binding: ItemRowBinding,
                           private var lifecycleOwner: LifecycleOwner)
        : RecyclerView.ViewHolder(binding.root),LifecycleOwner {
        private val lifecycleRegistry = LifecycleRegistry(this)
        private var paused: Boolean = false
    
        init {
            lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
        }
        fun lifecycleCreate() {
            lifecycleRegistry.currentState = Lifecycle.State.CREATED
        }
        override fun getLifecycle(): Lifecycle {
            return lifecycleRegistry
        }
    
        fun bind() {
            lifecycleOwner = this@SampleAdapter.lifecycleOwner
            binding.viewmodel = viewmodel
            binding.executePendingBindings()
        }
    
        fun attachToWindow() {
            if (paused) {
                lifecycleRegistry.currentState = Lifecycle.State.RESUMED
                paused = false
            } else {
                lifecycleRegistry.currentState = Lifecycle.State.STARTED
            }
        }
    }
    
    fun setList(list: List<String>) {
        this.list = list
        notifyDataSetChanged()
    } }
    
    我们需要传递生命周期所有者的原因是:
    ViewHolder 不是生命周期所有者,这就是它无法观察 LiveData 的原因。
    整个想法是通过实现 LifecycleOwner 使 Viewholder 成为生命周期所有者,然后开始其生命周期。

    关于android - 将 LifeCycleOwner 传递给 RecyclerView.Adapter 是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63461537/

    相关文章:

    java - RecyclerView : Inconsistency detected. 项目位置无效 - 为什么会这样?

    java - RecyclerView 多次显示适配器中的最后一项。需要所有适配器项目显示在 RecyclerView 中

    Android 9 (Pie) ContentResolver 查询 MediaStore.Images.Media.EXTERNAL_CONTENT_URI 在 api 28 上返回 null

    android.support.v4.widget.NestedScrollView 高度问题

    android - 缩放 View 会减小内容大小但会增加空白边距

    java - 无法在 Android Studio 3.1 中的当前主题中找到样式 'coordinatorLayoutStyle'

    android - 适用:iOS 7.1 支持 MKMapItem

    android - 您可以使用 native 应用程序做什么,而您不能使用混合应用程序

    Android:旋转和调整 FrameLayout 的大小

    Android studio RecyclerView onCreateViewHolder 布局膨胀好慢