Android 捕捉app崩潰信息,友好的提示用戶應(yīng)用發(fā)生故障。

每個(gè)應(yīng)用在所難免會(huì)有bug,崩潰的時(shí)候一閃而過(guò),這樣的話交互非常的差。在此,我為大家介紹一種捕捉崩潰信息,并且友好的提示用戶的方式。
Thread類中有這樣一個(gè)函數(shù)

/**
     * Set the default handler invoked when a thread abruptly terminates
     * due to an uncaught exception, and no other handler has been defined
     * for that thread.
     *
     * <p>Uncaught exception handling is controlled first by the thread, then
     * by the thread's {@link ThreadGroup} object and finally by the default
     * uncaught exception handler. If the thread does not have an explicit
     * uncaught exception handler set, and the thread's thread group
     * (including parent thread groups)  does not specialize its
     * <tt>uncaughtException</tt> method, then the default handler's
     * <tt>uncaughtException</tt> method will be invoked.
     * <p>By setting the default uncaught exception handler, an application
     * can change the way in which uncaught exceptions are handled (such as
     * logging to a specific device, or file) for those threads that would
     * already accept whatever "default" behavior the system
     * provided.
     *
     * <p>Note that the default uncaught exception handler should not usually
     * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
     * infinite recursion.
     *
     * @param eh the object to use as the default uncaught exception handler.
     * If <tt>null</tt> then there is no default handler.
     *
     * @throws SecurityException if a security manager is present and it
     *         denies <tt>{@link RuntimePermission}
     *         ("setDefaultUncaughtExceptionHandler")</tt>
     *
     * @see #setUncaughtExceptionHandler
     * @see #getUncaughtExceptionHandler
     * @see ThreadGroup#uncaughtException
     * @since 1.5
     */
    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
         defaultUncaughtExceptionHandler = eh;
     }

通過(guò)注釋我們可以看出這個(gè)函數(shù)是用于設(shè)置當(dāng)線程由于未捕獲的異常突然終止而調(diào)用的默認(rèn)處理程序,下面我們通過(guò)代碼來(lái)熟知這個(gè)函數(shù)的作用。
我們先定義一個(gè)CrashHandler類,這個(gè)類實(shí)現(xiàn)Thread.UncaughtExceptionHandler接口,重寫uncaughtException方法來(lái)捕捉未處理的異常信息并通過(guò)Log打印出來(lái)。代碼如下:

  package com.zzw.TestCrashHandler;

import android.util.Log;

/**
 * Created by zzw on 2017/4/28.
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "CrashHandler";
    private static CrashHandler instance;


    private CrashHandler() {
    }

    public static CrashHandler getInstance() {

        if (instance == null) {
            instance = new CrashHandler();
        }

        return instance;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Log.e(TAG, e.toString());
    }

    public void init() {
        Thread.setDefaultUncaughtExceptionHandler(this);
    }
}

接下來(lái)我們?cè)?code>Application的onCreate()里面初始化:

  package com.zzw.TestCrashHandler;

import android.app.Application;

/**
 * Created by zzw on 2017/4/28.
 */

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        CrashHandler.getInstance().init();
    }
}

我們接著制造一個(gè)bug出來(lái):

  package com.zzw.TestCrashHandler;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.crash_bt).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.crash_bt:
                String nullStr = null;
                Log.e("zzz", nullStr);
                break;
        }
    }
}
image.png

異常捕捉到了,但是卻卡主了,然后就是ANR,看來(lái)是造成線程堵塞了,所以我們必須把這個(gè)給處理了。

  package com.zzw.TestCrashHandler;

import android.content.Context;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

/**
 * Created by zzw on 2017/4/28.
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "CrashHandler";
    private static CrashHandler instance;
    private Thread.UncaughtExceptionHandler defaultHandler;//系統(tǒng)默認(rèn)的UncaughtException處理器
    private Context context;


    private CrashHandler() {
    }

    public static CrashHandler getInstance() {

        if (instance == null) {
            instance = new CrashHandler();
        }

        return instance;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (!handleException(e) && defaultHandler != null) {  //如果用戶沒(méi)有處理則讓系統(tǒng)默認(rèn)的異常處理器來(lái)處理
            defaultHandler.uncaughtException(t, e);
        } else {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                Log.e(TAG, "error : ", ex);
            }
            //退出程序
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);
        }
    }

    public void init(Context context) {
        this.context = context;
        //獲取系統(tǒng)默認(rèn)的UncaughtException處理器
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }


    private boolean handleException(Throwable e) {
        if (e == null)
            return false;

        //使用Toast來(lái)顯示異常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(context, "程序發(fā)生意外情況,即將關(guān)閉,我們深感抱歉!我們將會(huì)盡快修復(fù)!", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();

        saveException(e);

        return true;
    }

    /**
     * 一般在這是把崩潰信息保存下來(lái),然后等wifi的時(shí)候上傳到服務(wù)器
     *
     * @param e 異常信息
     */
    private void saveException(Throwable e) {
        Log.e(TAG, e.toString());
    }

}

這樣的話我們就能夠提示用戶,然后把異常信息保存下來(lái),等待有Wifi的時(shí)候上傳就可以了。
效果如下:

這篇文章到這,Demo就不上傳了,希望大家有所收獲,有什么建議在下方評(píng)論,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容