Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android進階——Crash異常捕獲並發送到服務器

Android進階——Crash異常捕獲並發送到服務器

編輯:關於Android編程

本篇文章包含以下內容:

Crash異常捕獲的簡單使用 Crash異常捕獲並發送到服務器

在項目中,我們常常會遇到Crash的現象,也就是程序崩潰的時候,這個時候最常看到的就是這個界面

\

如果你的項目已經發布到市場上了,這樣的崩潰對於開發人員是看不到的,所以我們得想方法將崩潰信息發送到服務器,交給我們的程序員查看,Google考慮到這一點,也提供了Thread.UncaughtExceptionHandler接口來實現這一問題

一、Crash異常捕獲的簡單使用

創建Crash異常捕獲很簡單,主要的步驟有:

創建BaseApplication繼承Application並實現Thread.UncaughtExceptionHandler 通過Thread.setDefaultUncaughtExceptionHandler(this)設置默認的異常捕獲 最後在manifests中注冊創建的BaseApplication
public class BaseApplication extends Application implements Thread.UncaughtExceptionHandler {

    @Override
    public void onCreate() {
        super.onCreate();
        //設置異常捕獲
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(final Thread thread, final Throwable ex) {
        //當有異常產生時執行該方法
    }
}

我們可以在uncaughtException()方法中輸出異常信息,並讓它隔兩秒殺死自己進程,這樣就不會彈出崩潰的彈窗,讓它直接退出程序

/**
 * 當有異常產生時執行該方法
 * @param thread 當前線程
 * @param ex 異常信息
 */
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.e("TAG","currentThread:"+Thread.currentThread()+"---thread:"+thread.getId()+"---ex:"+ex.toString());
        }
    }).start();
    SystemClock.sleep(2000);
    android.os.Process.killProcess(android.os.Process.myPid());
}

最後一步,別忘了在manifests中注冊BaseApplication


我們通過運行這個方法,來測試我們的程序

private void testError() {
    int a = 10 / 0;
}

查看Log信息,驗證我們的錯誤信息

12-18 11:40:02.074 7510-7555/com.handsome.ap E/TAG: currentThread:Thread[Thread-325,5,main]---thread:1---ex:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.handsome.ap/com.handsome.ap.Activity.MainActivity}: 
java.lang.ArithmeticException: divide by zero

完整代碼

public class BaseApplication extends Application implements Thread.UncaughtExceptionHandler {

    @Override
    public void onCreate() {
        super.onCreate();
        //設置異常捕獲
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 當有異常產生時執行該方法
     * @param thread 當前線程
     * @param ex 異常信息
     */
    @Override
    public void uncaughtException(final Thread thread, final Throwable ex) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("TAG","currentThread:"+Thread.currentThread()+"---thread:"+thread.getId()+"---ex:"+ex.toString());
            }
        }).start();
        SystemClock.sleep(2000);
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

二、Crash異常捕獲並發送到服務器

其實這裡就是將上面的簡單使用進行封裝,在一個類中處理相關的邏輯,主要步驟和上面是一樣的

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    /**
     * 捕獲異常回掉
     *
     * @param thread 當前線程
     * @param ex     異常信息
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        //導出異常信息到SD卡
        dumpExceptionToSDCard(ex);
        //上傳異常信息到服務器
        uploadExceptionToServer(ex);
        //延時1秒殺死進程
        SystemClock.sleep(2000);
        Process.killProcess(Process.myPid());
    }
}

我們為下面的信息保存先提供一些成員變量

//文件夾目錄
private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/crash_log/";
//文件名
private static final String FILE_NAME = "crash";
//文件名後綴
private static final String FILE_NAME_SUFFIX = ".trace";
//上下文
private Context mContext;

//單例模式
private static CrashHandler sInstance = new CrashHandler();
private CrashHandler() {}
public static CrashHandler getInstance() {
    return sInstance;
}

提供一個初始化的方法,記得調用Thread.setDefaultUncaughtExceptionHandler(this)這個方法

/**
 * 初始化方法
 *
 * @param context
 */
public void init(Context context) {
    //將當前實例設為系統默認的異常處理器
    Thread.setDefaultUncaughtExceptionHandler(this);
    //獲取Context,方便內部使用
    mContext = context.getApplicationContext();
}

剩下的就是保存異常信息了,這裡發送到服務端采用的是Bmob第三方後端雲

/**
 * 導出異常信息到SD卡
 *
 * @param ex
 */
private void dumpExceptionToSDCard(Throwable ex) {
    if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        return;
    }
    //創建文件夾
    File dir = new File(PATH);
    if (!dir.exists()) {
        dir.mkdirs();
    }
    //獲取當前時間
    long current = System.currentTimeMillis();
    String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current));
    //以當前時間創建log文件
    File file = new File(PATH + FILE_NAME + time + FILE_NAME_SUFFIX);
    try {
        //輸出流操作
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
        //導出手機信息和異常信息
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
        pw.println("發生異常時間:" + time);
        pw.println("應用版本:" + pi.versionName);
        pw.println("應用版本號:" + pi.versionCode);
        pw.println("android版本號:" + Build.VERSION.RELEASE);
        pw.println("android版本號API:" + Build.VERSION.SDK_INT);
        pw.println("手機制造商:" + Build.MANUFACTURER);
        pw.println("手機型號:" + Build.MODEL);
        ex.printStackTrace(pw);
        //關閉輸出流
        pw.close();
    } catch (Exception e) {

    }
}

/**
 * 上傳異常信息到服務器
 *
 * @param ex
 */
private void uploadExceptionToServer(Throwable ex) {
    Error error = new Error(ex.getMessage());
    error.save(new SaveListener() {
        @Override
        public void done(String objectId, BmobException e) {

        }
    });
}

在我們的Application中創建該異常捕獲

CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(this);

我們同樣按照上面的方法來測試這個異常捕獲,運行程序,在文件夾中找到我們創建的目錄

\

找到對應文件

\

查看對應信息

\

後台數據庫的信息

\

完整代碼

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    //文件夾目錄
    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/crash_log/";
    //文件名
    private static final String FILE_NAME = "crash";
    //文件名後綴
    private static final String FILE_NAME_SUFFIX = ".trace";
    //上下文
    private Context mContext;

    //單例模式
    private static CrashHandler sInstance = new CrashHandler();
    private CrashHandler() {}
    public static CrashHandler getInstance() {
        return sInstance;
    }

    /**
     * 初始化方法
     *
     * @param context
     */
    public void init(Context context) {
        //將當前實例設為系統默認的異常處理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        //獲取Context,方便內部使用
        mContext = context.getApplicationContext();
    }

    /**
     * 捕獲異常回掉
     *
     * @param thread 當前線程
     * @param ex     異常信息
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        //導出異常信息到SD卡
        dumpExceptionToSDCard(ex);
        //上傳異常信息到服務器
        uploadExceptionToServer(ex);
        //延時1秒殺死進程
        SystemClock.sleep(2000);
        Process.killProcess(Process.myPid());
    }

    /**
     * 導出異常信息到SD卡
     *
     * @param ex
     */
    private void dumpExceptionToSDCard(Throwable ex) {
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return;
        }
        //創建文件夾
        File dir = new File(PATH);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //獲取當前時間
        long current = System.currentTimeMillis();
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current));
        //以當前時間創建log文件
        File file = new File(PATH + FILE_NAME + time + FILE_NAME_SUFFIX);
        try {
            //輸出流操作
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            //導出手機信息和異常信息
            PackageManager pm = mContext.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
            pw.println("發生異常時間:" + time);
            pw.println("應用版本:" + pi.versionName);
            pw.println("應用版本號:" + pi.versionCode);
            pw.println("android版本號:" + Build.VERSION.RELEASE);
            pw.println("android版本號API:" + Build.VERSION.SDK_INT);
            pw.println("手機制造商:" + Build.MANUFACTURER);
            pw.println("手機型號:" + Build.MODEL);
            ex.printStackTrace(pw);
            //關閉輸出流
            pw.close();
        } catch (Exception e) {

        }
    }

    /**
     * 上傳異常信息到服務器
     *
     * @param ex
     */
    private void uploadExceptionToServer(Throwable ex) {
        Error error = new Error(ex.getMessage());
        error.save(new SaveListener() {
            @Override
            public void done(String objectId, BmobException e) {

            }
        });
    }
}

到這裡我們的Crash異常捕獲就結束了,很簡單的一段代碼就可以解決你缺少的項目經驗

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved