首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >把LifeCycleOwner传给RecyclerView.Adapter安全吗?

把LifeCycleOwner传给RecyclerView.Adapter安全吗?
EN

Stack Overflow用户
提问于 2020-08-18 03:39:54
回答 5查看 10.5K关注 0票数 15

考虑绑定到viewModel的布局数据。更具体地说,布局使用一个布局变量来访问这个底层viewModel。每当绑定被膨胀时,its viewModel和lifeCycleOwner将被设置为。(当然,viewModel包含一些直接绑定到某些视图属性的liveData )。

RecyclerView (在活动中创建和设置)被传递一个viewModels列表。对于每个viewModel,一个ViewHolder是通过膨胀一个新的布局副本及其dataBinding来生成的。

onBindViewHolder的策略是

  • 不要碰viewModels
  • 设置ViewHolder.dataBinding.setViewModel(viewModels[position])
  1. 但是如何设置LifeCycleOwner?
  2. 是否将LifeCycleOwner作为参数传递给适配器,好吗?毕竟,适配器只有在RecyclerView才能存活,而RecyclerView只有在父活动时才能存活。
  3. 这是在dataBinding上下文中使用RecyclerView的一种合理方法吗?

fig1。layout_counter.xml :添加到recyclerView中的单个组件的布局。

代码(如果需要)

  • MainViewModel.java
  • Adapter.java
  • MainActivity.java
  • layout_counter.xml
  • layout_main.xml

MainViewModel.java

代码语言:javascript
运行
复制
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;
    }
}

Adapter.java

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
<?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

代码语言:javascript
运行
复制
<?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>
EN

回答 5

Stack Overflow用户

发布于 2020-09-29 05:32:30

您可以参考以下示例代码:

代码语言:javascript
运行
复制
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成为生命周期所有者,然后开始它的生命周期。

票数 6
EN

Stack Overflow用户

发布于 2020-10-04 20:01:46

如果我从此页中正确理解了,那么最好将lifeCycleOwner传递给RecyclerView.Adapter绑定项,因为:

当一个ViewHolder被分离时,意味着它目前在屏幕上不可见,parentLifecycleOwner仍然处于恢复状态,因此ViewDataBindings仍然处于活动状态并观察数据。这意味着当一个LiveData实例被更新时,它会触发要更新的视图,但是视图目前没有显示!不太理想。

Stephen似乎提出了一些解决方案,但我没有对它们进行测试。

票数 3
EN

Stack Overflow用户

发布于 2021-04-30 06:03:29

而不是将LifeCycleOwner传递给RecyclerView。尝试在从observeForever(Observer)中观察数据的情况下使用RecyclerView。并在使用removeObserver(Observer)完成工作后移除观察者。

参考文档:https://developer.android.com/reference/androidx/lifecycle/LiveData#observeForever(androidx.lifecycle.Observer%3C?%20super%20T%3E)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63461537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档