您的位置:首页 > 移动开发 > Android开发

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

2016-12-02 14:08 513 查看
当用户发生了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 Strin
ed29
g 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信息上传服务器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: