当前位置:网站首页>JetPack - - - LifeCycle、ViewModel、LiveData
JetPack - - - LifeCycle、ViewModel、LiveData
2022-06-13 06:25:00 【m0_ forty-seven million nine hundred and fourteen thousand one 】
Jetpack It's a suite of multiple libraries , Helps developers follow best practices 、 Reduce boilerplate code and write available in a variety of Android Version and the code running in the device consistently , So that developers can focus on really important coding work .
JetPack The advantages of :
Follow best practices :
AndroidJetpack Components are built using the latest design methods , Backward compatibility , Can reduce crashes and memory leaks .
Eliminate boilerplate code :
AndroidJetpack Can manage all kinds of tedious Activity( Such as background tasks 、 Navigation and Lifecycle Management ), So you can focus on building great applications .
Reduce inconsistencies :
These libraries can be found in all kinds of Android Versions and devices operate in a consistent way , Help you reduce complexity .
LifeCycle
LifeCycle The component lifecycle changes are notified and decoupled , omitted onCreate()、onDestroy() Etc .
1. monitor activity Life cycle of
Let's start with LifeCycle Timer case for
<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=".Lifecycle.MainActivity">
<com.example.jetpacktest.Lifecycle.MyChronometer
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Here we refer to a custom timer class (activity Display timing , Pause timing after exiting ).
public class MyChronometer extends Chronometer implements LifecycleObserver {
private long mElapsedTime;
public MyChronometer(Context context, AttributeSet attrs) {
super(context, attrs);
}
// To configure onResume Listening in
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void startMeter(){
// Resume the timing and make sure that it is the time before exiting
setBase(SystemClock.elapsedRealtime()-mElapsedTime);
start();
}
// To configure onPause Listening in
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
private void stopMeter(){
// Record the timing
mElapsedTime = SystemClock.elapsedRealtime() - getBase();
stop();
}
}
Lifecycle How to use ( Above ):
1. Realization LifecycleObserver Interface .
2. Configure annotations and specify lifecycle
public class MainActivity extends AppCompatActivity {
private MyChronometer mViewById;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewById = findViewById(R.id.chronometer);
// binding activity Life cycle monitoring for
getLifecycle().addObserver(mViewById);
}
}
design sketch :
2. monitor service Life cycle of
Let's add this dependency first :
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
stay AndroidManifest.xml Add the permissions required for positioning in the file :
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
This time we passed a Service The case of printing coordinates in to illustrate the use method .
Let's start with a layout xml:
<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=".Lifecycle.MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#03A9F4"
android:text="start"
android:onClick="startGPS"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chronometer"
app:layout_constraintVertical_bias="0.346" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00BCD4"
android:text="stop"
android:onClick="stopGPS"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/chronometer"
app:layout_constraintVertical_bias="0.613" />
</androidx.constraintlayout.widget.ConstraintLayout>
stay Xml There are two buttons in the , Start and stop Service.
public class MyLocationService extends LifecycleService {
public MyLocationService() {
Log.i("ning","MyLocationService");
MyLocationObserver myLocationObserver = new MyLocationObserver(this);
// Binding lifecycle
getLifecycle().addObserver(myLocationObserver);
}
}
stay Service We first inherit LifecycleService, Then initialize the class for location monitoring , And bind your life cycle .
public class MyLocationObserver implements LifecycleObserver {
private Context mContext;
private LocationManager mSystemService;
private MyLocationListener mMyLocationListener;
public MyLocationObserver(Context pContext) {
mContext = pContext;
}
// monitor Service perform onCreate() When the
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void startGetLocation() {
Log.i("ning","startGetLocation");
mSystemService = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
mMyLocationListener = new MyLocationListener();
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
// Turn on Gps
mSystemService.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1, mMyLocationListener);
}
// monitor Service perform onDestroy() When the
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void stopGetLocation(){
Log.i("ning","stopGetLocation");
// close Gps
mSystemService.removeUpdates(mMyLocationListener);
}
static class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(@NonNull Location location) {
Log.d("ning","onLocationChanged"+location.getLongitude()+","+location.getLatitude());
}
}
}
And in activity It's written in the same way , Inherit LifecycleObserver Interface and add comments .
public class MainActivity extends AppCompatActivity {
private MyChronometer mViewById;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
}
public void startGPS(View view) {
startService(new Intent(this,MyLocationService.class));
}
public void stopGPS(View view) {
stopService(new Intent(this,MyLocationService.class));
}
}
At last I passed adb Order to modify gps The location of
adb -s emulator-5554 emu geo fix 121.4961236714487 31.24010934431376
adb -s emulator-5554 emu geo fix 122.4961236714487 31.24010934431376
Print the results :
2021-12-20 15:32:15.166 18692-18692/com.example.jetpacktest D/ning: onLocationChanged121.49612333333333,31.240108333333332
3. monitor App Life cycle of
We decided to have a App Life cycle listener class .
public class ApplicationObserver implements LifecycleObserver {
private static String TAG="TAG";
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreate(){
Log.i(TAG,"Lifecycle.Event.ON_CREATE");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onStop() {
Log.i(TAG,"Lifecycle.Event.ON_STOP");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onStart() {
Log.i(TAG,"Lifecycle.Event.ON_START");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void onResume() {
Log.i(TAG,"Lifecycle.Event.ON_RESUME");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
private void onPause() {
Log.i(TAG,"Lifecycle.Event.ON_PAUSE");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void onDestroy() {
Log.i(TAG,"Lifecycle.Event.ON_DESTROY");
}
}
The method is the same as before .
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Bind the listening class of the life cycle
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationObserver());
}
}
And then Application Just bind it !
4.Lifecycle The advantages of
1. Help developers build life cycle aware components
2. Components manage their own lifecycle within them , So as to reduce the module coupling
3. Reduce the possibility of memory leaks
4.Activity、Fragment、Application Both LifeCycle Support
Two .ViewModel
1.ViewModel The role of
1. It's between View( View ) and Model( Data model ) The bridge between .
2. View and data can be separated , Can also maintain communication .
2.ViewModel Application
We use a case to demonstrate ViewModel Usage of .
First introduce this dependency
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
<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=".ViewModel.ViewModelActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.23" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="ViewModelClick"
android:text=" Click Add 1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.532"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45" />
</androidx.constraintlayout.widget.ConstraintLayout>
public class ViewModelActivity extends AppCompatActivity {
private ApplicationViewModel mApplicationViewModel;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_model);
mTextView = findViewById(R.id.textView);
// initialization viewModel object
mApplicationViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(ApplicationViewModel.class);
// assignment
mTextView.setText(String.valueOf(mApplicationViewModel.num));
}
public void ViewModelClick(View view) {
// Add one to each click
mTextView.setText(String.valueOf(mApplicationViewModel.num++));
}
}
ViewModel Is independent of activity Beyond the life cycle of , We initialized ViewModel, And directly modify ViewModel The value in , such activity Even if it is destroyed , It won't affect ViewModel Value .
// To use Content Recommended when AndroidViewModel, When not in context, you can use ViewModel
public class ApplicationViewModel extends AndroidViewModel {
public int num;
public ApplicationViewModel(@NonNull Application application) {
super(application);
}
}
Result demonstration :
3.AndroidViewModel
Don't ViewModel In the middle of Context, Can cause memory leaks
If you want to use Context, Please use AndroidViewModel Medium Application
3、 ... and .LiveData
1.LiveData and ViewModel The relationship between
ViewModel The change of data in is the notification page
2.LiveData application
Let's introduce... Through a simple case LiveData Add ViewModel Usage of
<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=".LiveData.LiveDataActivity">
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="RequestLiveData"
android:text=" request "
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.492"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.237" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is the case Xml file .
public class LiveDataActivity extends AppCompatActivity {
private TextView mTextView2;
private MyViewMode mMyViewMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data);
mTextView2 = findViewById(R.id.textView2);
mMyViewMode = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewMode.class);
mTextView2.setText(String.valueOf(mMyViewMode.getCurrentSecond().getValue()));
//LiveData Monitor Whenever the monitored value changes , Will trigger a callback
mMyViewMode.getCurrentSecond().observe(this, pInteger -> mTextView2.setText(String.valueOf(pInteger)));
}
// Define timer
public void RequestLiveData(final View view) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// Not UI Threads use Post
//UI Threads use set Every second plus one
mMyViewMode.getCurrentSecond().postValue(mMyViewMode.getCurrentSecond().getValue()+1);
}
},1000,1000);
}
}
stay activity In the initialization ViewModel, Define the timer to increase automatically 1, And by LiveData Every time ViewModel All changes in the will start callback , To update UI.
public class MyViewMode extends ViewModel {
private MutableLiveData<Integer> currentSecond;
public MutableLiveData<Integer> getCurrentSecond(){
if (currentSecond==null){
currentSecond= new MutableLiveData<>();
// assignment
currentSecond.setValue(0);
}
return currentSecond;
}
}
stay ViewModel It's initialized in LiveData.
Result demonstration :
The second case :
<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=".liveDataFragment.LiveDataPagerActivity">
<fragment
android:id="@+id/fragment2"
android:name="com.example.jetpacktest.liveDataFragment.SecondFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="@+id/fragment"
android:name="com.example.jetpacktest.liveDataFragment.LiveDataFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fragment2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
Xml The top and bottom of the file fragment, A space line in the middle .
public class LiveDataPagerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data_pager);
}
}
activity Don't do anything? .
public class LiveDataViewModel extends ViewModel {
// TODO: Implement the ViewModel
private MutableLiveData<Integer> progress;
public MutableLiveData<Integer> getProgress(){
if (progress==null){
progress=new MutableLiveData<>();
progress.setValue(0);
}
return progress;
}
}
Same as before
public class LiveDataFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.live_data_fragment, container, false);
final SeekBar seekBar = inflate.findViewById(R.id.seekBar);
// initialization ViewModel
final LiveDataViewModel liveDataViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(LiveDataViewModel.class);
//liveData Listening in
liveDataViewModel.getProgress().observe(getActivity(), new Observer<Integer>() {
@Override
public void onChanged(Integer pInteger) {
// Configure the progress of the progress bar
seekBar.setProgress(pInteger);
}
});
// Progress bar listening
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Configure the progress of the slide
liveDataViewModel.getProgress().setValue(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
return inflate;
}
}
public class SecondFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View inflate = inflater.inflate(R.layout.fragment_second, container, false);
final SeekBar seekBar = inflate.findViewById(R.id.seekBar);
// initialization ViewModel
final LiveDataViewModel liveDataViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(LiveDataViewModel.class);
//liveData Listening in
liveDataViewModel.getProgress().observe(getActivity(), new Observer<Integer>() {
@Override
public void onChanged(Integer pInteger) {
// Configure the progress of the progress bar
seekBar.setProgress(pInteger);
}
});
// Progress bar listening
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Configure the progress of the slide
liveDataViewModel.getProgress().setValue(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
return inflate;
}
}
The above two fragment What you do is the same , The progress bar assigns progress to LiveData, And through the liveData Listening in , A callback is triggered when the value changes , Reached two fragment The effect of progress bar synchronization
Effect demonstration :
3.LiveData The advantages of
1. Make sure the interface matches the data state
2. No memory leaks
3. Not because of Activity Stop and cause a breakdown
4. No longer need to manually handle the lifecycle
5. Data is always up to date
6. Appropriate configuration changes
7. Shared resources
边栏推荐
- Uni app dynamic setting title
- Uni app upload file
- Fragment lifecycle
- MFS details (vii) - - MFS client and Web Monitoring installation configuration
- Notifyitemchanged flash back
- Usegeneratedkeys=true configuration
- 线程相关点
- [JS] handwriting call(), apply(), bind()
- Vector control of Brushless DC motor (4): sensorless control based on sliding mode observer
- Time complexity and space complexity
猜你喜欢
Echart line chart: when multiple lines have the same name, the legend is still displayed
JS to realize bidirectional data binding
AI realizes "Resurrection" of relatives | old photo repair | old photo coloring, recommended by free app
Fichier local second Search Tool everything
js将文本转成语言播放
自定义View —— 可伸展的CollapsExpendView
RFID process management solution for electroplating fixture
华为开发者认证与DevEco Studio编译器下载
Rk3399 hid gadget configuration
RN Metro packaging process and sentry code monitoring
随机推荐
不在以下合法域名列表中,微信小程序解决办法
Echart line chart: multiple line charts show only one line at a time
Logcat -b events and eventlogtags print the location correspondence of the events log in the code
Echart柱状图:echart实现堆叠柱状图
Solutions to common problems in small program development
MFS詳解(七)——MFS客戶端與web監控安裝配置
Applet export (use) public function, public data
Echart折线图:当多条折线图的name一样时也显示不同的颜色
楊輝三角形詳解
Huawei developer certification and deveco studio compiler Download
MFS详解(七)——MFS客户端与web监控安装配置
‘ipconfig‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
【MySQL】基础知识小复习
Fichier local second Search Tool everything
Dynamic link library nesting example
Echart histogram: stack histogram value formatted display
Alibaba cloud OSS file download cannot be resumed at a breakpoint
Free screen recording software captura download and installation
Regular verification of mobile phone number, landline email ID card
The jadx decompiler can decompile jars and apks