国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

在Android中自定義捕獲Application全局異常,可以替換掉系統(tǒng)的強(qiáng)制退出對(duì)話框

2019-11-09 18:28:51
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

       大家都知道,現(xiàn)在安裝 Android 系統(tǒng)的手機(jī)和設(shè)備千差萬(wàn)別,在模擬器上運(yùn)行良好的程序安裝到某款手機(jī)上說(shuō)不定就出現(xiàn)崩潰

的現(xiàn)象,開發(fā)者個(gè)人不可能購(gòu)買所有設(shè)備逐個(gè)調(diào)試,所以在程序發(fā)布出去之后,如果出現(xiàn)了崩潰現(xiàn)象,開發(fā)者應(yīng)該及時(shí)獲取在該設(shè)

備上導(dǎo)致崩潰的信息,這對(duì)于下一個(gè)版本的 BUG 修復(fù)幫助極大,所以今天就來(lái)介紹一下如何在程序崩潰的情況下收集相關(guān)的設(shè)備

參數(shù)信息和具體的異常信息,并發(fā)送這些信息到服務(wù)器供開發(fā)者分析和調(diào)試程序。

       遇到軟件沒有捕獲的異常之后,系統(tǒng)會(huì)彈出這個(gè)默認(rèn)的強(qiáng)制關(guān)閉對(duì)話框。

       我們當(dāng)然不希望用戶看到這種現(xiàn)象,簡(jiǎn)直是對(duì)用戶心靈上的打擊,而且對(duì)我們的 BUG 的修復(fù)也是毫無(wú)幫助的。我們需要的是軟

件有一個(gè)全局的異常捕獲器,當(dāng)出現(xiàn)一個(gè)我們沒有發(fā)現(xiàn)的異常時(shí),捕獲這個(gè)異常,并且將異常信息記錄下來(lái),上傳到服務(wù)器公開發(fā)

這分出現(xiàn)異常的具體原因。

       接下來(lái)我們就來(lái)實(shí)現(xiàn)這一機(jī)制,不過(guò)首先我們還是來(lái)了解以下兩個(gè)類:android.app.application

java.lang.Thread.UncaughtExceptionHandler。

    1、Application:用來(lái)管理應(yīng)用程序的全局狀態(tài)。在應(yīng)用程序啟動(dòng)時(shí) Application 會(huì)首先創(chuàng)建,然后才會(huì)根據(jù)情況(Intent)來(lái)啟動(dòng)

相應(yīng)的Activity 和 Service。本示例中將在自定義加強(qiáng)版的 Application 中注冊(cè)未捕獲異常處理器。

    2、Thread.UncaughtExceptionHandler:線程未捕獲異常處理器,用來(lái)處理未捕獲異常。如果程序出現(xiàn)了未捕獲異常,默認(rèn)會(huì)彈

出系統(tǒng)中強(qiáng)制關(guān)閉對(duì)話框。我們需要實(shí)現(xiàn)此接口,并注冊(cè)為程序中默認(rèn)未捕獲異常處理。這樣當(dāng)未捕獲異常發(fā)生時(shí),就可以做一些

個(gè)性化的異常處理操作。

 (1)新建java文件,CrashHandler.java 實(shí)現(xiàn)了 Thread.UncaughtExceptionHandler,使我們用來(lái)處理未捕獲異常的主要成員,代

碼如下:

public class CrashHandler implements UncaughtExceptionHandler {        public static final String TAG = "CrashHandler";        // CrashHandler 實(shí)例      PRivate static CrashHandler INSTANCE = new CrashHandler();        // 程序的 Context 對(duì)象      private Context mContext;        // 系統(tǒng)默認(rèn)的 UncaughtException 處理類      private Thread.UncaughtExceptionHandler mDefaultHandler;        // 用來(lái)存儲(chǔ)設(shè)備信息和異常信息      private Map<String, String> infos = new HashMap<String, String>();        // 用于格式化日期,作為日志文件名的一部分      private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");          /** 保證只有一個(gè) CrashHandler 實(shí)例 */      private CrashHandler() {      }        /** 獲取 CrashHandler 實(shí)例 ,單例模式 */      public static CrashHandler getInstance() {          return INSTANCE;      }        /**      * 初始化      *      * @param context      */      public void init(Context context) {          mContext = context;                // 獲取系統(tǒng)默認(rèn)的 UncaughtException 處理器          mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();                // 設(shè)置該 CrashHandler 為程序的默認(rèn)處理器          Thread.setDefaultUncaughtExceptionHandler(this);      }        /**      * 當(dāng) UncaughtException 發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來(lái)處理      */      @Override      public void uncaughtException(Thread thread, Throwable ex) {          if (!handleException(ex) && mDefaultHandler != null) {              // 如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來(lái)處理              mDefaultHandler.uncaughtException(thread, ex);          } else {              try {                  Thread.sleep(3000);              } catch (InterruptedException e) {                  Log.e(TAG, "error : ", e);              }                // 退出程序,注釋下面的重啟啟動(dòng)程序代碼            android.os.Process.killProcess(android.os.Process.myPid());              System.exit(1);                  // 重新啟動(dòng)程序,注釋上面的退出程序           Intent intent = new Intent();           intent.setClass(mContext,MainActivity.class);           intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK);           mContext.startActivity(intent);           android.os.Process.killProcess(android.os.Process.myPid());        }      }        /**      * 自定義錯(cuò)誤處理,收集錯(cuò)誤信息,發(fā)送錯(cuò)誤報(bào)告等操作均在此完成      *       * @param ex      * @return true:如果處理了該異常信息;否則返回 false      */      private boolean handleException(Throwable ex) {          if (ex == null) {              return false;          }            // 使用 Toast 來(lái)顯示異常信息          new Thread() {              @Override              public void run() {                  Looper.prepare();                  Toast.makeText(mContext, "很抱歉,程序出現(xiàn)異常,即將退出。", Toast.LENGTH_LONG).show();                  Looper.loop();              }          }.start();            // 收集設(shè)備參數(shù)信息          collectDeviceInfo(mContext);          // 保存日志文件          saveCrashInfo2File(ex);          return true;      }        /**      * 收集設(shè)備參數(shù)信息      * @param ctx      */      public void collectDeviceInfo(Context ctx) {          try {              PackageManager pm = ctx.getPackageManager();              PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);                if (pi != null) {                  String versionName = pi.versionName == null ? "null" : pi.versionName;                  String versionCode = pi.versionCode + "";                  infos.put("versionName", versionName);                  infos.put("versionCode", versionCode);              }          } catch (NameNotFoundException e) {              Log.e(TAG, "an error occured when collect package info", e);          }            Field[] fields = Build.class.getDeclaredFields();          for (Field field : fields) {              try {                  field.setaccessible(true);                  infos.put(field.getName(), field.get(null).toString());                  Log.d(TAG, field.getName() + " : " + field.get(null));              } catch (Exception e) {                  Log.e(TAG, "an error occured when collect crash info", e);              }          }      }        /**      * 保存錯(cuò)誤信息到文件中     *      * @param ex      * @return  返回文件名稱,便于將文件傳送到服務(wù)器      */      private String saveCrashInfo2File(Throwable ex) {          StringBuffer sb = new StringBuffer();          for (Map.Entry<String, String> entry : infos.entrySet()) {              String key = entry.getKey();              String value = entry.getValue();              sb.append(key + "=" + value + "/n");          }            Writer writer = new StringWriter();          PrintWriter printWriter = new PrintWriter(writer);          ex.printStackTrace(printWriter);          Throwable cause = ex.getCause();          while (cause != null) {              cause.printStackTrace(printWriter);              cause = cause.getCause();          }          printWriter.close();            String result = writer.toString();          sb.append(result);          try {              long timestamp = System.currentTimeMillis();              String time = formatter.format(new Date());              String fileName = "crash-" + time + "-" + timestamp + ".log";                            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                  String path = "/sdcard/crash/";                  File dir = new File(path);                  if (!dir.exists()) {                      dir.mkdirs();                  }                  FileOutputStream fos = new FileOutputStream(path + fileName);                  fos.write(sb.toString().getBytes());                  fos.close();              }                return fileName;          } catch (Exception e) {              Log.e(TAG, "an error occured while writing file...", e);          }            return null;      }  }  (2)完成這個(gè) CrashHandler 后,我們需要在一個(gè) Application 環(huán)境中讓其運(yùn)行,為此,我們繼承 android.app.Application,添加自己的代碼,CrashApplication.java代碼如下:package com.scott.crash;    import android.app.Application;    public class CrashApplication extends Application {            @Override      public void onCreate() {          super.onCreate();          CrashHandler crashHandler = CrashHandler.getInstance();          crashHandler.init(getApplicationContext());      }    }  

   

(3)因?yàn)槲覀兩厦娴?CrashHandler 中,遇到異常后要保存設(shè)備參數(shù)和具體異常信息到 SDCARD,所以我們需要在

 AndroidManifest.xml 中加入讀寫 SDCARD 權(quán)限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 山阳县| 定州市| 昌平区| 米脂县| 胶南市| 潜江市| 台山市| 元氏县| 宝坻区| 泰和县| 贵定县| 南澳县| 万盛区| 曲靖市| 尼木县| 龙泉市| 利川市| 中西区| 宁乡县| 高州市| 天全县| 昭苏县| 贵德县| 黑水县| 博白县| 登封市| 安宁市| 民权县| 福鼎市| 香港 | 扶绥县| 鹰潭市| 郎溪县| 宁夏| 宁都县| 光山县| 黑山县| 吉木萨尔县| 云梦县| 开平市| 马鞍山市|