Android全局捕获异常信息,并上传到服务器。

android全局捕获异常信息

由于最近在做一个国外的项目,所以客户测试时,有些简单的问题直接可以改改。但是当客户拿着国外的手机,或者一些各种机型的手机出现不同的问题时,真心不知道咋解决了。所以如果在程序出现异常时,需要及时捕获到并上传到服务器。这样我们就能够看到异常日志信息了。

1.首先介绍工具类:CrashUtils和xjzUtils

可以在github上找到:https://github.com/Blankj/AndroidUtilCode这个里面封装了很多工具类。

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.util.Log;

import com.ztxx.customer.http.HttpUtil;
import com.ztxx.customer.http.MyCallBack;
import com.ztxx.customer.http.UrlConst;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <pre>
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/09/27
 *     desc  : 崩溃相关工具类
 * </pre>
 */
public final class CrashUtils {

    private static String defaultDir;
    private static String dir;
    private static String versionName;
    private static int versionCode;

    private static ExecutorService sExecutor;

    private static final String FILE_SEP = System.getProperty("file.separator");
    private static final Format FORMAT = new SimpleDateFormat("MM-dd HH-mm-ss", Locale.getDefault());

    private static final String CRASH_HEAD;

    private static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER;
    private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER;

    static {
        try {
            PackageInfo pi = xjzUtils.getApp().getPackageManager().getPackageInfo(xjzUtils.getApp().getPackageName(), 0);
            if (pi != null) {
                versionName = pi.versionName;
                versionCode = pi.versionCode;
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        CRASH_HEAD = "\n************* Crash Log Head ****************" +
                "\nDevice Manufacturer: " + Build.MANUFACTURER +// 设备厂商
                "\nDevice Model       : " + Build.MODEL +// 设备型号
                "\nAndroid Version    : " + Build.VERSION.RELEASE +// 系统版本
                "\nAndroid SDK        : " + Build.VERSION.SDK_INT +// SDK版本
                "\nApp VersionName    : " + versionName +
                "\nApp VersionCode    : " + versionCode +
                "\n************* Crash Log Head ****************\n\n";

        DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler();

        UNCAUGHT_EXCEPTION_HANDLER = new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(final Thread t, final Throwable e) {
                Log.i("path", "抓住了异常");
                if (e == null) {
                    android.os.Process.killProcess(android.os.Process.myPid());
                    System.exit(0);
                    return;
                }
                Date now = new Date(System.currentTimeMillis());
//                fileName = FORMAT.format(now) + ".txt"
                fileName = "Exception.txt";
                fullPath = (dir == null ? defaultDir : dir) + fileName;
                if (!createOrExistsFile(fullPath)) return;
                if (sExecutor == null) {
                    sExecutor = Executors.newSingleThreadExecutor();
                }
                sExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        PrintWriter pw = null;
                        try {
                            pw = new PrintWriter(new FileWriter(fullPath, true));
                            pw.write(CRASH_HEAD);
                            e.printStackTrace(pw);
                            Throwable cause = e.getCause();
                            while (cause != null) {
                                cause.printStackTrace(pw);
                                cause = cause.getCause();
                            }


                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            if (pw != null) {
                                pw.close();
                            }
                        }
                    }
                });

                if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) {
                    DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, e);
                }
            }
        };
    }

    public static String fileName;
    private static String fullPath;

    private static void uploadCrash(String fullPath) {
        HttpUtil.uploadCrashFile(UrlConst.UPLOADURL, fullPath, new MyCallBack<String>() {
            @Override
            public void onSuccess(String result) {
                super.onSuccess(result);
                Log.i("path", result);
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                super.onError(ex, isOnCallback);
                Log.i("path", ex.toString());
            }
        });

    }

    private CrashUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    /**
     * 初始化
     * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
     */
    public static void init() {
        init("");
    }

    /**
     * 初始化
     * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
     *
     * @param crashDir 崩溃文件存储目录
     */
    public static void init(@NonNull final File crashDir) {
        init(crashDir.getAbsolutePath());
    }

    /**
     * 初始化
     * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
     *
     * @param crashDir 崩溃文件存储目录
     */
    public static void init(final String crashDir) {
        if (isSpace(crashDir)) {
            dir = null;
        } else {
            dir = crashDir.endsWith(FILE_SEP) ? crashDir : crashDir + FILE_SEP;
        }
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                && xjzUtils.getApp().getExternalCacheDir() != null)
            defaultDir = xjzUtils.getApp().getExternalCacheDir() + FILE_SEP + "crash" + FILE_SEP;
        else {
            defaultDir = xjzUtils.getApp().getCacheDir() + FILE_SEP + "crash" + FILE_SEP;
        }
        Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
    }

    private static boolean createOrExistsFile(final String filePath) {
        File file = new File(filePath);
        if (file.exists()) return file.isFile();
        if (!createOrExistsDir(file.getParentFile())) return false;
        try {
            return file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private static boolean createOrExistsDir(final File file) {
        return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
    }

    private static boolean isSpace(final String s) {
        if (s == null) return true;
        for (int i = 0, len = s.length(); i < len; ++i) {
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}
xjzUtils工具类:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.support.annotation.NonNull;

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.List;

public final class xjzUtils {

    @SuppressLint("StaticFieldLeak")
    private static Application sApplication;

    static WeakReference<Activity> sTopActivityWeakRef;
    static List<Activity> sActivityList = new LinkedList<>();

    private static Application.ActivityLifecycleCallbacks mCallbacks = new Application.ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle bundle) {
            sActivityList.add(activity);
            setTopActivityWeakRef(activity);
        }

        @Override
        public void onActivityStarted(Activity activity) {
            setTopActivityWeakRef(activity);
        }

        @Override
        public void onActivityResumed(Activity activity) {
            setTopActivityWeakRef(activity);
        }

        @Override
        public void onActivityPaused(Activity activity) {

        }

        @Override
        public void onActivityStopped(Activity activity) {

        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

        }

        @Override
        public void onActivityDestroyed(Activity activity) {
            sActivityList.remove(activity);
        }
    };

    private xjzUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    /**
     * 初始化工具类
     *
     * @param app 应用
     */
    public static void init(@NonNull final Application app) {
        xjzUtils.sApplication = app;
        app.registerActivityLifecycleCallbacks(mCallbacks);
    }

    /**
     * 获取Application
     *
     * @return Application
     */
    public static Application getApp() {
        if (sApplication != null) return sApplication;
        throw new NullPointerException("u should init first");
    }

    private static void setTopActivityWeakRef(Activity activity) {
        if (sTopActivityWeakRef == null || !activity.equals(sTopActivityWeakRef.get())) {
            sTopActivityWeakRef = new WeakReference<>(activity);
        }
    }
}
2.在Application中初始化。

/**
 *初始化APP
 */
public class CreateApp extends Application {
    private static Context mContext;
    public static Gson gsonInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        // 异常信息初始化
        xjzUtils.init(this);
        CrashUtils.init(Environment.getExternalStorageDirectory().getAbsolutePath());
    }
}
3.在AndroidManifest.xml中赋值

<application
        android:name=".application.MyApp"
        android:allowBackup="true"
        android:hardwareAccelerated="false"
        android:icon="@mipmap/android_template"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/TranslucentTheme">
写完上面的程序之后,当程序发生异常错误时,就可以捕获了。

4.将异常信息上传到服务器。

思路:当异常信息发生后,将异常信息保存到手机上。每次发生异常时,都会添加到Exception.txt文件中。在我们需要上传异常文件的地方,首先判断异常文件是否存在,然后请求服务器上传文件。上传成功之后可以及时将异常文件从客户手机中删除。

上传文件的方法:我是封装的xutils这个联网框架:

 public static <T> Cancelable uploadCrashFile(String url, String path,
                                                 CommonCallback<T> callback) {
        RequestParams params = new RequestParams(url);
        params.setHeader("Content-Type", "application/json;charest=utf-8");
        params.setMultipart(true);
        params.addBodyParameter("files", new File(path), "*/*", path);
        Cancelable cancelable = x.http().post(params, callback);
        return cancelable;
    }

//我是在主界面上传异常信息的。判断是否要上传

String filePath = Environment.getExternalStorageDirectory().
                getAbsolutePath() + File.separator + "Exception.txt";
        if (new File(filePath).exists()) {
            uploadCrash(filePath);
        }
上传文件

 private void uploadCrash(String fullPath) {
        HttpUtil.uploadCrashFile(UrlConst.UPLOADCRASH, fullPath, new MyCallBack<String>() {
            @Override
            public void onSuccess(String result) {
                super.onSuccess(result);
                // {"success":true,"code":"","message":"上传成功","data":"appuploadFiles/file/Exception.txt"}
                JSONObject jsonObject = null;
                try {
                    jsonObject = new JSONObject(result);
                    boolean success = jsonObject.getBoolean("success");
                    if (success){
                        File file=new File(filePath);
                        if (file.exists()){
                            file.delete();
                        }
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                super.onError(ex, isOnCallback);
            }
        });
    }
写完上面的就可以将异常文件上传到服务器了。








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值