android艺术开发探索之 CrashHandler(全局捕获异常)和应用方法数越界

CrashHandler(全局捕获异常)和应用方法数越界

题外话,虽然我已经干了2年了,但是确实很少用到这个类,个人觉得一个好的app应该有这个一个全局捕获的机制,因为 毕竟任何一个用户都不想看到那个程序异常退出的框,为了用户体验,个人觉得美工应该给程序做个漂亮的框提升体验,这个框就是平时有时候程序出问题了,会弹出一个发送报告的框,就是那一个,虽然自己写这个全局捕获异常的类很容易 第三方的有可能有广告啥的,但咋毕竟不是大神,可以用第三方腾讯的Bugly,自己写的话就如下,回到正题@_@.、

  package com.robot.zhangyun.deme.md;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.os.Build;
  import android.os.Environment;
  import android.os.Looper;
  import android.support.v7.app.AlertDialog;
  import android.util.Log;
  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.text.SimpleDateFormat;
  import java.util.Date;
  /**
   * Created by zhangyun on 2016/8/10.
   */
  public class ZyCrashHandler implements UncaughtExceptionHandler {
      private static final String TAG="ZyCrashHandler";
      private static final Boolean DEBUG=true;
      private static final String PATH=    Environment.getExternalStorageDirectory().getPath()+"/TheOne/log/";
      private static final String FILE_NAME="crash";
      private static final String FILE_NAME_SUFFIX=".trace";

      private static ZyCrashHandler sInstance=new ZyCrashHandler();
      private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
      private Context mContext;
      ZyCrashHandler(){
      }
      public static ZyCrashHandler getsInstance(){
          return sInstance;
      }
      public void init(Context context){
          mDefaultCrashHandler=Thread.getDefaultUncaughtExceptionHandler();
          Thread.setDefaultUncaughtExceptionHandler(this);
          mContext=context.getApplicationContext();

      }
      /**
       *程序崩溃时会调用此方法
       * @param thread 出现未捕获异常的线程
       * @param throwable 未捕获的异常
       */
      @Override
      public void uncaughtException(Thread thread, Throwable throwable) {
          try {
              dumpExceptionToSDCard(throwable);
              //上传sd卡上的异常信息文件到服务器,这样开发人员就可以查看了
              //uploadExceptionToServer();
              new Thread() {
                  @Override
                  public void run() {
                      Looper.prepare();
                      new AlertDialog.Builder(mContext).setTitle("提示").setCancelable(false)
                              .setMessage("程序崩溃了...").setNeutralButton("我知道了", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              System.exit(0);
                          }
                      })
                              .create().show();
                      Looper.loop();
                  }
              }.start();

          }catch (IOException e){
              e.printStackTrace();
          }


      }
      /**
       * 导出异常信息和手机应用信息到sd卡
       * @param throwable
       * @throws IOException
       */
      private void dumpExceptionToSDCard(Throwable throwable) throws IOException{
          //Environment.MEDIA_MOUNTED存储媒体已经挂载,并且挂载点可读/写
          if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
              if(DEBUG){
                  Log.w(TAG,"SD卡不可用");
                  return;

              }
          }
          File dir=new File(PATH);
          if(!dir.exists()){
              dir.mkdirs();
          }
          long current=System.currentTimeMillis();
          String time=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current));
          File file=new File(PATH+FILE_NAME+time+FILE_NAME_SUFFIX);
          try{
              PrintWriter pw=new PrintWriter(new BufferedWriter(new FileWriter(file)));
              pw.println(time);
              dumpPhoneInfo(pw);
              pw.println();
              throwable.printStackTrace(pw);
              pw.close();
          }catch (Exception E){
              Log.e(TAG,"存储异常信息失败");
          }

      }
      private void dumpPhoneInfo(PrintWriter pw)throws PackageManager.NameNotFoundException{
          PackageManager pm=mContext.getPackageManager();
          PackageInfo pi=pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES);
          pw.print("App Version: ");
          pw.print(pi.versionName);
          pw.print('_');
          pw.print(pi.versionCode);

          //android版本号
          pw.print("OS Version: ");
          pw.print(Build.VERSION.RELEASE);
          pw.print('_');
          pw.print(Build.VERSION.SDK_INT);

          //手机制造商
          pw.print("Vendor: ");
          pw.println(Build.MANUFACTURER);

          //手机型号
          pw.print("Model: ");
          pw.println(Build.MODEL);

          //cpu架构
          pw.print("CPU ABI: ");
          pw.print(Build.CPU_ABI);
      }
  }
package com.robot.zhangyun.deme.md;

import android.app.Application;

/**
 * Created by zhangyun on 2016/8/10.
 */
public class ZyApplication extends Application {
    private static ZyApplication sInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance=this;
        ZyCrashHandler zyapplication=ZyCrashHandler.getsInstance();
        zyapplication.init(this);
    }
    public static ZyApplication getsInstance(){
        return sInstance;
    }
}
  1. 为何方法数未超过65536但是在低版本手机上安装异常?
    dexopt在应用安装时被系统用来优化dex文件,dexopt采用固定大小的缓冲区LinearAlloc存储应用中的所有方法的信息,虽然在新版本手机上这个缓冲区的大小有8MB或者16MB,但在2.x系列的手机上这个缓冲区大小为5MB,因此在低版本上时dexopt就会报错,导致安装应用失败。

  2. 当整个应用的方法数超过65536越界抛出异常的时候怎么办或者说当方法数未超过65536但是在低版本手机上安装异
    常终止怎么办?

    2.1 删除无用的代码和第三方库,使用multidex方案将dex文件拆分成多个dex来避免单个dex文件方法数越界。android5 .0以前需要引入android sdk目录下的extras/android/support/multidex/library/libs/android-support-multidex.jar,android5.0以后默认支持了multidex.

    2.1.1 使用android sdk Build Tools 21.1及以上版本,

    2.1.2 修改app下的build.gradle 添加 multiDexEnable true配置,

    2.1.3 添加依赖 compile ‘com.android.support:multidex:1.0.0’,

    2.1.4 将application的name换成”android.support.multidex.MultiDexApplication”或者写个类继承application,然后在attachBaseContext方法中调用 Multidex.install(this);

    2.2 删除无用的代码和第三方库,使用动态加载.直接加载一个dex形式文件,将部分代码打包到一个单独的dex
    (或dex格式的jar,apk),在程序 需要时动态加载dex中的类。具体查看https://github.com/singwhatiwanna/dyna
    mic-load-apk,平时不怎么用到,就懒得写了,这里不解释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值