android 快速开发三、 获取应用的crash信息

来源:互联网 发布:进口儿童安全座椅知乎 编辑:程序博客网 时间:2024/05/29 19:56

当用户发生了crash,开发者却无法得知程序为何crash,即便开发人员想去解决这个crash,但是由于无法知道用户当时crash信息,所以往往无能为力。android 提供了获取crash信息的方法。话不多说,直接上代码。

package com.example.wmk.utils;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Build;import com.lidroid.xutils.util.LogUtils;import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.PrintWriter;/** * Created by 老王 on 2016/12/2. */public class CrashHandler implements Thread.UncaughtExceptionHandler {    /**     * CrashHandler     */    private static CrashHandler CRASHHANDLER = null;    private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;    private Context mContext;    private static final String FILE_NAME = "crash";    private static final String FILE_NAME_TXT = ".txt";    /**     * Get Instance     *     * @return CrashHandler     */    public static CrashHandler getInstance() {        if (CRASHHANDLER == null) {            CRASHHANDLER = new CrashHandler();        }        return CRASHHANDLER;    }    private CrashHandler() {    }    public void init(Context context) {        mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();        Thread.setDefaultUncaughtExceptionHandler(this);        mContext = context.getApplicationContext();    }    @Override    public void uncaughtException(Thread thread, Throwable ex) {        //导出异常信息到SD卡中        dumpExceptionToSDCard(ex);        //这里可以上传异常信息到服务器,便于开发人员分析日志从而解决bug        uploadExceptionToServer();        ex.printStackTrace();        //如果系统提供了默认的异常处理器,则交给系统去结束程序,否则就由自己结束自己        if (mDefaultUncaughtExceptionHandler != null) {            mDefaultUncaughtExceptionHandler.uncaughtException(thread, ex);        } else {            ActivityManager.getInstance().appExceptionExit();        }    }    private void dumpExceptionToSDCard(Throwable ex) {        String time = TimeUtils.formatDate("yyyy-MM-dd HH:mm:ss");        //创建crash文件        File file = ProjectUtils.createFile(ProjectUtils.WMK_LOG + FILE_NAME + time + FILE_NAME_TXT);        try {            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));            pw.println(time);            dumpPhoneInfo(pw);            pw.println();            ex.printStackTrace(pw);            pw.close();        } catch (Exception e) {            LogUtils.e("dump crash info failed");        }    }    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.println(pi.versionCode);        //Android版本号        pw.print("OS Version: ");        pw.print(Build.VERSION.RELEASE);        pw.print("_");        pw.println(Build.VERSION.SDK_INT);        //手机制造商        pw.print("Vendor: ");        pw.println(Build.MANUFACTURER);        //手机型号        pw.print("Model: ");        pw.println(Build.MODEL);        //CPU架构        pw.print("CPU ABI:");        pw.println(Build.CPU_ABI);    }    private void uploadExceptionToServer() {        //TODO Upload Exception Message To your Web Server    }}

首先,封装了一个日期工具类,用于显示日期,代码如下:

package com.example.wmk.utils;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;/** * Created by 老王 on 2016/12/2. */public class TimeUtils {    /**     * 格式化当前日期     *     * @param rule 格式规则     * @return 格式化后的日期     */    public static String formatDate(String rule) {        return new SimpleDateFormat(rule, Locale.getDefault()).format(new Date());    }}

其次,用到了项目工具类中的创建文件的方法。

package com.example.wmk.utils;import android.os.Environment;import java.io.File;/** * Created by 老王 on 2016/12/1. */public class ProjectUtils {    /**     * 根目录     */    public static File ROOT_DIRECTORY = Environment.getExternalStorageDirectory();    /**     * 项目路径     */    public static final String PROJECT_PATH = ROOT_DIRECTORY.getAbsolutePath() + "/WMK/";    /**     * 数据库     */    public static final String WMK_DB = PROJECT_PATH + "DB/";    /**     * 图片     */    public static final String WMK_IMG = PROJECT_PATH + "IMG/";    /**     * Log     */    public static final String WMK_LOG = PROJECT_PATH + "LOG/";    /**     * sdCard     *     * @return If there is a SD card to return true, otherwise false     */    public static boolean existsSdCard() {        return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);    }    /**     * 创建文件     *     * @param s     * @return If you create a file successfully returned to the current file, otherwise     * Null     */    public static File createFile(String s) {        return new File(s);    }    /**     * 创建文件夹     *     * @param s     * @return If you create a folder successfully returned to the current folder, otherwise     * Null     */    public static File createFolder(String s) {        File file = new File(s);        if (!file.exists()) {            file.mkdirs();        }        return file;    }    /**     * 初始化     *     * @return If true is returned to the initial success, otherwise false     */    public static boolean init() {        boolean result = false;        if (existsSdCard()) {            result = true;            result &= createFolder(PROJECT_PATH) != null;            result &= createFolder(WMK_DB) != null;            result &= createFolder(WMK_IMG) != null;            result &= createFolder(WMK_LOG) != null;        }        return result;    }}

最后,在application中,捕获crash信息,代码如下:

package com.example.wmk;import android.app.Activity;import android.app.Application;import android.os.Build;import android.os.Bundle;import com.example.wmk.utils.ActivityManager;import com.example.wmk.utils.CrashHandler;import com.example.wmk.utils.ProjectUtils;import com.lidroid.xutils.util.LogUtils;/** * Created by 老王 on 2016/12/1. */public class WMKApplication extends Application {    ActivityManager mActivityManager;    @Override    public void onCreate() {        super.onCreate();        //init ActivityManager        mActivityManager = ActivityManager.getInstance();        // 注册activity监听器        registerActivityListener();        if (ProjectUtils.init()) {            //在这里为应用设置异常处理,然后程序才能获取未处理的异常            CrashHandler crashHandler = CrashHandler.getInstance();            crashHandler.init(this);        } else {            mActivityManager.appExceptionExit();        }    }    private void registerActivityListener() {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {                @Override                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {                    /**                     * 监听到 Activity创建事件 将该 Activity 加入list                     */                    mActivityManager.pushActivity(activity);                    /**                     * 栈顶元素名称                     */                    LogUtils.d("TopActivityName:" + mActivityManager.getTopActivityName());                }                @Override                public void onActivityStarted(Activity activity) {                }                @Override                public void onActivityResumed(Activity activity) {                }                @Override                public void onActivityPaused(Activity activity) {                }                @Override                public void onActivityStopped(Activity activity) {                }                @Override                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {                }                @Override                public void onActivityDestroyed(Activity activity) {                    if (null == mActivityManager.getActivitys() && mActivityManager.getActivitys().isEmpty()) {                        return;                    }                    if (mActivityManager.getActivitys().contains(activity)) {                        /**                         * 监听到 Activity销毁事件 将该Activity list中移除                         */                        mActivityManager.popActivity(activity);                    }                }            });        }    }}

下面在activity中抛出一个异常,布局文件如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".activity.MainActivity">    <Button        android:id="@+id/btn_crash"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="crash" /></RelativeLayout>

activity界面代码如下:

package com.example.wmk.activity;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Button;import com.example.wmk.R;import com.lidroid.xutils.ViewUtils;import com.lidroid.xutils.view.annotation.ViewInject;public class MainActivity extends Activity {    @ViewInject(R.id.btn_crash)    private Button btnCrash = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ViewUtils.inject(this);        initOnclickListener();    }    private void initOnclickListener() {        View.OnClickListener onClickListener = new View.OnClickListener() {            @Override            public void onClick(View v) {                if (v == btnCrash) {                    throw new RuntimeException("自定义异常");                }            }        };        btnCrash.setOnClickListener(onClickListener);    }}

点击自定义异常按钮,抛出crash信息,在SDCard中,会产生一个crash文件,如图:


最后可以把用户的crash信息上传服务器。


1 0