Android应用被强杀或应用被回收导致的空指针问题等其他问题

android应用被强杀或应用被回收导致的空指针问题等其他问题 - 简书

在开发中我们经常会遇见app退到后台再打开会出现空指针、页面显示不全等一系列奇怪的问题。

问题分析:

当我们的进程被强杀或者被回收的时候,Android系统虽然让你的进程没有了,但是此进程中Activity中栈的信息还是存在的,也就是说此时当你点开此应用的时候程序中的Activity栈信息仍然存在,只不过Activity中的数据都没有了,需要重新创建新的Activity数据。

处理方式:

分别涉及到:一个单例ConstantInstance 基类BaseAcyivity 首页MainActivity 启动页IndexActivity

在启动页IndexActivity 存一个单例值
1
2
3
4
5
6
7
8
public class IndexActivity extends BaseAcyivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// 在单例中存一个状态标志app属于正常状态
ConstantInstance.getInstance().setAppStatus(ConstantInstance.STATUS_NORMAL);
super.onCreate(savedInstanceState);
、、、、、、
}
基类BaseAcyivity onCreate方法判断单例的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class BaseAcyivity extends AutoLayoutActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
switch (ConstantInstance.getInstance().getAppStatus()) {
/**
* 应用被强杀
*/
case ConstantInstance.STATUS_FORCE_KILLED:
//跳到主页,主页lauchmode SINGLETASK
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(ConstantInstance.KEY_HOME_ACTION, ConstantInstance.ACTION_RESTART_APP);
startActivity(intent);
break;
}
}
这里我们如果发现单例的状态变为非正常状态,被强杀了,就跳转到首页MainActivity ,
MainActivity 的启动模式为SINGLETASK,这时候会调用MainActivity 的onNewIntent方法
MainActivity的onNewIntent
1
2
3
4
5
6
7
8
9
10
11
12
 @Override
protected void onNewIntent(Intent intent) {
int appStatus = intent.getIntExtra(ConstantInstance.KEY_HOME_ACTION, ConstantInstance.STATUS_NORMAL);
L.e("appStatus====" + appStatus);
switch (appStatus) {
case ConstantInstance.ACTION_RESTART_APP:
startActivity(new Intent(this, IndexActivity.class));
finish();
break;
}
}
这里我们发现需要重启app 重启动页开始 重新启动app
ConstantInstance
1
2
3
public static final int STATUS_FORCE_KILLED = -1; //应用放在后台被强杀了
public static final int STATUS_NORMAL = 2; //APP正常态
public static final int ACTION_RESTART_APP = 9;//被强杀

防止应用被强杀而导致的空指针

当系统的内存不足的时候,系统会把后台程序强杀掉,所有的变量都被清空了,唯有activity的栈信息被保留。当用户再次启动这程序的时候,它会从之前的界面开始启动(有点坑,干嘛不重头来呢)。一旦这个界面有静态变量(静态变量随着类的加载而加载)并且对这个静态变量进行取值操作,就会导致了空指针异常。下面讲解如何设计框架避免这个问题:

1
2
3
4
5
6
7
8
9
10
11
public class CustomApplication extends Application{

public static ArrayList<String> mTestNullPointers;
//防止应用被强杀
//mAppStatus=-1 表示被强杀了
public static int mAppStatus=-1;
@Override
public void onCreate() {
super.onCreate();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BaseActivity extends AppCompatActivity {

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

if (CustomApplication.mAppStatus == -1) {
protectApp();
} else {
setupData();
}
}

protected void protectApp() {
Intent intent = new Intent(this, HomeActivity.class);
intent.putExtra("action", "force_kill");
startActivity(intent);
}

protected void setupData() {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//app的入口界面
public class WelcomeActivity extends BaseActivity {

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

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//置为正常的状态
CustomApplication.mAppStatus=0;
super.onCreate(savedInstanceState);
}

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

@Override
protected void onPause() {
super.onPause();
handler.removeMessages(0);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class HomeActivity extends BaseActivity implements View.OnClickListener {
private Button mHomeProfileBtn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
protected void setupData() {
setContentView(R.layout.activity_home);
mHomeProfileBtn=(Button)findViewById(R.id.mHomeProfileBtn);
mHomeProfileBtn.setOnClickListener(this);
CustomApplication.mTestNullPointers=new ArrayList<>();
CustomApplication.mTestNullPointers.add("profile");
}


@Override
protected void protectApp() {
//重头开始
startActivity(new Intent(this,WelcomeActivity.class));
finish();
}

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

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String action= intent.getStringExtra("action");
if(action.equals("force_kill")){
protectApp();
}
}
}

不管app是在HomeActivity或其他的Activity被强杀,因为这些Activity都继承BaseActivity,所以会先执行BaseActivity的onCreate(),这时候mAppStatus=-1.那么为什么要跳转到HomeActivity呢?HomeActivity的启动模式被设置为SingleTask,处理应用被强杀也是借助singletask,强杀了但activity栈未被清空,所以为了避免空指针,需要重新退出app再重新走应用流程WelcomeActivity。