应用异常完全退出应用

来源:互联网 发布:ipad淘宝不能横屏新版 编辑:程序博客网 时间:2024/06/13 23:33

/*******1.未捕获的异常处理**********/

/**

 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
 *
 * 需要在Application中注册,为了要在程序启动器就监控整个程序。
 */
public class CrashHandler implements UncaughtExceptionHandler {

    public static final String TAG = "CrashHandler";

    // 系统默认的UncaughtException处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    // CrashHandler实例
    private static CrashHandler instance;
    // 程序的Context对象
    private Context mContext;
    // 用来存储设备信息和异常信息
    private Map<String, String> infos = new HashMap<String, String>();

    // 用于格式化日期,作为日志文件名的一部分
    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
    private String sysVersion;
    private String softwareVersion;
    private String phoneSystem;
    private String phoneType;
    private String exceptionInfos;
    private String currentDateAndTime;

    /** 保证只有一个CrashHandler实例 */
    private CrashHandler() {
    }

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

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

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                Log.e(TAG, "error : ", e);
            }
            // 退出程序--
            AppBean.getInstance().exit();
        }
    }
    

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        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();
        exceptionInfos = writer.toString(); //异常信息
        // 收集设备参数信息
        collectDeviceInfo(mContext);

        // 使用Toast来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.",Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }.start();
        // 保存日志文件
        saveCatchInfo2File(ex);
        return true;
    }

    /**
     * 收集设备参数信息
     *
     * @param ctx
     */
    public void collectDeviceInfo(Context ctx) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     
        Date curDate = new Date(System.currentTimeMillis()); //获取当前时间     
        currentDateAndTime = formatter.format(curDate);     
        String date[] = currentDateAndTime.split(" ");
        infos.put("exceptionDate", date[0]); //出现异常的日期
        infos.put("exceptionTime", date[1]); //出现异常的时间
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                softwareVersion = pi.versionName == null ? "null": pi.versionName;
                infos.put("softwareVersion", softwareVersion);  //软件版本
            }
        } catch (NameNotFoundException e) {
            Log.e(TAG, "an error occured when collect package info", e);
        }
         phoneSystem = Build.MODEL;
         infos.put("phoneSystem", phoneSystem); //手机型号
         phoneType = "Android";
         infos.put("phoneType", phoneType);     //手机系统类型
         sysVersion = Build.FINGERPRINT;
         sysVersion = sysVersion.substring(sysVersion.indexOf(":")+1);
         sysVersion = sysVersion.substring(0,sysVersion.indexOf("/"));
         infos.put("sysVersion", sysVersion);  //手机系统版本
        
         SharedPreferences sp = ctx.getSharedPreferences("exceptionLog", Context.MODE_PRIVATE);
         Editor editor = sp.edit();
         editor.putBoolean("haveException", true); //出现异常的日期
         editor.putString("exceptionDate", date[0]); //出现异常的日期
         editor.putString("exceptionTime", date[1]); //出现异常的时间
         editor.putString("softwareVersion", softwareVersion);  //软件版本
         editor.putString("phoneSystem", phoneSystem); //手机系统
         editor.putString("phoneType", phoneType);     //手机型号
         editor.putString("sysVersion", sysVersion);   //手机系统版本
         editor.putString("exceptionInfos", exceptionInfos);   //手机系统版本
         editor.commit();
    }

    /**
     * 保存错误信息到文件中
     *
     * @param ex
     * @return 返回文件名称,便于将文件传送到服务器
     */
    private String saveCatchInfo2File(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();
        exceptionInfos = writer.toString();
        sb.append(exceptionInfos);
        try {
            long timestamp = System.currentTimeMillis();
            String time = formatter.format(new Date());
            String fileName = "crash-" + time + "-" + timestamp + ".txt";
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                String path = "/mnt/sdcard/bocMlife/exceptionLog/";
                File dir = new File(path);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                FileOutputStream fos = new FileOutputStream(path + fileName);
                fos.write(sb.toString().getBytes());
            
                sendCrashLog2PM(path + fileName);      // 发送给开发人员
                fos.close();
            }
            return fileName;
        } catch (Exception e) {
            Log.e(TAG, "an error occured while writing file...", e);
        }
        return null;
    }

    /**
     *  上传文件至Server的方法
     *  @param urlStr           服务器对应的路径
     *  @param serverFileName   上传服务器后在服务器上的文件名称 如:image.jpg
     *  @param uploadFile       要上传的文件路径 如:/sdcard/a.jpg
     */
    public void uploadFile(String urlStr, String serverFileName, File uploadFile) {
        String end = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        try {
            URL url = new URL(urlStr);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setDoInput(true);  //允许输入流
            con.setDoOutput(true); //允许输出流
            con.setUseCaches(false);  //不允许使用缓存
            con.setRequestMethod("POST");  // 设置传送的method=POST
            con.setRequestProperty("Connection", "Keep-Alive"); // setRequestProperty
            con.setRequestProperty("Charset", "UTF-8"); //设置编码
            con.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary);  //设置DataOutputStream
            DataOutputStream ds = new DataOutputStream(con.getOutputStream());
            ds.writeBytes(twoHyphens + boundary + end);
            ds.writeBytes("Content-Disposition: form-data; "+ "name=\"file1\";filename=\"" + serverFileName + "\""+ end);
            ds.writeBytes(end);
            FileInputStream fStream = new FileInputStream(uploadFile);  // 取得文件的FileInputStream
            int bufferSize = 1024; //设置每次写入1024bytes
            byte[] buffer = new byte[bufferSize];
            int length = -1; //从文件读取数据至缓冲区
            while ((length = fStream.read(buffer)) != -1) {  // 将资料写入DataOutputStream中
                ds.write(buffer, 0, length);
            }
            ds.writeBytes(end);
            ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
            fStream.close();
            ds.flush();  
            ds.close();
        } catch (Exception e) {
            
        }
    }
    
    /**
     * 将捕获的导致崩溃的错误信息发送给开发人员
     *
     * 目前只将log日志保存在sdcard 和输出到LogCat中,并未发送给后台。
     */
    private void sendCrashLog2PM(String fileName) {
        if (!new File(fileName).exists()) {
            Toast.makeText(mContext, "日志文件不存在!", Toast.LENGTH_SHORT).show();
            return;
        }
        FileInputStream fis = null;
        BufferedReader reader = null;
        String s = null;
        try {
            fis = new FileInputStream(fileName);
            reader = new BufferedReader(new InputStreamReader(fis, "GBK"));
            while (true) {
                s = reader.readLine();
                if (s == null)
                    break;
                // 由于目前尚未确定以何种方式发送,所以先打出log日志。
                // TODO:将异常信息上传服务器
                Logger.i("info", s.toString());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally { // 关闭流
            try {
                reader.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}






/****************2.退出应用********************/

public class myApplication extends Application {
    /****************  用于退出应用******************/
    // TODO 用于退出应用
        private  static Context mContext;
    private  static myApplication instance;
    private List<Activity> oList;// 用于存放所有启动的Activity的集合
    
        public myApplication(){
        oList = new LinkedList<Activity>();
    }
    @Override
    public void onCreate() {
        super.onCreate();
        //在使用sdk各组件前初始化context信息,传入applicationContext
        mContext  = getApplicationContext();
        // enable cookies
        SDKInitializer.initialize(this);
        //初始化全局异常捕获类
        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(mContext);
        

        
    }
    
    
    
    


    /**
     * 添加Activity
     */
    public void addActivity_(Activity activity) {
        // 判断当前集合中不存在该Activity
        if(oList != null && oList.size()>0){
            if (!oList.contains(activity)) {
                oList.add(activity);// 把当前Activity添加到集合中
            }
        }else if(0 == oList.size()){
            oList.add(activity);
        }
    }

    /**
     * 销毁单个Activity
     */
    public void removeActivity_(Activity activity) {
        // 判断当前集合中存在该Activity
        if (oList.contains(activity)) {
            oList.remove(activity);// 从集合中移除
            activity.finish();// 销毁当前Activity
        }
    }

    /**
     * 销毁所有的Activity
     */
    public void removeALLActivity_() {
        // 通过循环,把集合中的所有Activity销毁
        if(oList != null && oList.size() > 0){
            for (Activity activity : oList) {
                activity.finish();
            }
        }
        System.exit(0);
        System.gc();
    }
    
    /**
     * 单例模式中获取唯一的appBean实例
     * @return
     */
    public static AppBean getInstance(){
        if(instance == null){
            instance = new AppBean();
        }
        return instance;
    }
    /**
     * 用于崩溃,被动退出应用
     */
    public void exit(){
        removeALLActivity_();
    }
    /****************用于退出应用******************/
}


/*****************3.主动退出应用*****************/

//在base类中,调用addActivity方法

    private BaseActivity oContext;

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

  oContext = this;// 把当前的上下文对象赋值给BaseActivity
        addActivity();// 调用添加方法

 }

    // 添加Activity方法
    public void addActivity() {
//        appBean.addActivity_(oContext);// 调用myApplication的添加Activity方法
        AppBean.getInstance().addActivity_(oContext);
    }

这就完成退出应用了,另一种发送广播退出应用的方法,在activity调用正常,在cranshHandler中调用,baseActicrt中收不到广播,所以没用!

不过大家也可以做为参考,

1、在base类中进行广播注册,

    protected  MyBaseActiviy_Broad oBaseActiviy_Broad;

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

       //动态注册广播
        oBaseActiviy_Broad = new MyBaseActiviy_Broad();
        IntentFilter intentFilter = new IntentFilter("com.xx.xxt.BaseActivity");
        registerReceiver(oBaseActiviy_Broad, intentFilter);
    
    }

    /**
        //定义一个广播-用于销毁所有activity
     * @author Howe
     *
     */
    public  class MyBaseActiviy_Broad extends BroadcastReceiver {

        public void onReceive(Context arg0, Intent intent) {
            //接收发送过来的广播内容
            int closeAll = intent.getIntExtra("closeAll", 0);
            if (closeAll == 1) {
                finish();//销毁BaseActivity
            }
        }
        
    }

2、在另一个类中发送广播

    /**
     * 用于主动退出应用
     * @param context
     */
    public static void exitApp (Context context){
        Intent intent = new Intent("com.xx.xxt.BaseActivity");
        intent.putExtra("closeAll", 1);
        context.sendBroadcast(intent);//发送广播
    }

原创粉丝点击