首页 > 系统 > Android > 正文

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

2019-11-09 17:48:15
字体:
来源:转载
供稿:网友

关键词:强杀 / 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 有心课堂



发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表