1. 程式人生 > >Android全域性異常捕獲,解決日誌列印三次的BUG

Android全域性異常捕獲,解決日誌列印三次的BUG

最近寫的專案需要自己寫全域性的異常捕捉,所以百度了很多解決方案,發現出現各種問題,好不容易找到一些比較靠譜的方案,但是卻發現出現了一個讓我無語的問題——日誌列印輸出三次。於是又開始去尋找答案,發現並沒有相關的解決。好嘛,看來還是要自己搞了。

發生該現象的基本原因就是:Application沒有完全退出,導致同一個異常多次執行,於是出現了同一個異常列印多次的問題

【解決方案】

  • 處理全域性異常的Handler:CrashHandler.java,程式碼如下:
public class CrashHandler implements UncaughtExceptionHandler
{
private static CrashHandler instance; private UncaughtExceptionHandler mDefaultHandler; public void init(Context ctx) { Thread.setDefaultUncaughtExceptionHandler(this); mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 獲取系統預設的UncaughtException處理器 public
static CrashHandler getInstance() { if (instance == null) { instance = new CrashHandler(); } return instance; } /** * 核心方法,當程式crash 會回撥此方法, Throwable中存放這錯誤日誌 */ @Override public synchronized void uncaughtException(Thread arg0, Throwable arg1) { if
(mDefaultHandler != null && !handleException(arg1)) { // 如果自定義的沒有處理則讓系統預設的異常處理器來處理 mDefaultHandler.uncaughtException(arg0, arg1); } else { // 退出程式 try { Thread.sleep(3000);// 如果處理了,讓程式繼續執行3秒再退出,保證檔案儲存並上傳到伺服器 } catch (InterruptedException e) { e.printStackTrace(); } Myapplication.getApplication().closeApplication();//完全退出Application // 如果使用如下方法退出程式,將會發生日誌列印三次的BUG // android.os.Process.killProcess(android.os.Process.myPid()); // System.exit(1); } } private boolean handleException(Throwable arg1) { String logPath; if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { logPath = Environment.getExternalStorageDirectory() .getAbsolutePath() + File.separator + File.separator + "log"; File file = new File(logPath); if (!file.exists()) { file.mkdirs(); } try { FileWriter fw = new FileWriter(logPath + File.separator + CommonUtil.getStrTime() + ".log", false); StringBuffer sb = new StringBuffer(); sb.append("/*************************************************/\n"); sb.append(new Date() + "\n"); // 錯誤資訊 // 這裡還可以加上當前的系統版本,機型型號 等等資訊 StackTraceElement[] stackTrace = arg1.getStackTrace(); sb.append("錯誤資訊:" + arg1.getMessage() + "\n"); for (int i = 0; i < stackTrace.length; i++) { String info = "檔案:" + stackTrace[i].getFileName() + " 類:" + stackTrace[i].getClassName() + " 方法:" + stackTrace[i].getMethodName() + " 行號:" + stackTrace[i].getLineNumber() + "\n"; sb.append(info); } sb.append("/*************************************************/\n"); fw.write(sb.toString()); fw.close(); // 上傳錯誤資訊到伺服器 uploadToServer(sb); } catch (IOException e) { Log.e("crash handler", "load file failed...", e.getCause()); } } return true; } private void uploadToServer(StringBuffer sb) { //執行上傳操作,錯誤資訊為:sb.toString(); } }
  • Handler的初始化以及MyApplication的編寫:MyApplication.java
public class Myapplication extends Application {
    private List<Activity> activitys = new LinkedList<Activity>();
    private List<Service> services = new LinkedList<Service>();
    private static int mTid;
    private static Myapplication mApplication;
    private CrashHandler crashHandler;

    @Override
    public void onCreate() {
        super.onCreate();
        mApplication = this;
        mTid = android.os.Process.myTid();
        crashHandler = CrashHandler.getInstance();
        crashHandler.init(getApplicationContext());
    }

    /**
     * 
     * TODO 獲取活動佇列
     */
    public List<Activity> getActivitys() {
        return activitys;
    }

    /**
     * 
     * TODO 新增Activity
     */
    public void addActivity(Activity activity) {
        activitys.add(activity);
    }

    /**
     * 
     * TODO 移除Activity
     */
    public void removeActivity(Activity activity) {
        activitys.remove(activity);
    }

    /**
     * 
     * TODO 新增服務
     */
    public void addService(Service service) {
        services.add(service);
    }

    /**
     * 
     * TODO 移除Service
     */
    public void removeService(Service service) {
        services.remove(service);
    }

    /**
     * 
     * TODO 關閉程式
     */
    public void closeApplication() {
        closeActivitys();
        closeServices();
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    /**
     * 
     * TODO 關閉所有的Activity
     */
    public void closeActivitys() {
        ListIterator<Activity> iterator = activitys.listIterator();
        while (iterator.hasNext()) {
            Activity activity = iterator.next();
            if (activity != null) {
                activity.finish();
            }
        }
    }

    /**
     * 
     * TODO 關閉所有的Service
     */
    private void closeServices() {
        ListIterator<Service> iterator = services.listIterator();
        while (iterator.hasNext()) {
            Service service = iterator.next();
            if (service != null) {
                stopService(new Intent(this, service.getClass()));
            }
        }
    }


    /**
     * 
     * TODO 獲取Application
     */
    public static Myapplication getApplication() {
        return mApplication;
    }

    /**
     * 
     * TODO 獲取主執行緒PID
     */
    public static int getmTid() {
        return mTid;
    }

}
  • BaseActivity的編寫:BaseActivity.java
public class BaseActivity extends Activity {
    protected BaseActivity mActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);// 儲存生命週期的完整性
        ((Myapplication) getApplication()).addActivity(this);
        mActivity = this;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ((Myapplication) getApplication()).removeActivity(this);
    }
}

總結

以上程式碼僅供參考,可能有更好的解決方法,歡迎大家給我留言。本人Android菜鳥一枚,並非大牛,可能部分程式碼不盡如人意,希望各位大大可以予以指出,我會虛心接受並積極改正,謝謝大家!