如何判断应用被强杀杀了怎么办,如何判断应用被强杀杀

Android(37)
关键词:强杀 / 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,这样所有的变量都是按正常的流程去初始化,也就不会空指针了。需要判断是否被强杀,如果是,就强制重新走应用的开始流程。通过在有心课堂的学习,进行了这个过程的模仿并梳理了思路。
流程梳理 #
自定义了一个 CustomApplication,用来初始化全局变量
public class CustomApplication extends Application {
public static ArrayList&String& mTestNullP
public static int mAppStatus = -1;
public void onCreate() {
super.onCreate();
做了一个父类 BaseActivity ,让每一个 Activity 都继承自 BaseActivity,各 Activity 要么会执行 protectApp() 方法,要么会执行 setupData() 方法,前者是由于强杀,后者是正常情况下的初始化操作。
public class BaseActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (CustomApplication.mAppStatus == -1) {
protectApp();
setupData();
protected void setupData() {
protected void protectApp() {
Intent intent = new Intent(this, HomeActivity.class);
intent.putExtra("action", "force_kill");
startActivity(intent);
下面是模拟强杀并且进行优化处理的做法流程
图中各 Activity 对应的代码如下
1、WelcomeActivity
public class WelcomeActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
CustomApplication.mAppStatus = 0;
super.onCreate(savedInstanceState);
protected void setupData() {
setContentView(R.layout.activity_welcome);
handler.sendEmptyMessageDelayed(0, 1000);
Handler handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
startActivity(new Intent(WelcomeActivity.this, LoginActivity.class));
2、LoginActivity
public class LoginActivity extends BaseActivity {
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 mHomeProfileB
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
protected void setupData() {
setContentView(R.layout.activity_home);
mHomeProfileBtn = $(R.id.id_mHomeProfileBtn);
mHomeProfileBtn.setOnClickListener(this);
CustomApplication.mTestNullPointer = new ArrayList&&();
CustomApplication.mTestNullPointer.add("profile");
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String action = intent.getStringExtra("action");
if ("force_kill".equals(action)) {
protectApp();
protected void protectApp() {
startActivity(new Intent(this, WelcomeActivity.class));
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 mProfileL
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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);
Learn from 有心课堂
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:50160次
积分:1367
积分:1367
排名:千里之外
原创:88篇
(22)(1)(12)(1)(1)(1)(3)(4)(3)(11)(31)(4)(1)(1)(1)应用被强杀了怎么办 - 简书
应用被强杀了怎么办
应用在后台运行时很容易被强杀,这很正常,但是回到前台时,很容易出现空指针的情况。怎么解决这样的问题,且看看Stay的见解。
我们先跳出来看看android的app运行原理。app在后台被强杀,是在内存不足的情况下被强制释放了,也有一些恶心的rom会强制杀掉那些后台进程以释放缓存以提高所谓的用户体验。我们都觉得android rom很恶心,但同时还是用些更恶心的手法去绕开这些瓶颈。乱,是因为在最上层没有一个很好的约束,这也是开源的弊端。anyway。我们还是得想破脑袋来解决这些问题,否则饭碗就没了。
我们先来重现这个bug:
假设: App A -& B -& C -& D在D activity中点Home键后台运行,打开ddms,选中该App进程,强杀。然后从“最近打开的应用”中选中该App,回到的界面是D activity,假设App中没有静态变量,这个时候是不会crash的,点击返回到C,这个时候也只是短暂黑屏后显示C界面。但如果C中有引用静态变量,并想要获取静态变量中的某个值时,就NullPointer了。
以上复现的流程就几个点,我们展开说下:
当应用被强杀,整个App进程都是被杀掉了,所有变量全都被清空了。包括Application实例。更别提那些静态变量了。
虽然变量被清空了,但Android给了一些补救措施。activity栈没有被清空,也就是说A -& B -& C -& D这个栈还保存了,只是ABCD这几个activity实例没有了。所以回到App时,显示的还是D页面
另外当activity被强杀时,系统会调用onSaveInstance去让你保存一些变量,但我个人觉得面对海量的静态变量,这个根本不够用。
返回到C会黑屏,是因为C要重绘,重走onCreate流程,渲染上需要点时间,所以会黑屏。
大概是以上这些点。如果App中没有静态变量的引用,那就不用出现NullPointer这个crash,也就不需要解决。一旦你有静态变量,或者有些Application的全局变量,那就很危险了。比如登录状态,user profile等等。这些值都是空了。
肯定会有人说,这没关系啊,所有的静态变量都改到单例去不就好了吗?然后附加上一些持久化cache,空了再取缓存就ok了嘛。嗯,这肯定也是一个办法,但是这样的束手束脚对开发来说也是痛苦,至少需要多30%的编码时间才能全部cover。另外,还有那么多帮你挖坑的队友,难省心啊。
既然App都被强杀了,干嘛不重新走第一次启动的流程呢,别让App回到D而是启动A,这样所有的变量都是按正常的流程去初始化,也就不会空指针了,对吧?有人说这方案用户体验一点都不好呀。但哪有十全十美的事呢,是重走流程好,还是一点一个NullPointer好?好好去沟通,相信产品也不会为难你的。当然你也可以拿iOS来举例,iOS在最近打开的应用里杀了某个App,重新点击那个App,还是会重走流程的啊。
如果你接受我的这个解决方案,那且想想如何让它不回到D而是重走流程呢?也就是说中断D的初始化而回到A,并且按back键,不会回到D,C,B。考虑一下。
我们先实例化这个场景吧。A 为App的启动页B 为登录页C 为首页D 为二级页面
简单说下解决方案,剩下的自己思考。
把首页launchMode设置为singleTask,具体为什么我就不说了,自己google。
在BaseActivity中onCreate中判断App是否被强杀,强杀就不往下走,直接重走App流程。
首页起一个承接或者中转的作用,所有跨级跳转都需要通过首页来完成。
再给个提示,以上场景的解决方案也可以用于解决其它相关问题:
在任意页面退出App
在任意页面返回到首页
在任意页面注销或者token失效回到登录页
其实最重要的知识点就是launchMode,很多人面试的时候都能背出来,甚至是原理。但真正会合理应用它们的少之又少。有的时候,技术的优劣体现于此。生搬硬套肯定是站不到最高点的。
题外话:当我第一次碰到这种问题的时候就在想,为啥Android非得这么来实现,既然都已经把应用强杀了,为什么还把栈信息保存下来了。既然把栈信息保存下来,为什么不把整个App变量都cache到硬盘上呢。这样还能节省ram,每个当前运行的App分到的最大内存也不用再加限制了啊。这样的话Bitmap的OOM也很难发生了。多好。好吧,iOS的内存管理貌似就是这样的机制(我这是白话文,勿较真)
有很多bug都是系统级的限制,虽说没有解决不了的技术,但是偏要钻牛角尖偏要用自以为的方式去解决问题,那么就是坑自己,并且也坑了队友。
做技术越久,越能感受到,难做的不是技术,而是业务。如何理解业务,以及背后的需求本质,是开发中最最重要的事情。与其盲目的拿需求就开始写代码,不如花上些时间去理解需求。弄清前因后果,想好封装与扩展。这些是对思维逻辑的锻炼,并且也是技术提升最快的方式。
参考阅读:
微信订阅号:staynotes
(包含更多技术心得分享)
六年移动开发设计经验求问,如何辨别安卓app是被系统强杀还是用户在后台强行关闭?_安卓吧吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:6,023贴子:
求问,如何辨别安卓app是被系统强杀还是用户在后台强行关闭?收藏
求问,如何辨别安卓app是被系统强杀还是用户在后台强行关闭?
安卓系统,亚马逊新一代Kindle入门级,电子墨水屏,舒适护眼,超长续航,让阅读更方便!亚马逊Kindle正品低价,货到付款!15天内免费退换!
放后台不管他等一会看看要不要重载
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或应用(155)
程序(98)
AA 11:21:35
怎么在代码中杀死 录音机应用程序
BB 11:22:17
forceStopPackage(包名)
AA 11:26:30
forceStopPackage(&com.android.bbksoundrecorder&),这个forceStopPackage()方法是在Activity中直接调用?
BB 11:28:54
先获取ActivityManager对象,然后通过AM对象去调这个方法
AA 11:30:08
BB 11:34:08
// 获得ActivityManager服务的对象& &
&&&&&&& mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
AA 11:34:30
是这样获取ActivityManager服务的对象?
BB 11:34:34
AA 11:34:59
BB 11:35:06
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:158104次
积分:2524
积分:2524
排名:第12329名
原创:82篇
转载:110篇
(1)(1)(5)(12)(16)(6)(1)(12)(24)(14)(13)(6)(14)(67)}

我要回帖

更多关于 android 应用杀死监听 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信