美文网首页
Android——JetPack{LiveData}

Android——JetPack{LiveData}

作者: So_ProbuING | 来源:发表于2021-09-08 01:17 被阅读0次

LiveData是什么以及有什么特点

LiveData 之所以能够感知到组件的生命周期 是因为 在LiveData里面给组件中注册了一个生命周期的观察者


LiveData的特点

LiveData的使用方式

  1. 数据持有使用
  2. 跨组件通信

实时数据LiveData

LiveData是一个可被观察的数据容器类。它将数据包装起来,使数据成为被观察者,当该数据发生变化时,观察者就能获得通知,我们不需要自己去实现观察者模式

LiveData和ViewModel的关系

ViewModel用于存放页面所需的各种数据,我们还可以在其中存放一些与数据相关的业务逻辑,因此ViewModel中的数据可能会随着业务的变化而变化。
对于页面来说,页面并不需要关心ViewModel中的业务逻辑,它只需要关心展示什么数据,并且希望在数据发生变化时,得到通知并更新页面。

  • LiveData的作用:在ViewModel中的数据发生变化时通知页面,所以LiveData通常放在ViewModel中使用,用于包装ViewModel中需要被外界观察的数据。

LiveData的基本使用方法

我们在上一个案例的计时器基础上使用LiveData对接口进行改写。

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

public class TimerWithLiveDataViewModel extends ViewModel {
    //计时器中的秒是希望被外界观察的 所以我们使用LiveData进行包装
    private MutableLiveData<Integer> currentSecond;
    
    public LiveData<Integer> getCurrentSecond(){
        if (currentSecond == null) {
            currentSecond = new MutableLiveData<>();
        }
        return currentSecond;
    }
}

  1. 利用LiveData完成页面与ViewModel的通信
  private void initComponent() {
        TextView timeTv = (TextView) findViewById(R.id.tv_second);
        //创建viewModel
        TimerWithLiveDataViewModel timerWithLiveDataViewModel = new ViewModelProvider(this).get(TimerWithLiveDataViewModel.class);
        //得到ViewModel中的LiveData
        LiveData<Integer> currentSecond = timerWithLiveDataViewModel.getCurrentSecond();
        //通过Observe观察LiveData的变化
        currentSecond.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer second) {
                Log.d(TAG, "onChanged: "+second);
                //变化后更新UI
                timeTv.setText("TIME:" + second);

            }
        });

LiveData的postValue()和setValue()

  • postValue()和setValue()都是希望修改LiveData所包装的数据使用
  • postValue()用在非UI线程中、setValue()用在UI线程中

LiveData的原理

我们通过LiveData.observe()方法来看一下LiveData的原理,在observe方法中接收两个参数,一个是LifecycleOwner对象,一般是Activity,在方法的最后一行将Observer与Activity的生命周期关联在一起,所以LiveData能够感知页面的生命周期。它可以检测页面当前的状态是否为激活状态或者页面是否被销毁。只有页面处于激活状态时,页面才能收到来自LiveData的通知,若页面被销毁那么LiveData会自动清除与页面的 关联,从而避免可能引发的内存泄漏

LiveData.observerForever()方法

LiveData还提供了一个名为observerForever()的方法,使用起来与observe()没有太大差别。它们的区别主要在于,当LiveData所包装的数据发生变化时,无论页面处于什么状态,observerForever()都能收到通知。使用这个方法要注意记得调用removeObserver()来停止对LiveData的观察,否则LiveData一直处于激活状态,导致Activity不会被系统自动回收,这就造成了内存泄漏

ViewModel+LiveData实现Fragment间的通信

我们可以基于ViewModel和Fragment组件的特性,可以利用LiveData实现同一个Activity中不同的Fragment间的通信

  1. 创建viewModel使用LiveData包装Progress
public class ShareDataViewModel extends ViewModel {
    private MutableLiveData<Integer> progress;


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

    @Override
    protected void onCleared() {
        super.onCleared();
        progress = null;
    }   
}
  • fragment布局文件 两个fragment布局相同
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_above="@+id/seekBar"
        android:text="Fragment_One"/>
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:layout_centerInParent="true"
        android:layout_marginTop="20dp"/>

</RelativeLayout>
  • Fragment代码 两个Fragment代码类似
public class FragmentOne extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container,  Bundle savedInstanceState) {
        View parentView = inflater.inflate(R.layout.fragment_one, container, false);
        SeekBar seekBar = (SeekBar) parentView.findViewById(R.id.seekBar);
        //获取viewModel
        ShareDataViewModel shareDataViewModel = new ViewModelProvider(getActivity()).get(ShareDataViewModel.class);
        //获取viewModel中包装的seekbar
        MutableLiveData<Integer> progressLiveData = (MutableLiveData<Integer>) shareDataViewModel.getProgress();
        //通过观察LiveData的变化改变UI
        progressLiveData.observe(getViewLifecycleOwner(), new Observer<Integer>() {
            @Override
            public void onChanged(Integer progress) {
                seekBar.setProgress(progress);
            }
        });
        //监听seekbar变化
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //用户操作seekbar更新liveData数据
                progressLiveData.setValue(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
        return parentView;
    }
}
  • activity布局
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".fragmentcommunication.FragmentComminiActivity">
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentone"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/teal_200"
        />
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmenttwo"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />

</LinearLayout>
  • Activity代码
public class FragmentComminiActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_commini);
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        transaction.add(R.id.fragmentone, new FragmentOne());
        transaction.add(R.id.fragmenttwo, new FragmentTwo());
        transaction.commit();
    }
}

运行后,可以看到两个Fragment互相通信通过viewModel+liveData,并且旋转屏幕使得SeekBar进度保持一致


运行结果

整理与总结

总的来说就是,ViewModel将页面与数据进行解耦,ViewModel中存放页面中的数据,当ViewModel中的数据发生变化时我们希望通知页面进行页面更新。在没有LiveData之前,我们通过接口回调的方式来完成这个需求,有了LiveData之后,我们可以更简单、优雅的处理数据:
使用LiveData对ViewModel中的数据进行包装,并在页面中监听LiveData的数据变化。当数据变化时收到通知进而更新UI

相关文章

网友评论

      本文标题:Android——JetPack{LiveData}

      本文链接:https://www.haomeiwen.com/subject/pwcuwltx.html