編輯:關於Android編程
對於已經上線的項目,為了避免有沒有考慮到的bug發生,方便維護以及為了有更好的用戶體驗,不能再發生異常的時候彈出系統默認的提示框. 而是應該由自己程序本身捕獲,先保存到本地,當下次打開軟件時上傳到服務器. 這樣也可以為我們收集到BUG的第一手資料(主動收集), 更快地定位到異常位置並修復,這樣既節省了時間,也提高了工作的效率.
還有本身這種收集異常信息的做法也是借鑒於windows中殺毒軟件的做法(如遇到本地病毒庫或者服務器上都沒有遇到的病毒,上傳添加到病毒庫中) ..或者有很多軟件做的用戶反饋,模式都比較相似
這裡還有一些細節要注意:
[java]
1. 在上傳的時候還可以將該<SPAN style="COLOR: #cc0000">app的version(版本號),該手機的型號,網絡制式</SPAN>等信息一並發送的服務器
2. 原因:<SPAN style="COLOR: #cc0000">Android的兼容性</SPAN>眾所周知,所以可能錯誤不是每個手機都會報錯,還是有<SPAN style="COLOR: #cc0000">針對性</SPAN>的去debug比較好,而不是全部都進行分析,花費不必要的時間:
某些BUG可能是由於屏幕適配,或者由於不同品牌的手機使用的並不是原生系統,一般是經過修改過的,比較典型的是小米手機,對於系統修改的部分非常多.,有可能在原生系統
或者主流的三星,摩托等手機上運行無誤的程序,會發生特定的異常
1. 在上傳的時候還可以將該app的version(版本號),該手機的型號,網絡制式等信息一並發送的服務器
2. 原因:Android的兼容性眾所周知,所以可能錯誤不是每個手機都會報錯,還是有針對性的去debug比較好,而不是全部都進行分析,花費不必要的時間:
某些BUG可能是由於屏幕適配,或者由於不同品牌的手機使用的並不是原生系統,一般是經過修改過的,比較典型的是小米手機,對於系統修改的部分非常多.,有可能在原生系統
或者主流的三星,摩托等手機上運行無誤的程序,會發生特定的異常
原理: 跟JavaEE的自定義異常捕獲一樣,將錯誤一直向上拋,然後在最上層統一處理。這裡就可以獲得異常信息,先保存到本地,下一次運行的時候上傳到服務區. 當然這些可以由程序員自己根據實際情況具體處理,這裡只是提供捕獲異常並進一步處理的一個方案. 主要用到的是自定義的CrashHandler(繼承自UncaughtExceptionHandler),具體代碼如下:
[java]
/**
* @author Tian
* 在Application中統一捕獲異常,保存到文件中下次再打開時上傳
*/
public class CrashHandler implements UncaughtExceptionHandler {
/** 是否開啟日志輸出,在Debug狀態下開啟,
* 在Release狀態下關閉以提示程序性能
* */
public static final boolean DEBUG = true;
/** 系統默認的UncaughtException處理類 */
private Thread.UncaughtExceptionHandler mDefaultHandler;
/** CrashHandler實例 */
private static CrashHandler INSTANCE;
/** 程序的Context對象 */
// private Context mContext;
/** 保證只有一個CrashHandler實例 */
private CrashHandler() {}
/** 獲取CrashHandler實例 ,單例模式*/
public static CrashHandler getInstance() {
if (INSTANCE == null) {
INSTANCE = new CrashHandler();
}
return INSTANCE;
}
/**
* 初始化,注冊Context對象,
* 獲取系統默認的UncaughtException處理器,
* 設置該CrashHandler為程序的默認處理器
*
* @param ctx
*/
public void init(Context ctx) {
// mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 當UncaughtException發生時會轉入該函數來處理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用戶沒有處理則讓系統默認的異常處理器來處理
mDefaultHandler.uncaughtException(thread, ex);
} else { //如果自己處理了異常,則不會彈出錯誤對話框,則需要手動退出app
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
}
/**
* 自定義錯誤處理,收集錯誤信息
* 發送錯誤報告等操作均在此完成.
* 開發者可以根據自己的情況來自定義異常處理邏輯
* @return
* true代表處理該異常,不再向上拋異常,
* false代表不處理該異常(可以將該log信息存儲起來)然後交給上層(這裡就到了系統的異常處理)去處理,
* 簡單來說就是true不會彈出那個錯誤提示框,false就會彈出
*/
private boolean handleException(final Throwable ex) {
if (ex == null) {
return false;
}
// final String msg = ex.getLocalizedMessage();
final StackTraceElement[] stack = ex.getStackTrace();
final String message = ex.getMessage();
//使用Toast來顯示異常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
// Toast.makeText(mContext, "程序出錯啦:" + message, Toast.LENGTH_LONG).show();
// 可以只創建一個文件,以後全部往裡面append然後發送,這樣就會有重復的信息,個人不推薦
String fileName = "crash-" + System.currentTimeMillis() + ".log";
File file = new File(Environment.getExternalStorageDirectory(), fileName);
try {
FileOutputStream fos = new FileOutputStream(file,true);
fos.write(message.getBytes());
for (int i = 0; i < stack.length; i++) {
fos.write(stack[i].toString().getBytes());
}
fos.flush();
fos.close();
} catch (Exception e) {
}
Looper.loop();
}
}.start();
return false;
}
// TODO 使用HTTP Post 發送錯誤報告到服務器 這裡不再做詳細描述
// private void postReport(File file) {
// }
}
/**
* @author Tian
* 在Application中統一捕獲異常,保存到文件中下次再打開時上傳
*/
public class CrashHandler implements UncaughtExceptionHandler {
/** 是否開啟日志輸出,在Debug狀態下開啟,
* 在Release狀態下關閉以提示程序性能
* */
public static final boolean DEBUG = true;
/** 系統默認的UncaughtException處理類 */
private Thread.UncaughtExceptionHandler mDefaultHandler;
/** CrashHandler實例 */
private static CrashHandler INSTANCE;
/** 程序的Context對象 */
// private Context mContext;
/** 保證只有一個CrashHandler實例 */
private CrashHandler() {}
/** 獲取CrashHandler實例 ,單例模式*/
public static CrashHandler getInstance() {
if (INSTANCE == null) {
INSTANCE = new CrashHandler();
}
return INSTANCE;
}
/**
* 初始化,注冊Context對象,
* 獲取系統默認的UncaughtException處理器,
* 設置該CrashHandler為程序的默認處理器
*
* @param ctx
*/
public void init(Context ctx) {
// mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 當UncaughtException發生時會轉入該函數來處理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用戶沒有處理則讓系統默認的異常處理器來處理
mDefaultHandler.uncaughtException(thread, ex);
} else { //如果自己處理了異常,則不會彈出錯誤對話框,則需要手動退出app
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
}
/**
* 自定義錯誤處理,收集錯誤信息
* 發送錯誤報告等操作均在此完成.
* 開發者可以根據自己的情況來自定義異常處理邏輯
* @return
* true代表處理該異常,不再向上拋異常,
* false代表不處理該異常(可以將該log信息存儲起來)然後交給上層(這裡就到了系統的異常處理)去處理,
* 簡單來說就是true不會彈出那個錯誤提示框,false就會彈出
*/
private boolean handleException(final Throwable ex) {
if (ex == null) {
return false;
}
// final String msg = ex.getLocalizedMessage();
final StackTraceElement[] stack = ex.getStackTrace();
final String message = ex.getMessage();
//使用Toast來顯示異常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
// Toast.makeText(mContext, "程序出錯啦:" + message, Toast.LENGTH_LONG).show();
// 可以只創建一個文件,以後全部往裡面append然後發送,這樣就會有重復的信息,個人不推薦
String fileName = "crash-" + System.currentTimeMillis() + ".log";
File file = new File(Environment.getExternalStorageDirectory(), fileName);
try {
FileOutputStream fos = new FileOutputStream(file,true);
fos.write(message.getBytes());
for (int i = 0; i < stack.length; i++) {
fos.write(stack[i].toString().getBytes());
}
fos.flush();
fos.close();
} catch (Exception e) {
}
Looper.loop();
}
}.start();
return false;
}
// TODO 使用HTTP Post 發送錯誤報告到服務器 這裡不再做詳細描述
// private void postReport(File file) {
// }
}
項目地址:RingProgressBar簡介:一個簡單實現的自定義圓環進度條,可使用於文件的上傳下載圖片加載等地方.A material design circle th
本文代碼以MTK平台Android 4.4為分析對象,與Google原生AOSP有些許差異,請讀者知悉。 本文主要介紹MTK Android開機時,SIM卡的Fram
混淆簡單配置build.gradle的android節點下添加:buildTypes { release { minifyEnable
效果演示需求和技術分析RecyclerView Item拖拽排序::長按RecyclerView的Item或者觸摸Item的某個按鈕。 RecyclerView Item