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

首頁 > 系統 > Android > 正文

android 捕捉異常并上傳至服務器的簡單實現

2019-10-23 18:31:12
字體:
來源:轉載
供稿:網友

在項目中,我們的應用經常會遇到崩潰的情況,如果你的項目已經發送到了應用市場上,那么應用發生的崩潰開發人員是開不到的,所以我們要想辦法將異常信息傳到服務器上,便于開發人員查看并作出修改。Google考慮到這一點,也提供了Thread.UncaughtExceptionHandler接口來實現這一問題。

創建Crash異常捕獲很簡單,主要的步驟有:

1.創建BaseApplication繼承Application并實現Thread.UncaughtExceptionHandler

2.通過Thread.setDefaultUncaughtExceptionHandler(this)設置默認的異常捕獲

3.最后在manifests中注冊創建的BaseApplication

一、異常捕捉的簡單實用

public class BaseApplication extends Application implements Thread.UncaughtExceptionHandler {  @Override  public void onCreate() {    super.onCreate();    //設置異常捕獲    CrashHandler catchHandler = CrashHandler.getInstance();    catchHandler.init(this);  }}

二、CrashHandler(主要是實現uncaughtException方法)

public class CrashHandler implements UncaughtExceptionHandler {  public static final String TAG = "CrashHandler";  // 系統默認的UncaughtException處理類  private Thread.UncaughtExceptionHandler mDefaultHandler;  // CrashHandler實例  private static CrashHandler instance;  // 程序的Context對象  private Context mContext;  // 用來存儲設備信息和異常信息  private Map<String, String> infos = new HashMap<String, String>();  // 用于格式化日期,作為日志文件名的一部分  private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");  MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks = new MyActivityLifecycleCallbacks();  /** 保證只有一個CrashHandler實例 */  private CrashHandler() {  }  /** 獲取CrashHandler實例 ,單例模式 */  public static CrashHandler getInstance() {    if (instance == null)      instance = new CrashHandler();    return instance;  }  /**   * 初始化   */  public void init(SspApplication context) {    mContext = context;    context.registerActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks);    // 獲取系統默認的UncaughtException處理器    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();    // 設置該CrashHandler為程序的默認處理器    Thread.setDefaultUncaughtExceptionHandler(this);  }  /**   * 當UncaughtException發生時會轉入該函數來處理   */  @Override  public void uncaughtException(Thread thread, Throwable ex) {    if (!handleException(ex) && mDefaultHandler != null) {      // 如果用戶沒有處理則讓系統默認的異常處理器來處理      mDefaultHandler.uncaughtException(thread, ex);    } else {    //  try {    //    Thread.sleep(3000);    //  } catch (InterruptedException e) {    //    Log.e(TAG, "error : ", e);    //  }    // 注意Thread.sleep(3000)和 SystemClock.sleep(3000)的區別      SystemClock.sleep(3000);      // 退出程序      Log.i("=====killProcess======","=====killProcess======");      mMyActivityLifecycleCallbacks.removeAllActivities();      android/197887.html">android.os.Process.killProcess(android.os.Process.myPid());      System.exit(0);    }  }  /**   * 自定義錯誤處理,收集錯誤信息 發送錯誤報告等操作均在此完成.   *    * @param ex   * @return true:如果處理了該異常信息;否則返回false.   */  private boolean handleException(Throwable ex) {    Log.i("=====handleException======","=====handleException======");    if (ex == null) {      return false;    }    // 收集設備參數信息    collectDeviceInfo(mContext);    // 使用Toast來顯示異常信息    new Thread() {      @Override      public void run() {        Looper.prepare();        Toast.makeText(mContext, "哎呀,出問題了,我要暫時離開了", Toast.LENGTH_SHORT).show();        Looper.loop();      }    }.start();    // 保存日志文件    saveCatchInfo2File(ex);    return true;  }  /**   * 收集設備參數信息   *    * @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);      }    }  }  /**   * 保存錯誤信息到文件中   *    * @param ex   * @return 返回文件名稱,便于將文件傳送到服務器   */  private String saveCatchInfo2File(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());      SharedPreferences userInfo = mContext.getSharedPreferences(          Constants.USER_SETTING_INFOS, 0);      String loginName = userInfo.getString(Constants.USERNAME, "");      String fileName = "crash-" + time +"-"+loginName+ ".log";      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {        String path = "/mnt/sdcard/crash/";        File dir = new File(path);        if (!dir.exists()) {          dir.mkdirs();        }        FileOutputStream fos = new FileOutputStream(path + fileName);        fos.write(sb.toString().getBytes());        // 發送給開發人員        sendCrashLog2PM(path + fileName);        fos.close();      }      return fileName;    } catch (Exception e) {      Log.e(TAG, "an error occured while writing file...", e);    }    return null;  }  /**   * 將捕獲的導致崩潰的錯誤信息發送給開發人員   *    * 目前只將log日志保存在sdcard 和輸出到LogCat中,并未發送給后臺。   */  private void sendCrashLog2PM(final String fileName) {    if (!new File(fileName).exists()) {      Toast.makeText(mContext, "日志文件不存在!", Toast.LENGTH_SHORT).show();      return;    } else {        new Thread(new Runnable() {        @Override        public void run() {          Looper.prepare();          ArrayList<String> picList = new ArrayList<String>();          picList.add(fileName);          SendEventPic sFile = new SendEventPic(mContext);          UUIDGenerator generator = new UUIDGenerator();          String linkId = generator.generate().toString();          SharedPreferences userInfo = mContext.getSharedPreferences(              Constants.USER_SETTING_INFOS, 0);          String loginName = userInfo.getString(Constants.USERNAME, "");          String userId = userInfo.getString(Constants.USER_USERID_INFOS, "");          boolean isproblempic = sFile.isSendSuccess(picList, linkId,              "crash_tng", "crash_tng", loginName, userId);          Looper.loop();        }      }).start();    }    FileInputStream fis = null;    BufferedReader reader = null;    String s = null;    try {      fis = new FileInputStream(fileName);      reader = new BufferedReader(new InputStreamReader(fis, "GBK"));      while (true) {        s = reader.readLine();        if (s == null)          break;        // 由于目前尚未確定以何種方式發送,所以先打出log日志。        Log.i("info", s.toString());      }    } catch (FileNotFoundException e) {      e.printStackTrace();    } catch (IOException e) {      e.printStackTrace();    } finally { // 關閉流      try {        reader.close();        fis.close();      } catch (IOException e) {        e.printStackTrace();      }    }  }}

三、開發過程中遇到的坑

如果在activity創建的時候崩潰的話,系統有時候(目前不確定什么情況下會重啟)會重啟當前的activity,造成第二次的崩潰,如此循環……

所以,在應用崩潰時要完全退出應用。

public class MyActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {  private List<Activity> activities = new LinkedList<>();  public static int sAnimationId = 0;  @Override  public void onActivityCreated(Activity activity, Bundle savedInstanceState) {    addActivity(activity);  }  @Override  public void onActivityStarted(Activity activity) {  }  @Override  public void onActivityResumed(Activity activity) {  }  @Override  public void onActivityPaused(Activity activity) {  }  @Override  public void onActivityStopped(Activity activity) {  }  @Override  public void onActivitySaveInstanceState(Activity activity, Bundle outState) {  }  @Override  public void onActivityDestroyed(Activity activity) {    removeActivity(activity);  }  /**   * 添加Activity   */  public void addActivity(Activity activity) {    if (activities == null) {      activities = new LinkedList<>();    }    if (!activities.contains(activity)) {      activities.add(activity);// 把當前Activity添加到集合中    }  }  /**   * 移除Activity   */  public void removeActivity(Activity activity) {    if (activities.contains(activity)) {      activities.remove(activity);    }    if (activities.size() == 0) {      activities = null;    }  }  /**   * 銷毀所有activity   */  public void removeAllActivities() {    for (Activity activity : activities) {      if (null != activity) {        activity.finish();        activity.overridePendingTransition(0, sAnimationId);      }    }  }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 唐山市| 江山市| 城固县| 伊通| 泸水县| 修文县| 迁西县| 轮台县| 通江县| 安陆市| 柘荣县| 五指山市| 怀远县| 清远市| 汪清县| 内丘县| 安丘市| 白水县| 行唐县| 冕宁县| 若羌县| 茂名市| 江山市| 通州区| 托里县| 芦山县| 镇赉县| 岗巴县| 阳东县| 江北区| 孟连| 文昌市| 米脂县| 保德县| 宝丰县| 诸暨市| 四川省| 夏津县| 陆良县| 云安县| 肥城市|