標籤:android 運行時異常捕捉
在寫Android程式時,經常碰到在模擬器和調試器中無法捕捉的exception。有時自己運行好好的程式到了其他機器上就出現了問題。雖然Google Play有錯誤堆棧上傳功能,但是沒有辦法把整個啟動並執行過程記錄下來。為此我寫了一個LogDog類來試圖解決這個問題。
import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;import java.lang.Thread.UncaughtExceptionHandler;import java.sql.Date;import java.text.SimpleDateFormat;import java.util.HashSet;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.os.Build;import android.os.Environment;import android.os.Looper;//import android.util.Log;import android.util.Log;public class LogDog implements UncaughtExceptionHandler {public static String TAG = "LogDog";private static HashSet_tags = new HashSet();private static boolean_debug = false;static {// add tags to be captured_tags.add(PDFMaster.TAG);_tags.add(RecentlyUsedActivity.TAG);_tags.add(DB.TAG);}public static LogDog instance() {return _instance;}public static void i(String tag, String message) {if(_debug) {Log.i(tag, message);return;}PrintWriter writer = _instance.getWriter();if(writer != null && _tags.contains(tag)) {_instance._writer.println("i:" + tag + ":" + message);}}public static void e(String tag, String message) {if(_debug) {Log.i(tag, message);return;}PrintWriter writer = _instance.getWriter();if(writer != null && _tags.contains(tag)) {_instance._writer.println("e" + tag + ":" + message);}}public static void w(String tag, String message) {if(_debug) {Log.i(tag, message);return;}PrintWriter writer = _instance.getWriter();if(writer != null && _tags.contains(tag)) {_instance._writer.println("w" + tag + ":" + message);}}public void init(Context context) {_context = context;_fileName = _context.getString(R.string.app_name) + ".log";_defaultHandler = Thread.getDefaultUncaughtExceptionHandler();Thread.setDefaultUncaughtExceptionHandler(this);}public void close() {if(_writer != null) {_writer.close();_writer = null;}}// privateprivate static LogDog_instance = new LogDog();private static final String PATH =Environment.getExternalStorageDirectory().getPath() + "/log";private Context_context;private String_fileName;private Thread.UncaughtExceptionHandler_defaultHandler;private PrintWriter_writer = null;private LogDog() {}private PrintWriter getWriter() {if(_writer != null)return _writer;// check if we have SD cardif (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//Log.w(TAG, "sdcard unmounted,skip dump exception");return null;}File dir = new File(PATH);if (!dir.exists()) {dir.mkdirs();}File file = new File(PATH + "/" + _fileName);try {_writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));} catch (IOException e) {//Log.e(TAG, "Failed to open " + PATH + "/" + FILE_NAME);_writer = null;}return _writer;}@Overridepublic void uncaughtException(Thread thread, Throwable ex) {// first display a toast messagenew Thread() {@Overridepublic void run() {Looper.prepare();PDFMarkerApp.instance().showToast("Sorry for the trouble, dumping uncaught exeption to SD card");}}.start();try {dump(ex);} catch (Exception e) {//Log.e(TAG, "Failed to dump because " + e.getMessage());e.printStackTrace();}if (_defaultHandler != null) { _defaultHandler.uncaughtException(thread, ex); } else {// sleep so the toast can have time to displaytry {Thread.sleep(3000);} catch (InterruptedException e) {}android.os.Process.killProcess(android.os.Process.myPid()); }}private void dump(Throwable ex) throws IOException, NameNotFoundException {PrintWriter writer = _instance.getWriter();if(writer == null)return;long current = System.currentTimeMillis();String time = new SimpleDateFormat("yyyyMMdd.HHmmss").format(new Date(current));_writer.println(time);PackageManager pm = _context.getPackageManager();PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), PackageManager.GET_ACTIVITIES);_writer.print("App Version: ");_writer.print(pi.versionName);_writer.print(‘_‘);_writer.println(pi.versionCode); _writer.print("OS Version: ");_writer.print(Build.VERSION.RELEASE);_writer.print("_");_writer.println(Build.VERSION.SDK_INT);_writer.print("Vendor: ");_writer.println(Build.MANUFACTURER);_writer.print("Model: ");_writer.println(Build.MODEL);_writer.print("CPU ABI: ");_writer.println(Build.CPU_ABI);_writer.println();ex.printStackTrace(_writer);close();File file = new File(PATH + "/" + _fileName);File file2 = new File(PATH + "/" + _fileName + "." + time + ".txt");file.renameTo(file2);}}
在使用時所有的日誌就全記錄在一個檔案中,直到最後的異常。每次異常都會單獨被記錄在一個檔案中,連帶所有需要知道的資訊。要是正常運行,這個檔案下次就被覆蓋,不會造成空間問題。要是調試,只要把_debug改一下,所有日誌就在LogCat中顯示出來,非常方便。
Android 之 LogDog