0%

ViewModelSavedState(即使进程在后台被系统杀死数据也能保存下来)

引入

正常情况下,如果一个进程被移到后台,且当前系统内存不足时,会有一定概率会将该进程杀死来释放内存资源,而被系统杀死时,ViewModel也会被删除,UI的数据就会遭到丢失。

如下图所示,一旦切出后台进程被系统杀死数据就会丢失。

不过好在系统杀死进程时,会调用 onSaveInstanceState() 方法,顾名思义就是保存实例状态的,我们重写这个方法来保存我们的数据。


代码

1. onSaveInstanceState

ViewModel部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.viewmodelsavedstate;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> number;

public MutableLiveData<Integer> getNumber() {
if(number == null){
number = new MutableLiveData<>();
number.setValue(0);
}
return number;
}

public void add(int x){
number.setValue(number.getValue() + x);
}
}

MainActivity,21 - 23行是载入 savedInstanceState,28 - 32是写入 savedInstanceState。

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
package com.example.viewmodelsavedstate;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import com.example.viewmodelsavedstate.databinding.ActivityMainBinding;


public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
ActivityMainBinding binding;
public final static String SAVED_KEY_NAME = "number";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
if(savedInstanceState != null){
myViewModel.getNumber().setValue(savedInstanceState.getInt(SAVED_KEY_NAME));
}
binding.setData(myViewModel);
binding.setLifecycleOwner(this);
}

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVED_KEY_NAME, myViewModel.getNumber().getValue());
}
}

2. SavedStateHandle

ViewModel部分,使用 SavedStateHandle 来代替 MutableLiveData 存储数据,同时在创建 ViewModel 时将SavedStateHandle 传入供后续使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.viewmodelsavedstate;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;

public class MyViewModel extends ViewModel {
private SavedStateHandle handle;
public MyViewModel(SavedStateHandle handle){
this.handle = handle;
}

public MutableLiveData<Integer> getNumber() {
if(!handle.contains(MainActivity.SAVED_KEY_NAME)){
handle.set(MainActivity.SAVED_KEY_NAME, 0);
}
return handle.getLiveData(MainActivity.SAVED_KEY_NAME);
}

public void add(int x){
getNumber().setValue(getNumber().getValue() + x);
}
}

MainActivity部分

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
package com.example.viewmodelsavedstate;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;

import android.os.Bundle;

import com.example.viewmodelsavedstate.databinding.ActivityMainBinding;


public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
ActivityMainBinding binding;
public final static String SAVED_KEY_NAME = "number";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
binding.setData(myViewModel);
binding.setLifecycleOwner(this);
}

}