android 未捕获异常处理

我们知道,在android开发中,未捕获的异常,会导致app奔溃,这里测试,让程序报一个空指针异常,并且不捕获,这时如图app奔溃,android 未捕获异常处理_第1张图片,这时我们可以定义一个UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告. 在这里我是将异常发送到服务器,并且发送到我的邮箱,这时,我的邮箱就会收到一份异常信息,如图:android 未捕获异常处理_第2张图片,,并且你也可以自定义异常崩溃界面,例如我自定义了一个toast,如图:android 未捕获异常处理_第3张图片,具体实现如下:

1. 定义UncaughtException异常处理类

package com.jianhai.health.util.uncaughtexception;




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 com.jianhai.health.activiy.BuildConfig;
import com.jianhai.health.activiy.R;
import com.jianhai.health.db.uncaught.UnCaughtDBManager;
import com.jianhai.health.entity.uncaught.UncaughtExceptionItem;
import com.jianhai.health.util.MyActivityManager;
import com.jianhai.health.util.toast.ToastUtils;


import android.content.Context;  
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;  
/** 
 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告. 
 *  
 * @author user 
 *  
 */  
public class CrashHandler implements UncaughtExceptionHandler {  
      
    public static final String TAG = "CrashHandler";  
      
    //系统默认的UncaughtException处理类   
    private Thread.UncaughtExceptionHandler mDefaultHandler;  
    //CrashHandler实例  
    private static CrashHandler INSTANCE = new CrashHandler();  
    //程序的Context对象  
    private Context mContext;  
    //用来存储设备信息和异常信息  
    private Map infos = new HashMap();  
  
    //用于格式化日期,作为日志文件名的一部分  
    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) {  
        if (!handleException(ex) && mDefaultHandler != null) {  
            //如果用户没有处理则让系统默认的异常处理器来处理  
            mDefaultHandler.uncaughtException(thread, ex);  
        } else {  
            try {  
                Thread.sleep(4500);  
                
                MyActivityManager.getIns().exit();
                //退出程序  
                android.os.Process.killProcess(android.os.Process.myPid());  
                System.exit(1); 
                
            } catch (Exception e) {  
                Log.e(TAG, "error : ", e);  
            }  
            
        }  
    }  
  
    /** 
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 
     *  
     * @param ex 
     * @return true:如果处理了该异常信息;否则返回false. 
     */  
    private boolean handleException(Throwable ex) {  
        try {
        	if (ex == null) {  
                return false;  
            }  
            //使用Toast来显示异常信息  
            new Thread() {  
                @Override  
                public void run() {  
                    try {
                    	Looper.prepare();  
                        String des = "非常抱歉, 程序出现了不可预知的错误,即将退出, 小牛们将尽快为您修复。";
                        ToastUtils.makeErrorText( mContext, des).show();
                        Looper.loop();  
 } catch (Exception e) {
 e.printStackTrace();
 }
                }  
            }.start();  
            //收集设备参数信息   
            collectDeviceInfo(mContext);  
            //上传异常 
            saveCrashInfo(ex);  
            return true;  
 } catch (Exception e) {
 e.printStackTrace();
 return false;
 }
    }  
      
    /** 
     * 收集设备参数信息 
     * @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 void saveCrashInfo(Throwable ex) {  
          
        try {  
        
        	 StringBuffer sb = new StringBuffer();  
             for (Map.Entry 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.append(result);  
             
             if(BuildConfig.DEBUG){
             	Log.i("uncash", sb.toString());
             }
             
            long timestamp = System.currentTimeMillis();  
            String time = formatter.format(new Date());  
            String fileName = "crash-" + time + "-" + timestamp ;  
            
            // 上传到服务器
            UncaughtExceptionItem item = new UncaughtExceptionItem(fileName, "",sb.toString());
            UnCaughtDBManager.saveUncaughtExceptionItem(item); // 本地保存异常
            UnCaughtDBManager.upLoatUnCaughts(); // 上传异常
            
            
        } catch (Exception e) {  
            Log.e(TAG, "an error occured while writing file...", e);  
        }  
    }  
}  


然后在 Application中初始化:

package com.jianhai.health.application;

import org.litepal.LitePalApplication;

import android.content.Intent;
import android.content.IntentFilter;

import com.jianhai.health.entity.ClientUser;
import com.jianhai.health.receive.DrugAlarmRemaindReceiver;
import com.jianhai.health.util.AppManager;
import com.jianhai.health.util.uncaughtexception.CrashHandler;



/**
 * 记录一些全局变量
 * @author znn
 *
 */
public class HGApplication extends LitePalApplication {
	
	private static HGApplication instance;
	/**
     * 单例,返回一个实例
     * @return
     */
    public static HGApplication getInstance() {
        return instance;
    }
	
    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        AppManager.setContext(instance);
        
        // 奔溃处理器
        CrashHandler crashHandler = CrashHandler.getInstance();  
        crashHandler.init(getApplicationContext());  
    }
    
	// 消息总记录数
	public long messageTotalNum; 
}



import java.io.Serializable;

import com.jianhai.health.entity.BaseDBEntity;

/**
 * 未捕获异常对象信息
 * @author znn
 *
 */
public class UncaughtExceptionItem extends BaseDBEntity implements Serializable{

	private static final long serialVersionUID = 1L;
	
	private long id;
	
	private String fileName; // 异常标题
	
	private String context;  //异常内容
	
	private String sendEmail="n"; //是否发送了邮件,n=没有,y=发送了

	public UncaughtExceptionItem(String fileName, String path,String context) {
		super();
		this.fileName = fileName;
		this.context = context;
		this.sendEmail="n";
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}


	public String getContext() {
		return context;
	}

	public void setContext(String context) {
		this.context = context;
	}

	public String getSendEmail() {
		return sendEmail;
	}

	public void setSendEmail(String sendEmail) {
		this.sendEmail = sendEmail;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}
}




package com.jianhai.health.db.uncaught;

import java.util.List;

import org.apache.http.Header;
import org.json.JSONArray;
import org.json.JSONObject;
import org.litepal.crud.DataSupport;




import android.content.ContentValues;

import com.jianhai.health.entity.uncaught.UncaughtExceptionItem;
import com.jianhai.health.util.AppManager;
import com.jianhai.health.util.ProtocolType;
import com.jianhai.health.util.config.ConfigUtil;
import com.jianhai.health.util.emaill.EmailUtils;
import com.jianhai.health.util.http.AsyncHttpsClientUtils;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.PersistentCookieStore;
import com.loopj.android.http.RequestParams;

public class UnCaughtDBManager {

	/**
	 * 在产生异常、网络变化-有网络、应用初始化
	 * 
	 * 上传未读的异常
	 * 
	 * 原因在于:有可能用户在没有网络的情况下点击出现了异常,所以需要将异常保存起来,在发送
	 * 
	 */
	public static void upLoatUnCaughts(){
		doBackground(findUncaughtExceptionItems());
	}
	
	public static void doBackground(final List list) {
		try {
			if(list == null || list.size() <=0){
				return;
			}
			AsyncHttpClient client = AsyncHttpsClientUtils
					.getAsyncHttpClient(AppManager.getContext());
			PersistentCookieStore myCookieStore = new PersistentCookieStore(
					AppManager.getContext());
			client.setCookieStore(myCookieStore);
			RequestParams params = new RequestParams();
			params.put("protocol", ProtocolType.UNCAUGHT_EXCEPTION);
			
			JSONArray arry = new JSONArray();
			for(UncaughtExceptionItem item:list){
				JSONObject obj = new JSONObject();
				obj.put("ex", item.getContext());   // 异常内容
				obj.put("fileName", item.getFileName()); // 异常标题
				arry.put(obj);
				
				if("n".equals(item.getSendEmail())){  // 如果没有发送过邮件,者发送
					EmailUtils.sendEmail(item);
				}
				
			}
			params.put("exs", arry);
			
			
			client.post(ConfigUtil.getInstanse().getServerHost(), params,
					new AsyncHttpResponseHandler() {
						@Override
						public void onFailure(int arg0, Header[] arg1,
								byte[] arg2, Throwable error) {
					//		httpExceptionShow(error);
							error.printStackTrace();
						}

						@Override
						public void onSuccess(int arg0, Header[] arg1,
								byte[] arg2) {
							doPostExecute(arg2,list);
						}
					});
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	public static void updateSendEmail(UncaughtExceptionItem item){
		ContentValues values = new ContentValues();
		values.put("sendEmail","y");
		DataSupport.update(UncaughtExceptionItem.class, values, item.getId());
	}

	private static void doPostExecute(byte[] arg2,List list) {
		try {
			String rs = new String(arg2, "utf-8");
			JSONObject js = new JSONObject(rs);
			if (js.getInt("res") == 0) {
				deleteUncaughtExceptionItems(list);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 找出异常
	 * @return
	 */
	public static List findUncaughtExceptionItems() {
		List list = DataSupport.findAll(
				UncaughtExceptionItem.class);
		return list;
	}
	
	
	// 删除 已经发送
	public static void deleteUncaughtExceptionItems(List list) {
		for(UncaughtExceptionItem item:list){
			DataSupport.deleteAll(UncaughtExceptionItem.class, "fileName=?",item.getFileName());
		}
	}
	
	/**
	 * @param member
	 */
	public static void saveUncaughtExceptionItem(UncaughtExceptionItem item){
		item.save();
	}
	
}



发送邮件的代码在:http://pan.baidu.com/s/1bnfqQlT

转载于:https://my.oschina.net/u/2348543/blog/525644

你可能感兴趣的:(android 未捕获异常处理)