目录
- 1.onSaveInstanceState()方法
- 2.ViewModel
1.onSaveInstanceState()方法
当一个Activity进入了停止状态,是有可能被系统回收的。想象以下场景:应用中有一个ActivityA,用户在ActivityA的基础上启动了ActivityB,ActivityA就进入了停止状态,这个时候由于系统内存不足,将ActivityA回收掉了,然后用户按下Back键返回ActivityA,会出现什么情况呢?其实还是会正常显示ActivityA的,只不过这时并不会执行onRestart()方法,而是会执行ActivityA的onCreate()方法,因为ActivityA在这种情况下会被重新创建一次。
但是这种情况下可能会出现一个重要的问题:ActivityA中是可能存在临时数据和状态的。打个比方,MainActivity中如果有一个文本输入框,现在你输入了一段文字,然后启动NormalActivity,这时MainActivity由于系统内存不足被回收掉,过了一会你又点击了Back键回到MainActivity,这个时候你会发现刚刚输入的文字都没了,因为MainActivity被重新创建了。
如果我们的应用出现了这种情况是比较影响用户体验的,其实Activity还提供了一个onSaveInstanceState()回调方法,这个方法可以保证在Activity被回收之前一定会被调用,因此我们可以通过这个方法来解决这个问题。
onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个参数是真正要保存的内容。
在MainActivity中添加如下代码就可以将临时数据进行保存了:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val tempData="Something you just typed"
outState.putString("data_key",tempData)
}
数据是已经保存下来了,那么我们应该在哪里进行恢复呢?其实我们一直在使用的onCreate()方法其实也有一个Bundle类型的参数。这个参数在一般情况下都是null,但是如果在Activity被系统回收之前,你通过onSaveInstanceState()方法保存数据,这个参数就会带有之前保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。
修改MainActivity的onCreate()方法,如下所示:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
if(savedInstanceState!=null){
val tempData = savedInstanceState.getString("data_key")
tempData?.let { Log.d("tag", it) }
}
}
取出值之后就可以再做相应的恢复操作就可以了,比如将文本内容重新赋值到文本输入框上,这里我只是简单打印一下。
这里使用Bundle保存和取出数据和我们之前使用Intent传递数据的方法很类似,首先我们可以把需要传递的数据都保存在Bundle对象中,然后再将Bundle对象存放在Intent里。到了目标Activity之后,先从Intent中取出Bundle,再从Bundle中一一取出数据。
另外在手机的屏幕发生旋转的时候,Activity也会经历一个重新创建的过程,因而在这种情况下,Activity中的数据也会丢失。这种问题也可以通过onSaveInstanceState()方法来解决,但是对于横竖屏已经有了更好的方案。
2.ViewModel
使用 ViewModel,我们就无需再用这种方法保存,因为 ViewModel 会自动感知生命周期,处理数据的保存与恢复。即数据可在发生屏幕旋转等配置(其它例如分辨率调整、权限变更、系统字体样式、语言变更等)更改后继续留存。
代码如下:
package com.example.viewmodeldemo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private MyViewModel mMyViewModel;
private TextView textView;
private Button mButton1;
private Button mButton2;
private final String TAG="MainActivityTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: ");
//创建一个ViewModel对象
mMyViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
textView=findViewById(R.id.textView);
//ViewModel会保存数据,当你重新创建的时候会加载显示出来
textView.setText(String.valueOf(mMyViewModel.number));
mButton1=findViewById(R.id.button1);
mButton2=findViewById(R.id.button2);
mButton1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mMyViewModel.number++;
textView.setText(String.valueOf(mMyViewModel.number));
}
});
mButton2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mMyViewModel.number+=2;
textView.setText(String.valueOf(mMyViewModel.number));
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}
}
package com.example.viewmodeldemo;
import androidx.lifecycle.ViewModel;
//这里的ViewModel可以看作全局变量仓库
public class MyViewModel extends ViewModel {
public int number=0;
}
这样当你旋转屏幕生命周期发生变化,你的数据还在。