Android系统ANR以及Force Close出现的原因以及解决办法

时间:2022-02-01 14:46:35

ANR是Application Not Responding的简称,当android某个应用处于长期假死状态时,系统会弹出一个窗口: XXX is not responding, force close or wait。
用户可以选择wait让程序继续运行,在程序里对响应性能的设计很重要,这样系统不会显示ANR给用户。

一. ANR的产生

应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:

  1. 在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
  2. BroadcastReceiver在10秒内没有执行完毕
    【上面的时间在系统里定义的】

二. 如何避免ANR

  1. 运行在主线程里的任何方法都尽可能少做事情。Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。

  2. 网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里来完成或这用异步请求的方式。主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。

  3. IntentReceiver执行时间的特殊限制意味着它应该做小的、琐碎的工作如保存设定或者注册一个Notification,应用程序应该避免在BroadcastReceiver里做耗时的动作。但不再是在子线程里做这些任务(因为BroadcastReceiver的生命周期短),如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个Service。如果应用程序在响应Intent广播时需要向用户展示什么,你应该使用Notification Manager来实现。

三. Force Close原因

forceclose,意为强行关闭,当前应用程序发生了冲突。NullPointExection(空指针),IndexOutOfBoundsException(下标越界),就连Android API使用的顺序错误也可能导致(比如setContentView()之前进行了findViewById()操作)等等一系列未捕获异常。

四. 如何避免

如何避免弹出Force Close窗口 ,可以实现Thread.UncaughtExceptionHandler接口的uncaughtException方法 代码如下:

public class MainActivity extends Activity implements Thread.UncaughtExceptionHandler, View.OnClickListener {
    private List<String> mList = new ArrayList<String>();
    private Button btn;

    private int pid;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.i("tag", "--->>onCreate");

        initView();
        //设置处理异常的handler
        Thread.setDefaultUncaughtExceptionHandler(this);

    }

    /** * 初始化控件 */
    private void initView() {
        btn = (Button) findViewById(R.id.main_btn);
        btn.setOnClickListener(this);

    }

    @Override
    public void uncaughtException(Thread arg0, Throwable arg1) {
        // TODO Auto-generated method stub
        Log.i("tag",  "截获到forceclose,异常原因为:" + "\n" +
                arg1.toString()+" Thread:"+arg0.getId());
       // finish();//结束当前activity
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        switch (arg0.getId()) {
            case R.id.main_btn:
                mList.get(1) ;//产生异常
                break;

            default:
                break;
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.i("tag", "--》onpause");
    }

    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        Log.i("tag", "--->onstop");
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.i("tag", "-->ondestroy");
    }
}

再补充一句,想要哪个线程可以处理未捕获异常,Thread.setDefaultUncaughtExceptionHandler( this);这句代码都要在那个线程中执行一次

在uncaughtException方法中,第一个参数是线程,第二个参数是异常

public void uncaughtException(Thread arg0, Throwable arg1) {
    // TODO Auto-generated method stub
    Log.i("tag",  "截获到forceclose,异常原因为:" + "\n" +
          arg1.toString()+" Thread:"+arg0.getId());
    // finish();//结束当前activity
    android.os.Process.killProcess(android.os.Process.myPid());//自杀式
}

成功捕获到了异常,而且activity也退出了,可是并不是安全退出,因为当你再次点击打开apk时,发现程序无响应。

为了解决上述问题,我在uncaughtException方法里将进程杀死,杀死进程有好多中方法,在此列举一个自杀式方法。

参考文章:
http://blog.csdn.net/bailyzheng/article/details/13095231
http://www.cnblogs.com/jycboy/p/5754396.html