zoukankan      html  css  js  c++  java
  • Android应用如何反馈Crash报告(转)

    一、为什么要Crash

    crash可以理解成堕落,垮台。按照我们通俗理解就是android App 因为不可预知的因素导致奔溃。

    即使我们的程序发布前,经历了很多的测试,但是经过无数用户各种使用情况之后,可能会发生意想不到的crash.

    为了及时反馈bug,通常我们都需要一个crash机制,以让开发人员尽快了解到问题所在,在下个版本中及时改进。

    二、如何做到Crash

    java的Thread中有一个UncaughtExceptionHandler接口,该接口的作用主要是为了  当 Thread 因未捕获的异常而突然终止时,调用处理程序。

    接口下面有setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

    方法,方法主要作用为设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。

    通用demo如下

    复制代码
     1 public class DefaultExceptionHandler implements UncaughtExceptionHandler {  
     2   
     3    
     4   
     5     private Context act = null;  
     6   
     7    
     8   
     9     public DefaultExceptionHandler(Context act) {  
    10   
    11        this.act = act;  
    12   
    13     }  
    14   
    15    
    16   
    17     @Override  
    18   
    19     public void uncaughtException(Thread thread, Throwable ex) {  
    20   
    21    
    22   
    23        // 收集异常信息 并且发送到服务器  
    24   
    25        sendCrashReport(ex);  
    26   
    27    
    28   
    29        // 等待半秒  
    30   
    31        try {  
    32   
    33            Thread.sleep(500);  
    34   
    35        } catch (InterruptedException e) {  
    36   
    37            //  
    38   
    39        }  
    40   
    41          
    42   
    43        // 处理异常  
    44   
    45        handleException();  
    46   
    47    
    48   
    49     }  
    50   
    51    
    52   
    53     private void sendCrashReport(Throwable ex) {  
    54   
    55    
    56   
    57        StringBuffer exceptionStr = new StringBuffer();  
    58   
    59        exceptionStr.append(ex.getMessage());  
    60   
    61    
    62   
    63        StackTraceElement[] elements = ex.getStackTrace();  
    64   
    65        for (int i = 0; i < elements.length; i++) {  
    66   
    67            exceptionStr.append(elements[i].toString());  
    68   
    69        }  
    70   
    71    
    72   
    73        //TODO   
    74   
    75        //发送收集到的Crash信息到服务器  
    76   
    77     }  
    78   
    79    
    80   
    81     private void handleException() {  
    82   
    83        //TODO   
    84   
    85        //这里可以对异常进行处理。  
    86   
    87        //比如提示用户程序崩溃了。  
    88   
    89        //比如记录重要的信息,尝试恢复现场。  
    90   
    91        //或者干脆记录重要的信息后,直接杀死程序。  
    92   
    93     }  
    94   
    95    
    96   
    97 }  
    复制代码

    在主线程中调用

    Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler(  
      
           this.getApplicationContext()));  

    之前一直对公司项目的CrashHandler类不是很熟悉,这里结合项目代码,看下是如何具体实现的

    首先,在AndroidManifest.xml中的application节点中配置name 

    <application 
            android:name="com.newland.mbop.application.CrashHandlerApp">
    CrashHandlerApp中初始化CrashHandler(实现UncaughtExceptionHandler的实现类)
    复制代码
        @Override
        public void onCreate() {
            CrashHandler ch = CrashHandler.getInstance();
            ch.init(this);
    
            super.onCreate();
        }
    复制代码

     最后看下CrashHandler类的具体实现

    复制代码
    public class CrashHandler implements UncaughtExceptionHandler {
    
    /** 获取CrashHandler实例 */
        public static CrashHandler getInstance() {
            if (INSTANCE == null)
                INSTANCE = new CrashHandler();
            return INSTANCE;
        }
        public void init(CrashHandlerApp app) {
            Log.i("BaseActivity","init()");
            this.app = app;
            // 设置该类为线程默认UncatchException的处理器。
            Thread.setDefaultUncaughtExceptionHandler(this);
        }
    
        /**
         * 当UncaughtException发生时会回调该函数来处理
         */
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            System.out.println("system wrong....");
            // MBOPApplication app=(MBOPApplication) mainContext;
            // app.setNeed2Exit(true);
            //异常信息收集
            collectCrashExceptionInfo(thread, ex);
            //应用程序信息收集
            collectCrashApplicationInfo(app);
            //保存错误报告文件到文件。
            saveCrashInfoToFile(ex);
            //MBOPApplication.setCrash(true);
            //判断是否为UI线程异常,thread.getId()==1 为UI线程
            if (thread.getId() != 1) {
    //            System.out.println("Exception ThreadId" + thread.getId());
                thread.interrupt();
                //TODO 跳转到IndexActivity
                System.out.println("Thread ID--->" + Thread.currentThread().getId());
    //            Intent intent =new Intent(mainContext,IndexActivity.class);
    //            actContext.startActivity(intent);
                //弹出对话框提示用户是否上传异常日志至服务器
                new Thread(){
                    public void run() {}{                                        
                        Looper.prepare();
                        new AlertDialog.Builder(app.getCurrentAct()).setTitle("异常处理").setMessage("您的程序出现异常,是否将异常信息上传至服务器?")
                        .setPositiveButton("是", new OnClickListener() {
                            
                            public void onClick(DialogInterface dialog, int which) {
                                new Thread(new Runnable() {
                                    
                                    @Override
                                    public void run() {
                                        sendCrashReportsToServer(app,false);
                                        
                                    }
                                }).start();
    //                            new Thread(){
    //                                public void run() {}{    
    //                                    try{
    //                                        System.out.println("执行上传线程ID"+this.getId());
    //                                        this.sleep(5000);
    //                                    }catch(Exception e){
    //                                        
    //                                    }
    //                                    sendCrashReportsToServer(app);
    //                                }
    //                            }.start();                                    
                            }
                        }).setNegativeButton("否", new OnClickListener() {
                            
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                
                            }
                        }).create().show();
                        Looper.loop();                                 
                    }
                }.start();
                
            } else {
    
    //            UserSessionCache usc=UserSessionCache.getInstance();
    //            ObjectOutputStream oos=null;
    //            try {
    //                oos.writeObject(usc);
    //            } catch (IOException e) {
    //                e.printStackTrace();
    //            }
    //            SharedPreferences prefenPreferences = mainContext
    //            .getSharedPreferences("IsMBOPCrash",Activity.MODE_PRIVATE);
    //            SharedPreferences.Editor editor = prefenPreferences.edit();
    //            editor.clear();
    //            editor.putBoolean("ISCRASH", true);
    //            editor.commit();
                
                // 方案一:将所有Activity放入Activity列表中,然后循环从列表中删除,即可退出程序
    
                for (int i = app.getActivityList().size()-1; i >=0; i--) {
                    Activity act = app.getActivityList().get(i);
                    act.finish();
                }
                CoreCommonMethod.setCrash(app, true);
                Intent intent = new Intent(app, WelcomeActivity.class);
                intent.putExtra(WelcomeActivity.EXTRA_DIRECT_TO_INDEX, true);
                intent.putExtra(WelcomeActivity.EXTRA_USERINFO, UserSessionCache.getInstance().getUserInfo());
                intent.putExtra(WelcomeActivity.EXTRA_CURRENT_PORTAL_ID, UserSessionCache.getInstance().getCurrentPortalId());
    //            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    //            app.startActivity(intent);                     
                android.os.Process.killProcess(android.os.Process.myPid());  
                
                //方案二:直接使用ActivityManager的restartPackage方法关闭应用程序,
                //此方法在android2.1之后被弃用,不起作用
    //            ActivityManager am = (ActivityManager) mainContext.getSystemService(Context.ACTIVITY_SERVICE);
    //            am.restartPackage(mainContext.getPackageName());
    
            }
        }
    
    
    
    }
    复制代码

    一般来说,发生crash的时候,我们需要知道客户端的SDK版本,程序版本,分辨率等等因素

  • 相关阅读:
    JSP/Servlet相关
    mysql 相关问题解决
    Git常用
    利用JDBC连接MySQL并使用MySQL
    memcache、redis原理对比
    Python 2.7.x 和 3.x 版本的重要区别
    python 单例模式
    python 装饰器原理及用法
    python 冒泡排序
    python 迭代器和生成器
  • 原文地址:https://www.cnblogs.com/weixiao870428/p/3512434.html
Copyright © 2011-2022 走看看