Android开发中的异常统一处理

                                                              Android开发中的异常统一处理

实际开发中为了防止程序异常奔溃,而使得开发人员不知道奔溃原因,且影响用户体验:所以我们应该在app中统一处理异常,拦截异常信息,上报服务器。

一自定义异常拦截实现Thread.UncaughtExceptionHandler重写拦截异常方法

public class CrashHandler implements Thread.UncaughtExceptionHandler{

    public static final String TAG = "CrashHandler";
    //系统默认的UncaughtException处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    //CrashHandler实例
    private static volatile CrashHandler instance;
    //程序的Context对象
    private Context mContext;
    //创建警告对话框
    private   Dialog dialog;
    //异常文件存储路径
    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/myExceptionCatch/log/";
    //异常文件存储名字
    private static final String FILE_NAME = "catch";
    //异常文件存储后缀
    private static final String FLIE_NAME_SUFFIX = ".log";
    /**
     * 无参构造
     */
    public CrashHandler() {

    }

    /**
     * 获取CrashHandler实例 ,单例模式
     */
    public static CrashHandler getInstance() {
        if (instance == null)
            synchronized (CrashHandler.class) {
                if (instance == null) {
                    instance = new CrashHandler();
                }
            }
        return instance;
    }

    /**
     * 初始化
     */
    public void init(Context context) {
        mContext = context.getApplicationContext();
        //获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 程序崩溃会被该方法捕获到   在此添加逻辑是自己处理还是交给系统异常处理
     * handleException是自己处理异常的方法
     */
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if (!handleException(throwable) && mDefaultHandler != null) {
            //如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, throwable);
        } else {
            Log.d("flag","----------------获取到异常了else");
//            try {
//                Thread.sleep(3000);
//            } catch (InterruptedException e) {
//                Log.e(TAG, "error : ", e);
//            }
//            //退出程序
//            android.os.Process.killProcess(android.os.Process.myPid());
//            System.exit(1);
        }
    }

    /**
     * 添加自己处理异常的方法    在这里收集收集的设备信息   保存异常文件
     */
    private boolean handleException(final Throwable ex) {
        if (ex == null || mContext == null) {
            return false;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                try {
                    //先获取手机的基本信息  将异常信息一起写入文件   上传服务器
                    savcExceptionToSDCard(ex);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_SHORT).show();
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    Log.e(TAG, "error : ", e);
                }
                //退出程序
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(1);
                Looper.loop();
            }
        }).start();
        return true;
    }

    /**
     *  出现异常写到内存卡上   然后读文件上传到服务器
     */
    private void savcExceptionToSDCard(final Throwable ex) throws IOException {
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Log.w("TAG", "sdcard unmounted,skip save exception");
        }
        File dir = new File(PATH);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        long current = System.currentTimeMillis();
        final String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current));
        File file = new File(PATH + FILE_NAME + FLIE_NAME_SUFFIX);
        try {
            //写入时间
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(time);
            //写入手机信息
            savePhoneInfo(pw, ex);
        } catch (Exception e) {

        }
        //上传服务器
        uploadToServer(file);
    }

    /**
     *   写入手机基本信息   异常机型   异常原因等
     */
    private void savePhoneInfo(PrintWriter pw, Throwable ex) throws PackageManager.NameNotFoundException {
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
        pw.print("App version: ");
        pw.print(pi.versionName);
        pw.print('_');
        pw.println(pi.versionCode);

        //Android版本号
        pw.print("OS Version: ");
        pw.print(Build.VERSION.RELEASE);
        pw.print(" _ sdk: ");
        pw.println(Build.VERSION.SDK_INT);

        //手机制造商
        pw.print("Vendor: ");
        pw.println(Build.MANUFACTURER);

        //手机型号
        pw.print("Model: ");
        pw.println(Build.MODEL);

        //CPU架构
        pw.print("CPU ABI : ");
        pw.println(Build.CPU_ABI);
        pw.println();
        //异常信息
        ex.printStackTrace(pw);
        pw.close();
    }
    /**
     * 读取文件转换成字符串
     * 参数一 输入文件file
     *
     * @return
     */
    public String readFromFile(File file) {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(file));
            StringBuilder stringBuilder = new StringBuilder();
            String content;
            while ((content = bufferedReader.readLine()) != null) {
                stringBuilder.append(content);
            }
            return stringBuilder.toString();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private void uploadToServer(File file) {
        String ec=readFromFile(file);
        OkhttpUtils.upEcInfo(ec,"服务器的url");
    }
}

二为了实现app全局监听  在App的application里进行注册

public class MyApplication extends Application {
    private static MyApplication instance;
    @Override
    public void onCreate() {
        super.onCreate();
        //获取CrashHandler实例并初始化CrashHandler
        CrashHandler.getInstance().init(getApplicationContext());
    }
    public static MyApplication getInstance() {
        if (instance == null) {
            instance = new MyApplication();
        }
        return instance;
    }
}

三清单文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.wbxu.myexceptiondemo">
     <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

四上传工具本文使用okhttp

public class OkhttpUtils {
    //上传字符串
    private static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
    public static OkHttpClient mOkHttpClient;
    //    public static String SessionKey;
    // 1静态代码块初始化OkHttpClient
    static {
        // 2创建OkHttpClient构建器
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 3设置网络的链接超时时间
        builder.connectTimeout(50, TimeUnit.SECONDS);
        // 4使用构建器 构建出OkHttpClient
        mOkHttpClient = builder.build();
    }
    //获取OkHttpClient的方法
    public static OkHttpClient getOkHttpClient(){
        return mOkHttpClient;
    }
    public static void upEcInfo(String ecInfo,String url){
        RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, ecInfo);
        //4创建请求对象
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        //5执行请求      enqueue异步请求
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("Flag","------上传异常失败错误信息为:e.getLocalizedMessage() = " + e.getLocalizedMessage());
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String strInfo = response.body().string();

                Log.d("flag", "----------------门店检查图片信息上传返回的请求体为" + strInfo);
            }
        });
    }
}

五mainActivity里创建异常进行测试

public class MainActivity extends AppCompatActivity {
    private TextView ecTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ecTextView= (TextView) findViewById(R.id.tv);
    }
    /**
     *  制造异常
     */
    public void buildEc(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ecTextView.setText("异常捕获");
            }
        }).start();
    }
}

源码下载:http://download.csdn.net/detail/xuwb123xuwb/9872496





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值