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

来源:互联网 发布:视频制作软件免费下载 编辑:程序博客网 时间:2024/06/12 01:43

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,平时不怎么用到,就懒得写了,这里不解释。

1 0
原创粉丝点击