JetPack-LiveData

一、LiveData简介

  LiveData(实时数据)是一个可被观察的数据容器类,,可以将LiveData理解为一个数据的容器,它将数据包装起来,使数据成为观察者。当数据发生变化时,观察者能够获得通知,LiveData内部已经实现了观察者模式,可以使用LiveData完成ViewModel与页面之间的通信。

二、LiveData与ViewModel关系

  ViewModel用于存放页面所需要的各种数据。,我们还可以在其中放一些与数据相关的业务逻辑。例如我们可以在ViewModel中进行数据的获取,加工,解析等。因此,ViewModel中的数据会随着业务的变化而变化。
  对于页面来说,页面并不需要关心ViewModel中的业务逻辑,它只关心自己需要展示的数据。并且希望在数据发生变化时通知页面。LiveData的作用就是,在ViewModel中的数据发生变化时通知页面。,因此LiveData通常被放在ViewModel中使用。用于包装ViewModel中那些需要被外界观察的数据。

三、LiveData的使用

3.1、LiveData是一个抽象类,不能直接使用,通常我们使用它的子类MutableLiveData


public class TimerVideModel  extends ViewModel {
    
    private MutableLiveData<Integer> currentSecond;

    private Timer mTimer;

    public void startTiming(){
        if(mTimer == null){
            currentSecond.setValue(0);
            mTimer = new Timer();
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    //这里要用postValue方法,而不能用setValue方法,否则会报线程异常错误
                    currentSecond.postValue(currentSecond.getValue()+1);
                }
            };
            mTimer.schedule(task,1000,1000);
        }
    }



    public LiveData<Integer> getCurrentSecond(){
        if(currentSecond == null){
            currentSecond = new MutableLiveData<>();
        }
        return currentSecond;
    }
    
    @Override
    protected void onCleared() {
        super.onCleared();
        mTimer.cancel();
    }
}

3.2、完成与ViewModel之间的通信

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initComponent();
    }

    private void initComponent() {

        //通过ViewModelProvider 获取到ViewModel
        TimerVideModel timerVideModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(TimerVideModel.class);

        //得到ViewModel中的LiveData
        MutableLiveData<Integer> liveData = (MutableLiveData<Integer>) timerVideModel.getCurrentSecond();

        //通过 liveData.observe观察ViewModel中的数据变化
        liveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                ((TextView) findViewById(R.id.time)).setText("Time:" + integer);
            }
        });

        findViewById(R.id.reset).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过LiveData.setValue/postValue()完成对ViewModel中数据的修改
                liveData.setValue(0);
            }
        });

        timerVideModel.startTiming();


    }
}

在代码中我们通过liveData.observe()方法对LiveData所包装的数据进行观察。反过来,我们希望修改LiveData所包装的数据时,也可以通过LiveData.postValue()/LiveData().setValue()方法完成。LiveData.postValue()是用在非UI线程中,若在UI线程中用LiveData().setValue()方法。

在这里插入图片描述

四、LiveData的原理

LiveData通过 liveData.observe()观察ViewModel中的数据变化。
在这里插入图片描述
observe()方法接受两个参数,第一个是LifeCycleOwner对象,这里是Activity。第二个参数是Observe对象。 * owner.getLifecycle().addObserver(wrapper);*将Observe与Activity的生命周期关联在一起。因此LiveData能够感知Activity的生命周期。它可以检测到页面当前的状态是否是激活状态,或者页面是否被销毁,只有页面被处于激活状态(LifeCycle.State.ON_START或者LifeCycle.State.ON_RESUME)时,页面才会收到LiveData的通知,若页面被销毁(LifeCycle.State.ON_DESTORY)会自动清除与页面的关联。从而避免可能引发内存泄漏问题。

五、LiveData.ObserveForever()方法

  LiveData还提供了一个ObserveForever()的方法,使用和Observe()一样,区别在于,当LiveData所包装的数据发生变化时,无论页面处于什么状态,ObserveForever()都能收到通知,因此,用完之后,一定需要调用removeObserver()方法来停止对LiveData的观察,否则LiveData会一直处于激活状态,Activity则不会被系统自动回收,造成内存泄漏

六、ViewModel+LiveData实现Fragment间通信

6.1、实现效果

在这里插入图片描述

在MainActivity中有两个Fragment(FragmentOne和FragmentTwo),两个Fragment中都有一个seeker,拖拽任意的seekbar,另外一个Fragment中的seekbar也改变progress。

6.2、编写MainActivity中的XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="0" />


    <TextView
        android:id="@+id/reset"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="重置"
        android:textSize="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/time" />


    <fragment
        android:id="@+id/fragmentOne"
        android:name="com.example.livedata.OneFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/reset" />

    <View
        android:id="@+id/divideLine"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/fragmentOne" />

    <fragment
        android:id="@+id/fragmentTwo"
        android:name="com.example.livedata.TwoFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/divideLine" />


</androidx.constraintlayout.widget.ConstraintLayout>

6.3、定义ViewModel 和LiveData

public class ShareDataViewModel extends ViewModel {

    private MutableLiveData<Integer> progress;

    public LiveData<Integer> getProgress(){
        if(progress == null){
            progress = new MutableLiveData<>();
        }
        return progress;
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        progress = null;
    }
}

6.4、FragmentOne中逻辑代码


public class OneFragment extends Fragment {
    
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View parentView = inflater.inflate(R.layout.fragment_one, container, false);

        final SeekBar seekBar = parentView.findViewById(R.id.seekbar);
        final TextView seekProgressTv = parentView.findViewById(R.id.tvSeekValue);

        //注意:这里ViewModelProviders.of(getActivity())这里的参数需要是Activity,而不能是Fragment,否则收不到监听
        final ShareDataViewModel shareDataViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.NewInstanceFactory()).get(ShareDataViewModel.class);
        final MutableLiveData<Integer> liveData = (MutableLiveData<Integer>) shareDataViewModel.getProgress();

        //通过observe方法观察ViewModel中字段数据的变化,并在变化时,得到通知
        liveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer progress) {
                seekBar.setProgress(progress);
                seekProgressTv.setText("Progress:"+ progress);
            }
        });

        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //用户操作SeekBar时,更新ViewModel中的数据
                liveData.setValue(progress);
                seekProgressTv.setText("Progress:"+ progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        return parentView;
    }
}

6.5、FragmentTwo中的代码


public class TwoFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View parentView = inflater.inflate(R.layout.fragment_t_w_o, container, false);

        final SeekBar seekBar = parentView.findViewById(R.id.seekbar);

        final TextView seekProgressTv = parentView.findViewById(R.id.tvSeekValue);

        //注意:这里ViewModelProviders.of(getActivity())这里的参数需要是Activity,而不能是Fragment,否则收不到监听
        final ShareDataViewModel shareDataViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.NewInstanceFactory()).get(ShareDataViewModel.class);
        final MutableLiveData<Integer> liveData = (MutableLiveData<Integer>) shareDataViewModel.getProgress();

        //通过observe方法观察ViewModel中字段数据的变化,并在变化时,得到通知
        liveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer progress) {
                seekBar.setProgress(progress);
                seekProgressTv.setText("progress:" + progress);
            }
        });

        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //用户操作SeekBar时,更新ViewModel中的数据
                liveData.setValue(progress);
                seekProgressTv.setText("progress:" + progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        return parentView;
    }
}

七、DEMO代码:

Github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值