这是一篇笔记,也有参考别人的,也供别人参考,代码有详细注释
参考文章:
[转]Android自定义捕获Application全局异常
http://www.cnblogs.com/freeliver54/archive/2011/10/25/2223729.html
Android 对程序异常崩溃的捕捉
http://blog.youkuaiyun.com/i_lovefish/article/details/17719081
效果图:
输出异常信息:
android端:
一、自定义异常捕获类
package com.example.uncaughtexceptiondemo;
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 java.util.Set;
import android.app.AlertDialog;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.example.uncaughtexceptiondemo.application.AppManager;
import com.example.uncaughtexceptiondemo.net.HttpClientUtil;
/**
* 捕获全局异常,因为有的异常我们捕获不到
*
* @author river
*
*/
public class UncaughtException implements UncaughtExceptionHandler {
private final static String TAG = "UncaughtException";
/**
* 保存的异常信息的路径
*/
private static String path = Environment.getExternalStorageDirectory() + "/rz/crash/";
private static UncaughtException mUncaughtException;
private Context context;
private StringBuffer sb;
/**
* 取得当前时间
*/
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/**
* 声明当前年时间
*/
private String time;
/**
* 用来存储设备信息和异常信息,后面再把这些信息取出来用StringBuffer拼接后,存入文件中
*/
private Map<String, String> infos = new HashMap<String, String>();
public Context getContext() {
return context;
}
/**
* 初始化context 添加到需要检测的类下面
*
* @param context
*/
public void setContext(Context context) {
this.context = context;
}
private UncaughtException() {
// TODO Auto-generated constructor stub
}
/**
* 获取UncaughtException实例 ,单例模式 同步方法,保证只有一个CrashHandler实例 ,以免单例多线程环境下出现异常
*
* @return
*/
public synchronized static UncaughtException getInstance() {
if (mUncaughtException == null) {
mUncaughtException = new UncaughtException();
}
return mUncaughtException;
}
/**
*
* 获取系统默认的UncaughtException处理器, 设置该mUncaughtException为程序的默认处理器
* 初始化,把当前对象设置成UncaughtExceptionHandler处理异常
*/
public void init() {
Thread.setDefaultUncaughtExceptionHandler(mUncaughtException);
}
private boolean isShow = false;
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!isShow) {
// 获得当前的Activity对象
context = AppManager.getAppManager().currentActivity();
// 搜集设备信息
collectDeviceInfo(context);
// 保存信息到文件中
saveCrashInfo2File(ex);
// 发送错误报告到服务器 ,也可以放到dialog中,用户同意再发送
// sendCrashReportsToServer();
// 通知用户程序出现异常
showDialog();
} else {
}
}
private void sendCrashReportsToServer() {
// TODO Auto-generated method stub
// 发送Bug信息到服务器
HttpClientUtil util = new HttpClientUtil();
Map<String, String> map = new HashMap<String, String>();
map.put("ask", sb.toString());
String post = util.sendUnDESPost("www.baidu.com", map);
}
/**
* 弹出异常对话框,通知用户
*/
private void showDialog() {
new Thread() {
@Override
public void run() {
// 子线程弹出dialog 必须有looper.prepare(); Looper.loop();
Looper.prepare();
View view = View.inflate(context, R.layout.exception_dialog, null);
Button button = (Button) view.findViewById(R.id.dialog_button_cancel);
final AlertDialog dlg = new AlertDialog.Builder(context).setCancelable(false).create();
dlg.setView(view, 0, 0, 0, 0);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 用户同意再发送
// sendCrashReportsToServer();
isShow = true;
// Intent startMain = new Intent(Intent.ACTION_MAIN);
// startMain.addCategory(Intent.CATEGORY_HOME);
// startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(startMain);
System.exit(0);
}
});
dlg.show();
Looper.loop();
}
}.start();
}
/**
* 收集设备参数信息
*
* @param ctx
*/
public void collectDeviceInfo(Context context) {
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
// 把版本名字放入infos中
infos.put("versionName", versionName);
// 把版本号放入infos中
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info", e);
}
// 使用反射来收集设备信息.在Build类中包含各种设备信息,
// 例如: 系统版本号,设备生产商 等帮助调试程序的有用信息
// 具体信息请参考后面的log输出
// 得到Build的所有属性,通过Build的类获取手机硬件信息
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if ("TIME".equals(field.getName())) {
time = format.format(new Date());
infos.put(field.getName(), time);
Log.v("kan", "名字 = " + field.getName() + ",time = " + time);
// 输出:11-26 16:43:55.400: V/kan(1810): 名字 = TIME,time =
// 2014-11-26-16-43-55
} else {
infos.put(field.getName(), field.get(null).toString());
Log.v("kan", "名字 = " + field.getName() + ",值 = " + field.get(null).toString());
// 输出:
// 11-26 16:31:02.615: V/kan(862): 名字 = BOARD,值 = smdk4x12
// 11-26 16:31:02.615: V/kan(862): 名字 = BOOTLOADER,值 =
// C101ZNUANA2
// 11-26 16:31:02.615: V/kan(862): 名字 = BRAND,值 = samsung
// 11-26 16:31:02.620: V/kan(862): 名字 = CPU_ABI,值 =
// armeabi-v7a
// 11-26 16:31:02.620: V/kan(862): 名字 = CPU_ABI2,值 = armeabi
// 11-26 16:31:02.620: V/kan(862): 名字 = DEVICE,值 =
// mproject3g
// 11-26 16:31:02.620: V/kan(862): 名字 = DISPLAY,值 =
// JDQ39.C101ZNUANA2
// 11-26 16:31:02.620: V/kan(862): 名字 = FINGERPRINT,值 =
// samsung/mproject3gzn/mproject3g:4.2.2/JDQ39/C101ZNUANA2:user/release-keys
// 11-26 16:31:02.620: V/kan(862): 名字 = HARDWARE,值 =
// smdk4x12
// 11-26 16:31:02.620: V/kan(862): 名字 = HOST,值 = SEP-123
// 11-26 16:31:02.620: V/kan(862): 名字 = ID,值 = JDQ39
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_DEBUGGABLE,值 =
// false
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_SECURE,值 = false
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_SYSTEM_SECURE,值 =
// false
// 11-26 16:31:02.620: V/kan(862): 名字 =
// IS_TRANSLATION_ASSISTANT_ENABLED,值 = false
// 11-26 16:31:02.620: V/kan(862): 名字 = MANUFACTURER,值 =
// samsung
// 11-26 16:31:02.620: V/kan(862): 名字 = MODEL,值 = SM-C101
// 11-26 16:31:02.620: V/kan(862): 名字 = PRODUCT,值 =
// mproject3gzn
// 11-26 16:31:02.620: V/kan(862): 名字 = RADIO,值 = unknown
// 11-26 16:31:02.620: V/kan(862): 名字 = SERIAL,值 =
// 4d004dd9b0d87003
// 11-26 16:31:02.620: V/kan(862): 名字 = TAGS,值 =
// release-keys
// 11-26 16:31:02.625: V/kan(862): 名字 = TYPE,值 = user
// 11-26 16:31:02.625: V/kan(862): 名字 = UNKNOWN,值 = unknown
// 11-26 16:31:02.625: V/kan(862): 名字 = USER,值 = se.infra
}
/*
* Set<String> set = infos.keySet(); for(String key:set){
* Log.v("kan","key : "+key+", 值 : "+infos.get(key)); }
*/
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) {
String SDState = Environment.getExternalStorageState();
if (SDState.equals(Environment.MEDIA_MOUNTED)) {
sb = new StringBuffer();
sb.append("本手机信息:\n");
// 取出infos中的信息放入字符sb中
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中
sb.append("异常信息 :\n" + result);
try {
long timestamp = System.currentTimeMillis();
String time = format.format(new Date());
String fileName = "crash-" + time + "-" + timestamp + ".txt";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
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;
}
}
二、针对异常的捕捉要进行全局监控整个项目,所以要将其在Application中注册(也就是初始化):
package com.example.uncaughtexceptiondemo.application;
import java.util.LinkedList;
import java.util.List;
import android.app.Activity;
import android.app.Application;
import com.example.uncaughtexceptiondemo.UncaughtException;
/**全局application类
* @author nseer
*
*/
public class GlobalParams extends Application {
@Override
public void onCreate() {
super.onCreate();
// Initialize UncaughtException
//针对异常的捕捉要进行全局监控整个项目,所以要将其在Application中注册(也就是初始化):
UncaughtException crashHandler = UncaughtException.getInstance();
crashHandler.init();
}
}
三、定义一个activity管理类,负责将监控的activity加入,一般加入顶级父类
package com.example.uncaughtexceptiondemo.application;
import android.app.Activity;
import android.content.Context;
import java.util.Stack;
/**
* 应用程序Activity管理类:用于Activity管理和应用程序退出
*/
public class AppManager {
private static Stack<Activity> activityStack;
private static AppManager instance;
private AppManager(){}
/**
* 单一实例
*/
public static AppManager getAppManager(){
if(instance==null){
instance=new AppManager();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity){
if(activityStack==null){
activityStack=new Stack<Activity>();
}
activityStack.add(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity currentActivity(){
Activity activity=activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity(堆栈中最后一个压入的)
*/
public void finishActivity(){
Activity activity=activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity){
if(activity!=null){
activityStack.remove(activity);
activity.finish();
activity=null;
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class<?> cls){
for (Activity activity : activityStack) {
if(activity.getClass().equals(cls) ){
finishActivity(activity);
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity(){
for (int i = 0, size = activityStack.size(); i < size; i++){
if (null != activityStack.get(i)){
activityStack.get(i).finish();
}
}
activityStack.clear();
}
/**
* 退出应用程序
*/
public void AppExit(Context context) {
try {
finishAllActivity();
// ActivityManager activityMgr= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// activityMgr.killBackgroundProcesses(context.getPackageName());
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Exception e) { }
}
}
四、在配置文件中对Application进行注册:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.uncaughtexceptiondemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<!-- Required 一些系统要求的权限,如访问网络等 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:name="com.example.uncaughtexceptiondemo.application.GlobalParams"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.uncaughtexceptiondemo.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>
</manifest>
五、模拟一个空指针异常测试:
package com.example.uncaughtexceptiondemo;
import java.util.List;
import com.example.uncaughtexceptiondemo.application.AppManager;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加入需要监控的activity,一般放在顶级父类中
//两种方法
//第一种方法利用AppManager添加到栈中
AppManager.getAppManager().addActivity(this);
//第二种方法调用setContext()直接初始化
//设置UncaughtException 需要的上下文
// UncaughtException.getInstance().setContext(this);
}
public void throwException(View view) {
List list = null;
Log.e("MainActivity", list.get(0)+"");
}
}
服务器端:
一、servlet接受代码:
后端接受ask值后,保存在本地E盘根目录下,文件名以日期格式yyyy-MM-dd-HH-mm-ss命名:
package android.log ;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.io.* ;
import javax.servlet.* ;
import javax.servlet.http.* ;
public class AndroidLogServlet extends HttpServlet {
/** */
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String ask = req.getParameter("ask");
PrintWriter out = resp.getWriter();
out.write("ask: " + ask);
System.out.println(ask);
if(ask!=null)
saveLog(ask);
}
private void saveLog(String log) {
// TODO Auto-generated method stub
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String temp = format.format(new Date());
File f = new File("e:\\"+temp+".txt") ;
OutputStream out = null ;
try
{
out = new FileOutputStream(f) ;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
byte b[] = log.getBytes() ;
try
{
out.write(b) ;
}
catch (IOException e1)
{
e1.printStackTrace();
}
try
{
out.flush();
out.close() ;
}
catch (IOException e2)
{
e2.printStackTrace();
}
}
}
把类编译成class文件:
二:web.xml配置:
<servlet>
<servlet-name>android</servlet-name>
<servlet-class>android.log.AndroidLogServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>android</servlet-name>
<url-pattern>/androidLog</url-pattern>
</servlet-mapping>
web配置效果:
三、启动tomcat信息:
四、可以通过两种方式访问:浏览器访问和android客户端访问
ask的值会显示在上图tomcat的下面
1.浏览器访问
2.android客户端访问效果见第一张效果图。
五、后台效果图:
注意事项:
请求网络
1.关掉防火墙
2.把请求放到线程当中
3.url写替换为本机IP地址
改写异常类代码:主要是修改网络发送log信息部分
package com.example.uncaughtexceptiondemo;
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 java.util.Set;
import android.app.AlertDialog;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.example.uncaughtexceptiondemo.application.AppManager;
import com.example.uncaughtexceptiondemo.net.HttpClientUtil;
/**
* 捕获全局异常,因为有的异常我们捕获不到
*
* @author river
*
*/
public class UncaughtException implements UncaughtExceptionHandler {
private final static String TAG = "UncaughtException";
/**
* 保存的异常信息的路径
*/
private static String path = Environment.getExternalStorageDirectory() + "/rz/crash/";
private static UncaughtException mUncaughtException;
private Context context;
private StringBuffer sb;
/**
* 取得当前时间
*/
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/**
* 声明当前年时间
*/
private String time;
/**
* 用来存储设备信息和异常信息,后面再把这些信息取出来用StringBuffer拼接后,存入文件中
*/
private Map<String, String> infos = new HashMap<String, String>();
public Context getContext() {
return context;
}
/**
* 初始化context 添加到需要检测的类下面
*
* @param context
*/
public void setContext(Context context) {
this.context = context;
}
private UncaughtException() {
// TODO Auto-generated constructor stub
}
/**
* 获取UncaughtException实例 ,单例模式 同步方法,保证只有一个CrashHandler实例 ,以免单例多线程环境下出现异常
*
* @return
*/
public synchronized static UncaughtException getInstance() {
if (mUncaughtException == null) {
mUncaughtException = new UncaughtException();
}
return mUncaughtException;
}
/**
*
* 获取系统默认的UncaughtException处理器, 设置该mUncaughtException为程序的默认处理器
* 初始化,把当前对象设置成UncaughtExceptionHandler处理异常
*/
public void init() {
Thread.setDefaultUncaughtExceptionHandler(mUncaughtException);
}
private boolean isShow = false;
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!isShow) {
// 获得当前的Activity对象
context = AppManager.getAppManager().currentActivity();
// 搜集设备信息
collectDeviceInfo(context);
// 保存信息到文件中
saveCrashInfo2File(ex);
// 发送错误报告到服务器 ,也可以放到dialog中,用户同意再发送
sendCrashReportsToServer();
// 通知用户程序出现异常
showDialog();
} else {
}
}
private void sendCrashReportsToServer() {
// TODO Auto-generated method stub
new Thread(new Runnable() {
@Override
public void run() {
sendUnDESPost();
// sentGet();
}
}).start();
}
private void sendUnDESPost() {
// 发送Bug信息到服务器
HttpClientUtil util = new HttpClientUtil();
Map<String, String> map = new HashMap<String, String>();
map.put("ask", sb.toString());
// Log.v("kan", "输出 :" + sb.toString());
String postString = util.sendUnDESPost("http://192.168.0.113:8080/myweb/androidLog", map);
Log.v("kan", "postString = " + postString);
}
/**
* 弹出异常对话框,通知用户
*/
private void showDialog() {
new Thread() {
@Override
public void run() {
// 子线程弹出dialog 必须有looper.prepare(); Looper.loop();
Looper.prepare();
View view = View.inflate(context, R.layout.exception_dialog, null);
Button button = (Button) view.findViewById(R.id.dialog_button_cancel);
final AlertDialog dlg = new AlertDialog.Builder(context).setCancelable(false).create();
dlg.setView(view, 0, 0, 0, 0);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 用户同意再发送
// sendCrashReportsToServer();
isShow = true;
// Intent startMain = new Intent(Intent.ACTION_MAIN);
// startMain.addCategory(Intent.CATEGORY_HOME);
// startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(startMain);
System.exit(0);
}
});
dlg.show();
Looper.loop();
}
}.start();
}
/**
* 收集设备参数信息
*
* @param ctx
*/
public void collectDeviceInfo(Context context) {
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
// 把版本名字放入infos中
infos.put("versionName", versionName);
// 把版本号放入infos中
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info", e);
}
// 使用反射来收集设备信息.在Build类中包含各种设备信息,
// 例如: 系统版本号,设备生产商 等帮助调试程序的有用信息
// 具体信息请参考后面的log输出
// 得到Build的所有属性,通过Build的类获取手机硬件信息
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if ("TIME".equals(field.getName())) {
time = format.format(new Date());
infos.put(field.getName(), time);
// Log.v("kan", "名字 = " + field.getName() + ",time = " + time);
// 输出:11-26 16:43:55.400: V/kan(1810): 名字 = TIME,time =
// 2014-11-26-16-43-55
} else {
infos.put(field.getName(), field.get(null).toString());
// Log.v("kan", "名字 = " + field.getName() + ",值 = " + field.get(null).toString());
// 输出:
// 11-26 16:31:02.615: V/kan(862): 名字 = BOARD,值 = smdk4x12
// 11-26 16:31:02.615: V/kan(862): 名字 = BOOTLOADER,值 =
// C101ZNUANA2
// 11-26 16:31:02.615: V/kan(862): 名字 = BRAND,值 = samsung
// 11-26 16:31:02.620: V/kan(862): 名字 = CPU_ABI,值 =
// armeabi-v7a
// 11-26 16:31:02.620: V/kan(862): 名字 = CPU_ABI2,值 = armeabi
// 11-26 16:31:02.620: V/kan(862): 名字 = DEVICE,值 =
// mproject3g
// 11-26 16:31:02.620: V/kan(862): 名字 = DISPLAY,值 =
// JDQ39.C101ZNUANA2
// 11-26 16:31:02.620: V/kan(862): 名字 = FINGERPRINT,值 =
// samsung/mproject3gzn/mproject3g:4.2.2/JDQ39/C101ZNUANA2:user/release-keys
// 11-26 16:31:02.620: V/kan(862): 名字 = HARDWARE,值 =
// smdk4x12
// 11-26 16:31:02.620: V/kan(862): 名字 = HOST,值 = SEP-123
// 11-26 16:31:02.620: V/kan(862): 名字 = ID,值 = JDQ39
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_DEBUGGABLE,值 =
// false
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_SECURE,值 = false
// 11-26 16:31:02.620: V/kan(862): 名字 = IS_SYSTEM_SECURE,值 =
// false
// 11-26 16:31:02.620: V/kan(862): 名字 =
// IS_TRANSLATION_ASSISTANT_ENABLED,值 = false
// 11-26 16:31:02.620: V/kan(862): 名字 = MANUFACTURER,值 =
// samsung
// 11-26 16:31:02.620: V/kan(862): 名字 = MODEL,值 = SM-C101
// 11-26 16:31:02.620: V/kan(862): 名字 = PRODUCT,值 =
// mproject3gzn
// 11-26 16:31:02.620: V/kan(862): 名字 = RADIO,值 = unknown
// 11-26 16:31:02.620: V/kan(862): 名字 = SERIAL,值 =
// 4d004dd9b0d87003
// 11-26 16:31:02.620: V/kan(862): 名字 = TAGS,值 =
// release-keys
// 11-26 16:31:02.625: V/kan(862): 名字 = TYPE,值 = user
// 11-26 16:31:02.625: V/kan(862): 名字 = UNKNOWN,值 = unknown
// 11-26 16:31:02.625: V/kan(862): 名字 = USER,值 = se.infra
}
/*
* Set<String> set = infos.keySet(); for(String key:set){
* Log.v("kan","key : "+key+", 值 : "+infos.get(key)); }
*/
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) {
String SDState = Environment.getExternalStorageState();
if (SDState.equals(Environment.MEDIA_MOUNTED)) {
sb = new StringBuffer();
sb.append("本手机信息:\n");
// 取出infos中的信息放入字符sb中
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中
sb.append("异常信息 :\n" + result);
try {
long timestamp = System.currentTimeMillis();
String time = format.format(new Date());
// 指定文件格式为txt
String fileName = "crash-" + time + "-" + timestamp + ".txt";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
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;
}
}