Android Activity被回收的情况分析
作者:发飙的蜗牛YR
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; }
这样当你旋转屏幕生命周期发生变化,你的数据还在。
到此这篇关于Android Activity被回收的情况分析的文章就介绍到这了,更多相关Android Activity被回收内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!