与ViewModel的关系:在ViewModel中的数据发生变化时通知页面
LiveData的优势:
- 确保界面符合数据状态
- 不会发生内存泄漏
- 不会因Activity停止而导致崩溃
- 不再需要手动处理生命周期
- 数据始终保存最新状态
- 适当的配置更新
- 共享资源
LiveData的基本使用
基本用法就是创建一个ViewModel,然后使用observer
1 2 3 4 5 6 7
| MutableLiveData<String> mLiveData = mTestViewModel.getLiveData(); mLiveData.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { } });
|
简单应用
还是直接上代码:
布局xml,使用TextView显示读秒:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?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/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
MyViewModel.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.example.livedata;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel { public MutableLiveData<Integer> getCurrentSecond() { if (currentSecond == null) { currentSecond = new MutableLiveData<>(); currentSecond.setValue(0); } return currentSecond; }
private MutableLiveData<Integer> currentSecond;
}
|
activity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.example.livedata;
import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import android.os.Bundle; import android.widget.TextView; import java.util.Timer; import java.util.TimerTask;
public class MainActivity extends AppCompatActivity { private TextView textView; private MyViewModel myViewModel;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); myViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class); textView.setText(String.valueOf(myViewModel.getCurrentSecond().getValue()));
myViewModel.getCurrentSecond().observe(this, new Observer<Integer>() { @Override public void onChanged(Integer i) { textView.setText(String.valueOf(i)); } }); startTimer(); }
private void startTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { myViewModel.getCurrentSecond().postValue(myViewModel.getCurrentSecond().getValue() + 1); } }, 1000, 1000); } }
|
ViewModel+LiveData实现Fragment间通信
需求:有两个fragment,里面都是一个SeekBar,然后让两个SeekBar的process保存一致。
先创建两个fragment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?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=".FirstFragment">
<SeekBar android:id="@+id/seekBar" android:layout_width="0dp" android:layout_height="wrap_content" android:min="0" android:max="100" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
第二个fragment叫SecondFragment
添加到activity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?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">
<androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView" android:name="com.example.livedata.FirstFragment" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" app:layout_constraintBottom_toTopOf="@+id/guideline3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline android:id="@+id/guideline3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.5" />
<androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView2" android:name="com.example.livedata.SecondFragment" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline3" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
同样创建ViewModel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.example.livedata;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel { private MutableLiveData<Integer> progress;
public MutableLiveData<Integer> getProgress() { if (progress == null) { progress = new MutableLiveData<>(); progress.setValue(0); } return progress; }
}
|
fragment的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| package com.example.livedata;
import android.os.Bundle;
import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.SeekBar;
public class FirstFragment extends Fragment {
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_first, container, false); SeekBar seekBar = root.findViewById(R.id.seekBar); MyViewModel viewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(MyViewModel.class); viewModel.getProgress().observe(getActivity(), new Observer<Integer>() { @Override public void onChanged(Integer integer) { seekBar.setProgress(integer); } });
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { viewModel.getProgress().setValue(progress); }
@Override public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override public void onStopTrackingTouch(SeekBar seekBar) {
} }); return root; } }
|
第二个Fragment也上面的基本一致(名字进行修改)
activity的java文件保持默认。