6.2 Activity 相关的异常
Android四大组件,对于应用类App而言,使用最多的是Activity,偶尔会用到Service和BroadCastReceiver,线上关于Actvity的崩溃也是最多的。
对于这些异常,只从字面上分析是远远不够的。它们通常是由外界环境所导致的,比如说找不到一个Activity或Service,有可能是混淆或dex拆分不当导致的。
6.2.1 找不到Activity
异常中的关键字:
android.content.ActivityNotFoundException:No Activity found to handle Intent{…}
发生频率:★★★
出现错误的原因是,URL不是以http开头,代码就会抛出异常:
Uri uri = Uri.parse("www.baidu.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent);
这类Crash还有一种发生的场景是,当我们要打开SD卡上的一个HTML页面时,没有为Intent指定打开该HTML页面所需要的浏览器,如下所示:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("file:// sdcard/101.html")); // 此处指定系统自带浏览器包名和 Activity名称 . // intent.setClassName("com.android.browser", // "com.android.browser.BrowserActivity"); startActivity(intent);
就是因为指定浏览器的语句被注释了,所以就崩溃了。我最初想重现这个异常的时候,因为手机上装了爱奇艺App,所以即使没有指定系统自带的浏览器,也会弹出爱奇艺的播放器。只有卸载了爱奇艺App,才会复现该问题。
还有一个原因,如果是调用百度地图的openBaiduMapNavi方法导致的Crash,有可能是手机没有安装百度地图的客户端,而这个方法就是要打开这个客户端。解决方案是判断其是否安装了,没有的话就提示用户有问题要么就干脆不显示。
6.2.2 不能实例化Activity
异常中的关键字:
java.lang.RuntimeException:Unable to instantiate activity ComponentInfo
发生频率:★★★★
这种Crash,通常是因为没有在AndroidManifest.xml清单中注册该activity,或者在创建完activity后,修改了包名或者activity的类名,而配置清单中没有修改,造成不能实例化。
如果还不能解决问题,有可能是系统处于异常状态(关机,内存不足)等,导致部件初始化失败。
6.2.3 找不到Service
异常中的关键字:
java.lang.RuntimeException:Unable to instantiate receiver
发生频率:★★
对于应用类App而言,不可能开发期间没有问题,而发布到线上却发现上述的崩溃,所以我们接下来的讨论也基于此。对于Manifest.xml文件中写错了的类似问题我们就不研究了。
首先检查代码中是否有Class.forName("class1")这样的语句。对于此,ProGuard会将class1混淆,从而就是找不到class1这个类。
6.2.4 不能启动BroadcastReceiver
异常中的关键字:
Unable to start receiver
发生频率:★★
在推送的时候,会和App事先定好协议,点击推送消息就能跳过首页直接进入二级页面,如下所示,我们要在一个BroadcastReceiver中编写如下代码:
Intent intent = new Intent(context, S13Activity.class); intent.putExtra(bundle); intent.setFlags(intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);
使用Activity以外的content来startActivity,比如BroadcastReceiver,就必须指定为Intent.FLAG_ACTIVITY_NEW_TASK,否则就会抛出上述异常信息。
此外,还有类似的一个异常,如下所示:
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK fiag. Zs this really what you want?
众所周知,Context中有一个startActivity方法,Activity继承自Context,重载了startActivity方法。如果使用Activity的startActivity方法,不会有任何限制,而如果使用Context的startActivity方法的话,就需要开启一个新的task,遇到上面那个异常的,都是因为使用了Context的startActivity方法。解决办法是,加一个fiag:
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
这样就可以在新的task里面启动这个Activity了。 [1]
6.2.5 startActivityForResult不能回传
异常中的关键字:
Failure delivering result ResultInfo{who=null,request=0,result=-1
发生频率:★★★
这类问题是startActivityForResult导致的。就是说传回来的key是A,但是却按照B这个key来取值。如下所示:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (resultCode) { case 1: Bundle bundle = data.getExtras(); String number = bundle.getString("number"); if (!("".equals(number))) textview1.setText(number); break; default: break; } }
我们看到,number这个字符串为null时,在执行equal语法时就会崩溃。其实是空指针导致的,但是表现为Failure delivering result ResultInfo的异常。
6.2.6 猴急的Fragment
异常中的关键字:
Fragment not attached to Activity
发生频率:★★★
发生这个异常,是因为Fragment在还没有Attach到Activity时,调用了诸如getResource()这样的方法:
getResources().getString(R.string.app_name);
相应的解决方案是,在获取资源前先使用isAdded方法进行判断,如下所示:
if(isAdded()){ getResources().getString(R.string.app_name); }
isAdd方法是Android系统提供的,它只有在Fragment被添加到所属的Activity后才会返回true。
[1] 关于这个Crash的更多信息请参见:http://www.it165.net/pro/html/201406/15547.html。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论