編輯:關於Android編程
本篇文章包含以下內容:
Crash異常捕獲的簡單使用 Crash異常捕獲並發送到服務器
在項目中,我們常常會遇到Crash的現象,也就是程序崩潰的時候,這個時候最常看到的就是這個界面
如果你的項目已經發布到市場上了,這樣的崩潰對於開發人員是看不到的,所以我們得想方法將崩潰信息發送到服務器,交給我們的程序員查看,Google考慮到這一點,也提供了Thread.UncaughtExceptionHandler接口來實現這一問題
創建Crash異常捕獲很簡單,主要的步驟有:
創建BaseApplication繼承Application並實現Thread.UncaughtExceptionHandler 通過Thread.setDefaultUncaughtExceptionHandler(this)設置默認的異常捕獲 最後在manifests中注冊創建的BaseApplicationpublic 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()); } }
其實這裡就是將上面的簡單使用進行封裝,在一個類中處理相關的邏輯,主要步驟和上面是一樣的
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異常捕獲就結束了,很簡單的一段代碼就可以解決你缺少的項目經驗
概述有圖有真相,所以先上圖:上圖是從Android官網截下的Activity的生命周期流程圖,結構非常清晰,它描述了Activity在其生命周期中所有可能發生的情況以及發
用過美團客戶端的朋友都知道,美團的加載等待提示很有意思,是一種動畫的形式展現給我們,下面我們就對這背後的原理進行了解,然後實現自己的等待動畫效果。首先我們准備兩張圖片:這
0x00 序隨著移動安全越來越火,各種調試工具也都層出不窮,但因為環境和需求的不同,並沒有工具是萬能的。另外工具是死的,人是活的,如果能搞懂工具的原理再結合上
本文實例講述了Android編程實現調用系統圖庫與裁剪圖片功能。分享給大家供大家參考,具體如下:在Android開發中,調用系統圖庫和裁剪照片是很常見的需求。相對於自己實