Android Activity被回收的情况分析

 更新时间:2022年11月24日 11:52:04   作者:发飙的蜗牛YR  
Activity作为Android四大组件之一,他的启动绝对没有那么简单。这里涉及到了系统服务进程,启动过程细节很多,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值

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被回收内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android实现圆形图片的两种方式

    Android实现圆形图片的两种方式

    这篇文章主要为大家详细介绍了Android实现圆形图片的两种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • Android入门之TableLayout应用解析(二)

    Android入门之TableLayout应用解析(二)

    这篇文章主要介绍了Android入门之TableLayout应用,需要的朋友可以参考下
    2014-08-08
  • 利用libmp3lame实现在Android上录音MP3文件示例

    利用libmp3lame实现在Android上录音MP3文件示例

    本篇文章主要介绍了利用Lame库实现在Android上录音MP3文件示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • android之listview悬浮topBar效果

    android之listview悬浮topBar效果

    这篇文章主要为大家详细介绍了android之listview悬浮topBar效果的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • Android使用Activity实现简单的可输入对话框

    Android使用Activity实现简单的可输入对话框

    大家在做弹出对话框效果的时候最容易想到的是用Dialog显示,但其实弹出对话框的实现效果有两种:Dialog和Activity,那么下面这篇文章就来给大家介绍了关于Android使用Activity如何实现一个简单的可输入对话框的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10
  • Android实现动态改变app图标的示例代码

    Android实现动态改变app图标的示例代码

    本篇文章主要介绍了Android实现动态改变app图标的示例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • Android最新状态栏处理介绍

    Android最新状态栏处理介绍

    大家好,本篇文章主要讲的是Android最新状态栏处理介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • Android实现有视差效果的ListView

    Android实现有视差效果的ListView

    这篇文章给大家详解介绍了在Android中如何实现带有视差效果的ListView,文章给出了示例代码相信对大家的理解和学习更有帮助,有需要的朋友们下面来一起看看吧。
    2016-09-09
  • AndroidStudio3.6的卸载安装,Gradle持续下载/Gradle Build失败等问题

    AndroidStudio3.6的卸载安装,Gradle持续下载/Gradle Build失败等问题

    这篇文章主要介绍了AndroidStudio3.6的卸载安装,Gradle持续下载/Gradle Build失败等问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Android中EditText 设置 imeOptions 无效问题的解决方法

    Android中EditText 设置 imeOptions 无效问题的解决方法

    有时候我们需要在EditText 输出完之后 需要在键盘出现 右下角变成“Go”或“前往 搜索时;通常我们需要设置Android:imeOptions属性,但是今天我发现设置了无效,下面给大家分享下解决方案
    2016-12-12

最新评论