app異常處理

鋸齒流沙發表於2017-12-26

當app釋出到市場,使用者下載使用過程中如果出現crash的情況,對使用者來說是非常不友好,有可能使用者直接把應用給解除安裝了。因此捕獲以及分析crash對我們來說至關重要,讓我們及時修復異常,減少使用者流失。

定義crash處理類CrashHandler,並且實現Thread.UncaughtExceptionHandler介面

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private final String PATH = "error";
    private Context mContext;

    private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler;

    public void init(Context context)
    {
        // 獲取程式預設的異常處理
        mUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 把自定義的異常處理替換預設的
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = context;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex)
    {
        //獲取異常寫入檔案
        handleException(ex);
        //先判斷是否連結了網路,開啟後臺服務,將異常檔案上傳到伺服器
        if(NetWorkState.IsConnectNet(mContext))
        {
            Intent it = new Intent(mContext, ExceptionService.class);
            mContext.startService(it);
        }
        //如果系統提供了預設到異常處理,則交給系統去結束程式,否則自己結束
        if(mUncaughtExceptionHandler != null)
        {
            mUncaughtExceptionHandler.uncaughtException(thread, ex);
        }else{
            Process.killProcess(Process.myPid());
        }
    }

    private boolean handleException(Throwable ex)
    {
        String xml = getExceptionXML(mContext, ex);
        if(xml != null)
        {
            //儲存crash日誌檔案到sdcard
            String filename = SaveFile(xml.getBytes());
            if(filename != null)
            {
                return true;
            }
        }

        return false;
    }

    public static String getExceptionXML(Context context, Throwable ex)
    {
        String xml = null;
        if(context != null && ex != null)
        {
            xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><info>";
            xml += collectDeviceInfo(context);//收集裝置資訊
            xml += collectErrorInfo(ex);    //收集錯誤資訊
            xml += "</info>";
        }
        return xml;
    }
    
}
複製程式碼

這裡首先要獲取得到crash資訊,然後將crash資訊存到sdcard,得到crash資訊檔案後,開啟後臺服務,將檔案上傳到後臺即可。這裡收集到資訊包括:應用版本號、手機配置資訊和crash資訊。

public class ExceptionService extends Service {
    private boolean mIsRun;
    private Handler mHandler = new Handler();

    @Override
    public void onCreate()
    {
        super.onCreate();

        mIsRun = false;
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        if(intent != null && !mIsRun)
        {
            mIsRun = true;
            StartUpload();
        }

        return super.onStartCommand(intent, flags, startId);
    }

    private void StartUpload()
    {
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                //這裡將crash檔案上傳到伺服器
                
                
                //上傳檔案完畢之後,關閉後臺服務
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        ExceptionService.this.stopSelf();
                        System.exit(0);
                    }
                });
            }
        }).start();
    }
}
複製程式碼

這個後臺服務主要的工作就是將crash上傳到伺服器,上傳完成就關閉服務。

public class BaseApplication extends Application {
    private static Context mContext;
    private CrashHandler mCrashHandler;
    @Override
    public void onCreate() {

        mContext = this;
        mCrashHandler = new CrashHandler();
        mCrashHandler.init(mContext);
        super.onCreate();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
    }

    /**
     * 獲取上下文
     *
     * @return
     */
    public static Context getContext() {
        return mContext;
    }


    public static BaseApplication getInstance() {
        return (BaseApplication) mContext;
    }
}
複製程式碼

這裡需要在onCreate方法裡面初始化CrashHandler,主要是為應用設定異常處理,然後程式才能獲取未處理的異常。

經過上面的步驟就可以處理crash了,只要應用crash了就會將資訊上傳到伺服器,我們從伺服器中獲取資訊,分析crash進而處理這些bug。