zoukankan      html  css  js  c++  java
  • Android应用崩溃后异常捕获并重启并写入日志

    在Android开发时,有时会因为一些异常导致应用报错,偶尔会因为错误 而崩溃,导致用户体验下降,为了解决这问题,我们就要对这样的异常处理:
    代码如下:
    CrashHandler.java
    import android.content.Context;
    import android.content.Intent;
    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;

    import com......activity.SplashActivity;
    import com.......util.ImgClipUtil;

    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;

    /**
     * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
     *
     * @author user
     *
     */
    public class CrashHandler implements UncaughtExceptionHandler {

        public static final String TAG = "CrashHandler";

        // CrashHandler 实例
        private static CrashHandler INSTANCE = new CrashHandler();

        // 程序的 Context 对象
        private Context mContext;

        // 系统默认的 UncaughtException 处理类
        private Thread.UncaughtExceptionHandler mDefaultHandler;

        // 用来存储设备信息和异常信息
        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) {
            //删除裁剪留在缓存的照片
            ImgClipUtil.deleteAllFiles(ImgClipUtil.imgClipPath);
            if (!handleException(ex) && mDefaultHandler != null) {
                // 如果用户没有处理则让系统默认的异常处理器来处理
                mDefaultHandler.uncaughtException(thread, ex);
            } else {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Log.e(TAG, "error : ", e);
                }

                // 退出程序,注释下面的重启启动程序代码
    //            android.os.Process.killProcess(android.os.Process.myPid());
    //            System.exit(1);
                // 重新启动程序,注释上面的退出程序
                Intent intent = new Intent();
                intent.setClass(mContext, SplashActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mContext.startActivity(intent);
                android.os.Process.killProcess(android.os.Process.myPid());
            }
        }

        /**
         * 自定义错误处理,收集错误信息,发送错误报告等操作均在此完成
         *
         * @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 + " ");
            }

            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/tpages/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;
        }
    }

    MyApplication.java
    /**
     * Created by IT01 on 2015/10/28 0028.
     */
    public class MyApplication extends Application {
      /*  private RefWatcher mRefwatcher;

        public static RefWatcher getRefWatcher(Context context) {
            MyApplication application = (MyApplication) context.getApplicationContext();
            return application.mRefwatcher;
        }*/

        @Override
        public void onCreate() {
            super.onCreate();
    //        mRefwatcher = LeakCanary.install(this);
            //cookie策略 让OkHttp接受所有的cookie
    /*        CookieManager cookieManager = new CookieManager();
            OkHttp.setCookie(cookieManager);*/

            if (Constants.Config.DEVELOPER_MODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyDialog().build());
                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build());
            }
            if (android.os.Build.VERSION.SDK_INT > 9) {
                StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
                StrictMode.setThreadPolicy(policy);
            }

            CrashHandler crashHandler = CrashHandler.getInstance();
    //        crashHandler.init(getApplicationContext());
      
        }
      
    }


    ImgClipUtil.java
    import android.graphics.Bitmap;
    import android.graphics.Matrix;

    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
     * Created by IT01 on 2015/12/14 0014.
     */
    public class ImgClipUtil {
        public static boolean isClip(Bitmap bit){
            int w = bit.getWidth(); // 得到图片的宽,高
            int h = bit.getHeight();
            if((w==h)&&w<1080)return false;
            return true;
        }
        public static int getSquareSize(Bitmap bit){
            int w = bit.getWidth(); // 得到图片的宽,高
            int h = bit.getHeight();
            int wh = w > h ? h : w;// 裁切后所取的正方形区域边长
            return wh > 1080 ? 1080 : wh;
        }

        public static Bitmap ScaleBitmap(Bitmap bitmap, int edgeLength)
        {

            if(null == bitmap || edgeLength <= 0)
            {
                return null ;
            }

            Bitmap result = bitmap;
            int widthOrg = bitmap.getWidth();
            int heightOrg = bitmap.getHeight();

            if(widthOrg >= edgeLength && heightOrg >= edgeLength)
            {
                //压缩到一个最小长度是edgeLength的bitmap
                int longerEdge = (int)(edgeLength * Math.max(widthOrg, heightOrg) / Math.min(widthOrg, heightOrg));
                int scaledWidth = widthOrg > heightOrg ? longerEdge : edgeLength;
                int scaledHeight = widthOrg > heightOrg ? edgeLength : longerEdge;
                Bitmap scaledBitmap;
                try{
                    scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);
                }
                catch(Exception e){
                    return null;
                }

                //从图中截取正中间的正方形部分。
                int xTopLeft = (scaledWidth - edgeLength) / 2;
                int yTopLeft = (scaledHeight - edgeLength) / 2;

                try{
                    result = Bitmap.createBitmap(scaledBitmap, xTopLeft, yTopLeft, edgeLength, edgeLength);
                    scaledBitmap.recycle();
                }
                catch(Exception e){
                    return null;
                }
            }

            return result;
        }

        /**
         * 保存文件
         * @param bm
         * @param fileName
         * @throws IOException
         */
        public static void saveFile(Bitmap bm, String fileName) throws IOException {
            String path =imgClipPath+"/"; //"/sdcard/revoeye/";
            File dirFile = new File(path);
            if(!dirFile.exists()){
                dirFile.mkdir();
            }
            File myCaptureFile = new File(path + fileName);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
            bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
            bos.close();
        }

        // 旋转图片
        /**
         * 将图片按照某个角度进行旋转
         *
         * @param bm
         *            需要旋转的图片
         * @param degree
         *            旋转角度
         * @return 旋转后的图片
         */
        public Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
            Bitmap returnBm = null;
            // 根据旋转角度,生成旋转矩阵
            Matrix matrix = new Matrix();
    //        matrix.postRotate(degree);
            matrix.setRotate(degree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
            try {
                // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
                returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
            }
            if (returnBm == null) {
                returnBm = bm;
            }
            if (bm != returnBm) {
                bm.recycle();
            }
            return returnBm;
        }

        public static File imgClipPath =new File(Utils.getPicPath() + "img");
        public static void deleteAllFiles(File root) {

            File files[] = root.listFiles();
            if (files != null)
                for (File f : files) {
                    if (f.isDirectory()) { // 判断是否为文件夹
                        deleteAllFiles(f);
                        try {
                            f.delete();
                        } catch (Exception e) {
                        }
                    } else {
                        if (f.exists()) { // 判断是否存在
                            deleteAllFiles(f);
                            try {
                                f.delete();
                            } catch (Exception e) {
                            }
                        }
                    }
                }
        }

    }





  • 相关阅读:
    Educational Codeforces Round 74 (Rated for Div. 2)
    Codeforces Round #591 (Div. 2, based on Technocup 2020 Elimination Round 1) 题解
    D
    Card Hand Sorting 二进制枚举暴力
    20172018-acmicpc-southeastern-european-regional-programming-contest-seerc-2017-en A
    Round #590 (Div. 3)
    A
    P2634 [国家集训队]聪聪可可
    HDU-4807-Lunch Time(二分+费用流,思维)
    易错分析
  • 原文地址:https://www.cnblogs.com/ut2016-progam/p/5584929.html
Copyright © 2011-2022 走看看