android全局处理非捕捉异常

一、概述

android应用捕捉所有线程没有catch的exception,并将相关日志文件压缩并发送到服务器。环境如下:
android: slf4j+logback,retrofit
server: play framework 2

二、自定义Application

public class MyApp extends Application {
    private static final Logger log = LoggerFactory.getLogger(MyApp.class);
    public boolean isUIThread(){
        return Looper.getMainLooper().getThread() == Thread.currentThread();
    }
        @Override
    public void onCreate() {
        log.debug("onCreate");
        super.onCreate();
        //处理非捕捉异常
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable e) {
                handleUncaughtException(thread, e);
            }
        });
    }
    private void handleUncaughtException(Thread thread, Throwable e) {
        log.error("UncaughtException thread=" + thread.getName(), e);
        if(isUIThread()) {//UI thread throw exception
            invokeLogActivity();
        }else{//non UI thread throw exception
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    invokeLogActivity();
                }
            });
        }
    }
    //启动另外一个acitivy发送日志
    private void invokeLogActivity(){
        Intent intent = new Intent();
        intent.setAction("cn.mydomain.SEND_LOG");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        startActivity(intent);
        System.exit(1);
    }
}

三、发送错误日志文件的Activity

<activity
    android:label="@string/base_warning"
    android:name=".ui.SendErrorLogActivity"
    android:theme="@android:style/Theme.Holo.Dialog" >
    <intent-filter>
        <action android:name="cn.mydomain.SEND_LOG" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
public class SendErrorLogActivity extends Activity{

    private static final Logger log = LoggerFactory.getLogger(SendErrorLogActivity.class);

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setFinishOnTouchOutside(false);

        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setPadding(8, 8, 8, 8);
        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

        TextView textView = new TextView(this);
        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        textView.setText(R.string.error_exit);
        textView.setTextAppearance(this, R.style.TextAppearance_AppCompat_Large);
        textView.setPadding(8, 8, 8, 8);
        layout.addView(textView);

        button = new Button(this);
        button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        button.setText(R.string.base_confirm);
        button.setGravity(Gravity.CENTER);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                log.info("send error file to server");
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss");
                    String targetFile = getCacheDir() + "/errorMsg" + sdf.format(new Date()) + ".gz";               
                    CompressUtil.createGzFile(MyApp.instance.getAppDir() + "/files/log.txt", targetFile);//压缩文件
                    button.setEnabled(false);
                    //发送文件到服务器
                    MainManage.uploadErrorFile(new File(targetFile), new Function() {
                        @Override
                        public void success(Object o) {
                            log.error("send error file success");
                            log.error("app exit by uncaught exception");
                            System.exit(1);
                        }

                        @Override
                        public void fail(Throwable t) {
                            log.error("send error file fail", t);
                            log.error("app exit by uncaught exception");
                            System.exit(1);
                        }
                    });
                } catch (Exception e1) {
                    log.error("send error file fail", e1);
                    log.error("app exit by uncaught exception");
                    System.exit(1);
                }
            }
        });
        layout.addView(button);

        setContentView(layout);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            log.error("app exit by uncaught exception without send error file");
            System.exit(1);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

MainManage调用核心方法

    public static void uploadErrorFile(File file, final Function callback){
        log.info("uploadErrorFile");
        service.uploadErrorFile(new TypedFile("application/x-gzip", file), new MyCallBack("uploadErrorFile fileName=" + file.getName(), callback));
    }

    public interface MyService{
        @Multipart
        @POST("/app/errorFile")
        void uploadErrorFile(@Part("errorFile") TypedFile errorFile, Callback<Response> cb);
    }

四、服务器处理

routes

POST    /app/errorFile  cn.mydomain.web.controllers.Controller.uploadErrorFile()
    public Result uploadErrorFile(){
        Http.MultipartFormData body = request().body().asMultipartFormData();
        if(body == null){
            return badRequest();
        }
        Http.MultipartFormData.FilePart errorFile = body.getFile("errorFile");
        if (errorFile != null) {
            String fileName = errorFile.getFilename();
            logger.info("uploadErrorFile fileName=" + fileName);
            File file = errorFile.getFile();
            File targetDir = new File(GlobalData.ERROR_FILE_PATH);
            if(!targetDir.exists()){
                targetDir.mkdirs();
            }
            try {
                IOUtils.copy(new FileInputStream(file), new FileOutputStream(GlobalData.ERROR_FILE_PATH + fileName));
            } catch (IOException e) {
                logger.error("upload error file fail filename=" + fileName, e);
            }
            return ok("File uploaded");
        } else {
            return badRequest();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值