全局捕获异常

来源:互联网 发布:天天回程车软件 编辑:程序博客网 时间:2024/06/01 10:28

在我们的Android应用开发中 经常出现一些bug 这样在用户体验的过程中 就会产生不好的回应 所以项目中我们实现全局捕获异常 这样 当程序崩溃时 会将报错的信息保存上传到服务器 由服务器解决 客户端这面会土司提示我们 程序遇到错误 即将退出 比崩了温柔多了 所以现在都是提高用户体验 下面我们提供全局捕获异常的代码 首先我们写一个本身就会报错的例子

import android.app.Activity;import android.os.Bundle;public class MainActivity extends Activity {     private String s;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        System.out.println(s.equals("any string"));    }}

不用说大家都知道 这个代码运行肯定会报空指针异常 因为找不到s这个对象 这个时候程序就崩了 如何才能不如此粗暴呢 看下面的代码

import java.io.File;  import java.io.FileOutputStream;  import java.io.PrintWriter;  import java.io.StringWriter;  import java.io.Writer;  import java.lang.Thread.UncaughtExceptionHandler;  import java.lang.reflect.Field;  import java.text.DateFormat;  import java.text.SimpleDateFormat;  import java.util.Date;  import java.util.HashMap;  import java.util.Map;  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.widget.Toast;  /** * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告. *  * @author user *  */  public class CrashHandler implements UncaughtExceptionHandler {     public static final String TAG = "CrashHandler";     //系统默认的UncaughtException处理类      private Thread.UncaughtExceptionHandler mDefaultHandler;     //CrashHandler实例     private static CrashHandler INSTANCE = new CrashHandler();     //程序的Context对象     private Context mContext;     //用来存储设备信息和异常信息     private Map<String, String> infos = new HashMap<String, String>();     //用于格式化日期,作为日志文件名的一部分     private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");     /** 保证只有一个CrashHandler实例 */     private CrashHandler() {     }     /** 获取CrashHandler实例 ,单例模式 */     public static CrashHandler getInstance() {         return INSTANCE;     }     /**     * 初始化     *      * @param context     */     public void init(Context context) {         mContext = context;         //获取系统默认的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);             }             //退出程序             android.os.Process.killProcess(android.os.Process.myPid());             System.exit(1);         }     }     /**     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.     *      * @param ex     * @return true:如果处理了该异常信息;否则返回false.     */     private boolean handleException(Throwable ex) {         if (ex == null) {             return false;         }         //使用Toast来显示异常信息         new Thread() {             @Override             public void run() {                 Looper.prepare();                 Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show();                 Looper.loop();             }         }.start();         //收集设备参数信息          collectDeviceInfo(mContext);         //保存日志文件          saveCrashInfo2File(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 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;     }  }  

上面这个代码就是全局捕获异常 当程序发生错误的时候 会将程序托管 并将报错的信息保存到文件 上传到服务 所以这个时候我们还需要写入SD卡的权限

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

我们还需要在我们的application中初始化我们的CrashHandler 下面看一下我们的代码

import android.app.Application;public class CrashApplication extends Application {     @Override          public void onCreate() {              super.onCreate();              CrashHandler crashHandler = CrashHandler.getInstance();              crashHandler.init(getApplicationContext());          }  }

所有的在application中初始化的内容都要在清单文件的application标签中配置

<application        android:name="com.example.view.CrashApplication"        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application>

这样就温柔多了 程序会提醒我们遇到错误 即将退出 不会崩溃

0 0