Android全域性異常捕獲,解決日誌列印三次的BUG
阿新 • • 發佈:2019-02-03
最近寫的專案需要自己寫全域性的異常捕捉,所以百度了很多解決方案,發現出現各種問題,好不容易找到一些比較靠譜的方案,但是卻發現出現了一個讓我無語的問題——日誌列印輸出三次。於是又開始去尋找答案,發現並沒有相關的解決。好嘛,看來還是要自己搞了。
發生該現象的基本原因就是: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菜鳥一枚,並非大牛,可能部分程式碼不盡如人意,希望各位大大可以予以指出,我會虛心接受並積極改正,謝謝大家!