红米Note调用系统相机拍照后应用崩溃问题分析解决

这几天突然发现红米Note手机只要调用系统相机进行拍照时,我的应用必定会崩溃。这个问题折腾了好久才解决,现在记录下问题跟踪解决的过程和方法。(红米Note手机的系统太坑爹了%>_<%)

解决办法请直接从第7条开始看,1~5条为我的问题处理过程,第6条为问题原因分析。

1. 问题刚出现的时候,当然是想调试,在调用系统相机拍照的前后代码出打好断点准备调试,结果发现这段代码没有任何异常(其实想想也是正常的,因为其他手机都是好的,唯独红米Note有问题,要是这段代码有问题,其他手机应该也有问题,这一步真是多余)

2.既然暂时找不到系统崩溃时代码的出错行,那只有去查看系统崩溃日志了(这里提一下,应用开发时一定要通过UncaughtExceptionHandler捕获系统未处理的系统,并在uncaughtException(Thread thread, Throwable ex)方法中记录异常日志,不然应用运行中崩溃了完全无法快速准确的定位错误信息)。

3.当我打开日志文件一看,傻眼了,这日志记录完全无法定位错误信息(日志记录不完全,也没有准确记录,没有记录出错的代码行以及相关的方法运行栈信息)。没办法,我只能想办法重新改写记录日志的方式,下面是我记录异常信息日志的方法,可以准确的定位到出错的代码行和方法,以及其运行前后的方法栈信息:

public void uncaughtException(Thread thread, Throwable ex) {
	String logdir = logPath ;  
        File file = new File(logdir);  
        boolean mkSuccess;  
        if (!file.isDirectory()) {  
            mkSuccess = file.mkdirs();  
            if (!mkSuccess) {  
                mkSuccess = file.mkdirs();  
            }  
        } 
        
        StringBuffer sb = new StringBuffer();
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        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();  
        String result = writer.toString();  
        sb.append(result);  
        try {  
            String time = formatter.format(new Date());
            String logFile = logdir + File.separator + time + ".log";
            
            FileOutputStream fos = new FileOutputStream(logFile);  
            fos.write(sb.toString().getBytes());
            fos.close();
        } catch (Exception e) {  
            Log.e(TAG, "an error occured while writing file...", e);  
        }  
    
	if (!handleException(ex) && mDefaultHandler != null) {
	    mDefaultHandler.uncaughtException(thread, ex);
	} else {
	    try {
	        Thread.sleep(1000);
	    } catch (InterruptedException e) {
	        Log.e(TAG, "Error : ", e);
	    }
        }
	android.os.Process.killProcess(android.os.Process.myPid());
	System.exit(10);
}

4.重新运行了几次,发现每次出错的地方竟然还不一样(但每次出错都是空指针异常引起的),有时候是调用系统相机的那个Activity的onCreate方法调用的时候出现空指针,有时候是调用系统相机的前面一个Activity的onCreate方法中出现空指针(假设界面A跳到界面B,在B中调用系统相机,出错的时候A和B中的onCreate方法里都有空指针异常信息),知道出现错误的代码行数这救你好办了,赶紧打好断点准备调试,结果竟然发现不管怎么操作,代码就是不进断点。

5.代码不进断点,就没法找到问题根源,只能分析代码寻求解决办法了,我在出现空指针错误的地方加上非空判断,重新运行发现这几个地方虽然不出错了,但是又在其他的地方出现空指针异常了,经过分析发现所有出现空指针的地方都是我的自定义Application里面的某几个static引用型变量为空了。分析到这里,在加上前面的代码不进断点以及空指针出现onCreate方法中,猜测是不是应用直接被系统回收了。

6.调用系统相机的时候,应用被系统回收(Application、处于后台和前台的Activity都被销毁,静态变量全部消失),此时拍照完成之后重新恢复创建Activity(重新创建的时候,手机与编辑器的调试状态肯定就断掉了,因此通过onCreate重新创建Activity时无法进到断点),重新调用onCreate时,因为该方法中有用到自定义Application里的static变量(此时已被销毁),所以会出现空指针异常。至于为什么界面A和B对应的onCreate方法中都会出现空指针,那是因为B调用系统相机完成之后会重新创建,创建失败之后按照Activity的栈顺序会接着创建界面A,而A中的onCreate方法里也用到了自定义Application里的static变量,所以也出现了空指针。

7.既然知道了问题原因,那就来寻求解决办法,我在onSaveInstanceState(Bundle outState)方法中保存当前Activity里操作过的所有变量信息,然后在重新创建该Activity时通过onRestoreInstanceState(Bundle savedInstanceState)方法来恢复这些数据信息(这两个方法的执行机制请参考我的另外一篇文章:Android基础篇之:Activity生命周期),同时在onCreate中用到自定义Application里的static变量的地方进行非空判断(为空的时候进行重新初始化),进过这一系列的代码处理之后,再次运行正常,完美解决问题。

8.不过在步骤7中解决问题时发现,在处理应用被回收重新创建时要注意如下几点:

  1. Activity里用户操作的所有数据全部需要保存
  2. Activity中第一次初始化时获取到的变量也需要保存
  3. 用户登陆后所有拥有的相关权限也需要进行处理保存
  4. 数据恢复时要考虑当前Activity引用的其他Activity或Application里面的变量的再次初始化
  5. 所有自定义对象都最好能被序列化,否则无法进行状态保存
  6. 尽量少用static类型的变量
  7. 有些服务能不在Application中初始化,最好不要在Application中初始化。
  8. 在Application中定义的变量最后都在Application中进行初始化创建,不要部分在Application进行初始化,部分在其他的Activity里进行初始化
  9. 应用开发时要考虑到应用被回收的情况,以便真正被回收后能方便的解决(虽然应用被回收的几率很低,但是不排除某些坑爹的手机很容易被回收,就像红米Note一样)。


欢迎访问我的个人博客:http://ittiger.cn/

write by laohu

2015年10月22日

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值