返回介绍

6.2 Activity 相关的异常

发布于 2024-08-17 23:46:12 字数 4047 浏览 0 评论 0 收藏 0

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文