程序异常问题:
程序因未捕获的异常而突然终止时,系统会调用处理程序的接口UncaughtExceptionHandler。如果我们想处理未被程序正常捕获的异常,只需实现这个接口里的uncaughtException方法,uncaughtException方法回传了Thread 和 Throwable两个参数。通过这两个参数,我们来对异常进行我们需要的处理
处理异常思路:
1.收集产生崩溃的手机信息,写入文件系统中。
2.崩溃的应用需要可以自动重启。
3.自动上传崩溃信息文件到自己的服务器。
1.收集手机的信息:
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);
infos.put("crashTime", formatter.format(new Date()));
}
} 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);
}
}
}
2.崩溃和手机信息写入文件:
private void writeCrashInfoToFile(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 + "\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);
//这里把刚才异常堆栈信息写入SD卡的Log日志里面
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
String sdcardPath = Environment.getExternalStorageDirectory().getPath();
String filePath = sdcardPath + "/cym/crash/";
localFileUrl = writeLog(sb.toString(), filePath);
}
}
/**
*
* @param log
* @param name
* @return 返回写入的文件路径
* 写入Log信息的方法,写入到SD卡里面
*/
private String writeLog(String log, String name)
{
CharSequence timestamp = new Date().toString().replace(" ", "");
timestamp = "crash";
String filename = name + timestamp + ".log";
File file = new File(filename);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
try
{
Log.d("TAG", "写入到SD卡里面");
// FileOutputStream stream = new FileOutputStream(new File(filename));
// OutputStreamWriter output = new OutputStreamWriter(stream);
file.createNewFile();
FileWriter fw=new FileWriter(file,true);
BufferedWriter bw = new BufferedWriter(fw);
//写入相关Log到文件
bw.write(log);
bw.newLine();
bw.close();
fw.close();
return filename;
}
catch (IOException e)
{
Log.e(TAG, "an error occured while writing file...", e);
e.printStackTrace();
return null;
}
}
3.重启应用:
private void restart(){
try{
Thread.sleep(2000);
}catch (InterruptedException e){
Log.e(TAG, "error : ", e);
}
Intent intent = new Intent(context.getApplicationContext(), MainActivity.class);
PendingIntent restartIntent = PendingIntent.getActivity(
context.getApplicationContext(), 0, intent,
Intent.FLAG_ACTIVITY_NEW_TASK);
//退出程序
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
restartIntent); // 1秒钟后重启应用
}
4.上传崩溃
public static String uploadFile(File file,String requestUrl){
String result = null;
String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成
String PREFIX = "--" ;
String LINE_END = "\r\n";
String CONTENT_TYPE = "multipart/form-data"; //内容类型
try{
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true); //允许输入流
conn.setDoOutput(true); //允许输出流
conn.setUseCaches(false); //不允许使用缓存
conn.setRequestMethod("POST"); //请求方式
conn.setRequestProperty("Charset", CHARSET); //设置编码
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
if(file!=null)
{
/**
* 当文件不为空,把文件包装并且上传
*/
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINE_END);
/**
* 这里重点注意:
* name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
sb.append("Content-Disposition: form-data; name=\"uploadcrash\"; filename=\""+file.getName()+"\""+LINE_END);
sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END);
sb.append(LINE_END);
dos.write(sb.toString().getBytes());
InputStream is = new FileInputStream(file);
byte[] bytes = new byte[1024];
int len = 0;
while((len=is.read(bytes))!=-1)
{
dos.write(bytes, 0, len);
}
is.close();
dos.write(LINE_END.getBytes());
byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes();
dos.write(end_data);
dos.flush();
/**
* 获取响应码 200=成功
* 当响应成功,获取响应的流
*/
int res = conn.getResponseCode();
Log.e(TAG, "response code:" + res);
// if(res==200)
// {
Log.e(TAG, "request success");
InputStream input = conn.getInputStream();
StringBuffer sb1= new StringBuffer();
int ss ;
while((ss=input.read())!=-1)
{
sb1.append((char)ss);
}
result = sb1.toString();
Log.e(TAG, "result : "+ result);
// }
// else{
// Log.e(TAG, "request error");
// }
}
}catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}