Livedata+viewmodel+Fragment
title:LiveData viewmodel 实现Fragment间的通信
使用ViewModel+LiveData实现同一个Activity不同Fragment间的通信。
1.将两个Fragment等比例放置在Activity的布局文件中。
<?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">
<fragment
android:id="@+id/one_fragment"
android:name="com.test.mytest.OneFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/two_fragment"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="@+id/two_fragment"
android:name="com.test.mytest.TwoFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/one_fragment" />
2.定义Livedata和ViewModel
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;
}
}
3.编写Fragment的代码,实现具体的通信。这里以OneFragment为例,TwoFragment也是类似的代码。
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);
//注意:这里ViewModelProviders.of(getActivity())这里的参数需要是Activity,而不能是Fragment,否则收不到监听
final ShareDataViewModel shareDataViewModel = ViewModelProviders.of(getActivity()).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);
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
//用户操作SeekBar时,更新ViewModel中的数据
liveData.setValue(progress);
}
});
return parentView;
}
}
4.在Fragment的布局文件中放置一个SeekBar控件。
<?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:layout_marginTop="20dp"
android:max="100"
android:layout_centerInParent="true"/>
</RelativeLayout>
可以看到,无论是滑动OneFragment还是TwoFragment中的SeekBar,另外一个Fragment中的SeekBar也会跟着滑动。滑动SeekBar时,通过LiveData.setValue(),修改了ViewModel中LiveData包装的数据(progress字段)。由于Fragment通过LiveData.observe()方法,监听了数据的变化,所以progress字段被修改后,Fragment能够第一事件收到通知,进而更新UI。这就是利用ViewMode和LiveData实现Fragment间通信的原理。另外,从演示图中,我们还能看到,屏幕旋转后SeekBar的进度与旋转前保持一直,数据并未丢失,这也是ViewModel带来的好处之一。