# 对 Android 应用被强杀重回应用的优化处理(重走应用流程)

关键词:强杀 / home 键 / static 导致的 NullPointerException / BaseActivity

背景:Android 编程中我们经常会使用到 static 变量,static 变量属于类本身,所有实例调用的静态变量的值都是一样的,如果在某一个类里改变了一个静态变量的值,其它所有的实例在调用这个值的时候也全都会发生了变化。static 在虚拟机中单独占用内存,在不同的包和类中都能使用,很方便。但是当应用被强杀后,若应用较长时间处于后台,会导致 NullPointerException 的异常产生。

解释:因为按下 Android 的 home 键,如果位于后台较长时间,或者由于内存不足应用被强杀,应用依然会保持 activity 的栈信息(activity 栈没有被清空,比如说 A -> B -> C -> D 这个栈还保存了,只是 ABCD 这几个 activity 实例没有了。所以回到 App 时,显示的还是 D 页面),当我们选择 “最近打开的应用” 回到前台的时候,该 activity 会重新执行 onCreate() 进行初始化操作(也包括 application 的初始化),如果操作中包含了对其他类的静态变量的引用,而应用被强杀后该静态变量的实例已被虚拟机回收,这样便引发了空指针。
那么问题来了,我们理应重新走应用的流程,如何改善这种情况而避免这种异常的发生呢,既然 App 都被强杀了,干嘛不重新走第一次启动的流程呢,别让 App 回到 D 而是再启动 A,这样所有的变量都是按正常的流程去初始化,也就不会空指针了。需要判断是否被强杀,如果是,就强制重新走应用的开始流程。通过在有心课堂的学习,进行了这个过程的模仿并梳理了思路。

参考:应用被强杀了怎么办 http://notes.stay4it.com/2016/02/26/how-to-handle-app-force-killed/

流程梳理 #

自定义了一个 CustomApplication,用来初始化全局变量

public class CustomApplication extends Application {

    public static ArrayList<String> mTestNullPointer;
    // 我们把 -1 模拟表示被强杀
    public static int mAppStatus = -1;

    @Override
    public void onCreate() {
        super.onCreate();
    }
}

做了一个父类 BaseActivity ,让每一个 Activity 都继承自 BaseActivity,各 Activity 要么会执行 protectApp() 方法,要么会执行 setupData() 方法,前者是由于强杀,后者是正常情况下的初始化操作。

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 判断如果被强杀,就回到 HomeActivity 中去,否则可以初始化
        if (CustomApplication.mAppStatus == -1) {
            // 重走应用流程
            protectApp();
        } else {
            setupData();
        }

    }

    // 在这里做初始化操作
    protected void setupData() {

    }

    // 使用 protected 让子类可以重写该方法
    protected void protectApp() {
        // 重新走应用的流程是一个正确的做法,因为应用被强杀了还保存 Activity 的栈信息是不合理的
        Intent intent = new Intent(this, HomeActivity.class);
        intent.putExtra("action", "force_kill");
        startActivity(intent);
    }

}

下面是模拟强杀并且进行优化处理的做法流程

对 Android 应用被强杀重回应用的优化处理(重走应用流程)

图中各 Activity 对应的代码如下

1、WelcomeActivity

public class WelcomeActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 把状态变为 0 能使父类不会走 protectApp()
        CustomApplication.mAppStatus = 0;
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void setupData() {
        setContentView(R.layout.activity_welcome);
        handler.sendEmptyMessageDelayed(0, 1000);
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            startActivity(new Intent(WelcomeActivity.this, LoginActivity.class));
            finish();
        }
    };
}

2、LoginActivity

public class LoginActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
    }

    public void login(View view) {
        startActivity(new Intent(this, HomeActivity.class));
    }
}

3、HomeActivity

/**
 * HomeActivity 的启动模式为 "singleTask"
 */

public class HomeActivity extends BaseActivity implements View.OnClickListener {

    private Button mHomeProfileBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // 初始化操作
    @Override
    protected void setupData() {
        setContentView(R.layout.activity_home);
        mHomeProfileBtn = $(R.id.id_mHomeProfileBtn);
        mHomeProfileBtn.setOnClickListener(this);
        CustomApplication.mTestNullPointer = new ArrayList<>();
        CustomApplication.mTestNullPointer.add("profile");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String action = intent.getStringExtra("action");
        if ("force_kill".equals(action)) {
            // 在 ProfileActivity 被强杀了就重新走应用的流程
            protectApp();
        }
    }

    @Override
    protected void protectApp() {
        // 回到 WelcomeActivity
        startActivity(new Intent(this, WelcomeActivity.class));
        finish();
    }

    @Override
    public void onClick(View view) {
        startActivity(new Intent(this, ProfileActivity.class));
    }

    @SuppressWarnings("unchecked")
    private <T> T $(int resId) {
        return (T) findViewById(resId);
    }
}

4、ProfileActivity

public class ProfileActivity extends BaseActivity {

    private TextView mProfileLabel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 让所有继承于 BaseActivity 的子类的 onCreate() 都直接交给父类 BaseActivity 去操作,
        // 让父类进行一系列的先判断,不让子类随随便便地进行初始化
    }

    @Override
    protected void setupData() {
        setContentView(R.layout.activity_profile);
        mProfileLabel = $(R.id.id_mProfileLabel);
        mProfileLabel.setText(CustomApplication.mTestNullPointer.toString());
    }

    @SuppressWarnings("unchecked")
    private <TT> TT $(int resId) {
        return (TT) findViewById(resId);
    }

}

End.

Note by HF.
Learn from 有心课堂


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值