• 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) {
                            }
                        }
                    }
                }
        }

    }





  • 相关阅读:
    2020暑假项目-车辆派遣管理系统需求
    2020暑假项目-车辆派遣管理系统
    关于页面刷新或者调用方法事获取不到元素信息或者出现缺少对象错误的换位思考setTimeout的使用
    JSON 传值 textarea中虚拟换行功能
    我的MYSQL学习心得(十) 自定义存储过程和函数
    我的MYSQL学习心得(九) 索引
    我的MYSQL学习心得(八) 插入 更新 删除
    我的MYSQL学习心得(六) 函数
    我的MYSQL学习心得(七) 查询
    我的MYSQL学习心得(四) 数据类型
  • 原文地址:https://www.cnblogs.com/ut2016-progam/p/5584929.html
Copyright © 2020-2023  润新知