Android监听全局异常,并记录异常

现在我们的项目现在又一个需求,需要全局监听系统中的异常,然后当程序发生异常时记录下发生的异常,并上传到服务器,便于下一个版本修复这些问题,然后重启当前程序。
首先需要在Application中注册监听全局异常,
在Appliation 的onCreate()方法中加入下面方法

 CrashHandler handler = CrashHandler.getInstance();
        Thread.setDefaultUncaughtExceptionHandler(handler);

新建一个CrashHandler.java

package com.test.pack;

import android.content.Context;
import android.content.Intent;
import android.widget.TextView;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private static CrashHandler INSTANCE = new CrashHandler();
    // 程序的 Context 对象
    private Context mContext = MyApplication.getContext();
   
    // 用于格式化日期,作为日志文件名的一部分
    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
    private CrashHandler() {

    }

    public static CrashHandler getInstance() {
        return INSTANCE;
    }

    /**
     * 当有未捕获异常发生,就会调用该函数,
     * 可以在该函数中对异常信息捕获并上传
     *
     * @param thread 发生异常的线程
     * @param ex     异常
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
       
        //启动Services向服务器发送数据
        Intent start = new Intent(mContext, Services.class);
        start.putExtra("de", device + operationVer);
        start.putExtra("ver", versionName);
        start.putExtra("ap", "");
        start.putExtra("ex", detailException(ex));
        start.putExtra("time", formatter.format(date));
               mContext.startService(start);
        //这里写在发生异常时当前程序要做什么
        //重启当前程序
         System.out.println(ex.toString());
        time2Restart();
    }
//拿到更加详细的异常信息
    private static String detailException(Throwable e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        e.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }

}

新建一个IntentService.java用于向服务器上传异常信息
这里说明一下为什么要用IntentService,当程序发生异常时,即使我们kill掉当前程序,这个IntentService也不会受影响
下面是IntentService中的代码

package com.test.pack;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

import com.google.gson.Gson;
import com.greatzee.poc.bean.ExceptionDto;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static com.serenegiant.utils.UIThreadHelper.runOnUiThread;

public class Services extends IntentService {
    private Context mContext = MyApplication.getContext();
    private String de="";
    private String Version="";
    private String AppId="";
    private String ExceptionStack="";
    private String CreateTime="";
    private final String serverPath = MyApplication.BROADCAST_URL;

    public Services() {
        this("Service");
    }

    public Services(String name) {
        super(name);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        //拿到传过来的值,然后传给服务器
        Device=intent.getStringExtra("de");
        Version=intent.getStringExtra("ver");
        AppId=intent.getStringExtra("ap");
        ExceptionStack=intent.getStringExtra("ex");
        CreateTime=intent.getStringExtra("time");
        getData(intent);
    }
//异步请求服务器
    public void getData(final Intent intent){
        OkHttpClient client = new OkHttpClient();
        MediaType mediaType = MediaType.parse("application/json;charset=UTF-8");
        ExceptionDto exceptionDto=new ExceptionDto();
        exceptionDto.setCreateTime(CreateTime);
        exceptionDto.setAppId(AppId);
        exceptionDto.setDevice(Device);
        exceptionDto.setExceptionStack(ExceptionStack);
        exceptionDto.setVersion(Version);
        RequestBody body = RequestBody.create(mediaType, new Gson().toJson(exceptionDto));
        Request request = new Request.Builder()
                .url(serverPath)
                .post(body)
                .addHeader("Content-Type", "application/json;charset=UTF-8")
                .addHeader("cache-control", "no-cache")
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
//                Toast.makeText(mContext, "失败", Toast.LENGTH_SHORT).show();
                stopService(intent);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String string = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        stopService(intent);
//                        Toast.makeText(mContext, string, Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }
}

重启当前程序的代码如下所示:
首先需要在AndroidMainfest.xml中配置首个启动的界面配置android:name属性


            
                
                
                
                
            
        

下面是唤起程序的代码:

/**
     * 重启App
     */
    public static void time2Restart(String value) {
        if (TextUtils.isEmpty("刚才定义的名字") ||TextUtils.isEmpty("包名")) {
            return;
        }
        Intent intent = new Intent("刚才定义的名字");
        intent.putExtra("Be_offline", value);
        intent.setPackage("包名");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent restartIntent = PendingIntent.getActivity(Application.getContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarmManager = (AlarmManager) Application.getContext().getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), restartIntent);
    }

你可能感兴趣的:(Android相关)