Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 60025|回复: 0

关于Android Force Close 出现的原因 以及解决方法

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-6 08:17:39 | 显示全部楼层 |阅读模式

    一、原因:

    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());
        }
    

     接下来,看log日志的结果:

    08-0918:50:27.87410739-10739/example.com.force_anrI/tag:--->>onCreate
    08-0918:50:31.66410739-10739/example.com.force_anrI/tag:forceclose
    java.lang.IndexOutOfBoundsException:Invalidindex1,sizeis0Thread:1

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

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

    修改如下: 

    @Override  
        public void uncaughtException(Thread arg0, Throwable arg1) {  
            // TODO Auto-generated method stub  
            Log.i("tag",  "截获到forceclose,异常原因为:" + "\n" +  
                       arg1.toString());  
             android.os.Process.killProcess(android.os.Process.myPid()); //
        }  其他程序未变。。
    

    3,我们不仅可以在主线程中这么做,还可以在子线程中进行:

    然后在activity的生命周期中开启子线程,监听未捕获异常的发生。

    class MyRunnable extends Thread implements Thread.UncaughtExceptionHandler {
    
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Thread.setDefaultUncaughtExceptionHandler(this);
            }
            @Override
            public void uncaughtException(Thread arg0, Throwable arg1) {
                // TODO Auto-generated method stub
                Log.i("tag", "childThread:截获到forceclose,异常原因为:" + "\n" +
                        arg1.toString()+"  Thread->"+arg0.getId()+" 本线程id->"+Thread.currentThread().getId()+" "+
                        Thread.currentThread().getName());
                android.os.Process.killProcess(android.os.Process.myPid());
            }
    
        }
    

      这里有个问题:我们明明是在子线程捕获的异常,但是怎么Thread的id->1 本线程id->1,为什么线程是主线程!在下面探讨这个问题。

    08-09 19:02:47.734 14483-14483/example.com.force_anr I/tag: --->>onCreate
    08-09 19:02:51.304 14483-14483/example.com.force_anr I/tag: childThread:截获到forceclose,异常原因为:
    java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0 Thread->1 本线程id->1 main
    

      

    4.解决第三步的问题

    我们重写子线程:在子线程里设置异常,同时别忘把activity中的捕获异常的代码和发生异常的代码删除。

    class MyRunnable extends Thread implements Thread.UncaughtExceptionHandler {
    
            int a[];
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Thread.setDefaultUncaughtExceptionHandler(this);
                int i = a[0];//异常
            }
            @Override
            public void uncaughtException(Thread arg0, Throwable arg1) {
                // TODO Auto-generated method stub
                Log.i("tag", "childThread:截获到forceclose,异常原因为:" + "\n" +
                        arg1.toString()+"  Thread->"+arg0.getId()+" 本线程id->"+Thread.currentThread().getId()+" "+
                        Thread.currentThread().getName());
                android.os.Process.killProcess(android.os.Process.myPid());
            }
    
        }
    

      在启动程序看到下面的log:

    08-09 19:08:20.124 16308-16308/example.com.force_anr I/tag: --->>onCreate
    08-09 19:08:20.124 16308-16341/example.com.force_anr I/tag: childThread:截获到forceclose,异常原因为:
                                                                java.lang.NullPointerException: Attempt to read from null array  Thread->44829 本线程id->44829 Thread-44829
    08-09 19:08:20.254 16349-16349/example.com.force_anr I/tag: --->>onCreate
    08-09 19:08:20.354 16376-16376/example.com.force_anr I/tag: --->>onCreate
    08-09 19:08:20.354 16376-16411/example.com.force_anr I/tag: childThread:截获到forceclose,异常原因为:
                                                                java.lang.NullPointerException: Attempt to read from null array  Thread->44839 本线程id->44839 Thread-44839
    

     好像是尝试启动了两次,看下Thread已经变了。所以在这个方法uncaughtException(Thread arg0, Throwable arg1)中的arg0指的是发生异常的那个Thread,而不一定是uncaughtException注册的Thread。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-2 09:49 , Processed in 0.086670 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表