笔记 intent隐式启动的两个注意事项

隐式启动activity:
intent进行匹配时需要3个属性, action category 和data,
通常情况下首先在清单文件里注册

        <activity android:name="ActivityTest">
             <intent-filter>
                 <action android:name="com_activity_test"/>
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:scheme="xxx"/>
              </intent-filter>           
        </activity>

action 和 category 这两个属性必须要有, data可以省略.

说一下<category android:name="android.intent.category.DEFAULT" /> 这个属性的作用:
当使用隐式启动activity时,若不加这条属性会报如下错误:
   // android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com_activity_test }

一般来说如果不指定category,只要匹配到对应的action就应该查找到对应的activity,但真是的原因是,android默认会给intnet加上一个CATEGORY_DEFAULT,
这样的话,如果当前注册的activity中没有"android.intent.category.DEFAULT"这个category属性,intnet匹配时就无法找到对应的activity.

查看源码,当我们使用 intent.resolveActivity(getPackageManager()) 进行检查时:
/frameworks/base/core/java/android/content/Intent.java
 public ComponentName resolveActivity(PackageManager pm) {
        if (mComponent != null) {
            return mComponent;
        }
    //{@link PackageManager#resolveActivity} with the "defaultOnly" parameter true MATCH_DEFAULT_ONLY 值为 1
        ResolveInfo info = pm.resolveActivity(this, PackageManager.MATCH_DEFAULT_ONLY); 
        if (info != null) {
            return new ComponentName(
                    info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.name);
        }
        return null;
    }

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
/** if using an implicit Intent (without an explicit ComponentName
  * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY} only flag
  *
  * @param flags Additional option flags.  The most important is
  * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
  * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
*/
public abstract ResolveInfo resolveActivity(Intent intent, int flags);

通过注释可以看出resolveActivity方法会默认添加MATCH_DEFAULT_ONLY的flags,用来限制查找那些添加了android.content.Intent#CATEGORY_DEFAULT属性的
activites,所以你注册的activity没有添加此属性是无法被找到的.

隐式启动service:
在5.0之前可采用如下方式来启动:
注册
  <service android:name="ServicesTest">
        <intent-filter>
            <action android:name="com_services_test"/>
        </intent-filter>            
   </service>
启动
   Intent sendIntent = new Intent();
   sendIntent.setAction("com_services_test");
   startService(sendIntent);

在5.0之后会报如下错误:
//java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com_services_test }

通过报错log发现原因如下:
/frameworks/base/core/java/android/app/ContextImpl.java
   private void validateServiceIntent(Intent service) {
        if (service.getComponent() == null && service.getPackage() == null) { //判断ComponentName 是否为空
            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                IllegalArgumentException ex = new IllegalArgumentException(
                        "Service Intent must be explicit: " + service);
                throw ex;
            } else {
                Log.w(TAG, "Implicit intents with startService are not safe: " + service
                        + " " + Debug.getCallers(2, 3));
            }
        }
    }
在5.0之前只是会报一个警告,可以正常编译运行,但是在5.0之后,系统不允许使用隐式来启动service,直接抛出异常,其实隐式启动service是非常不安全的.

根据判断的条件只要ComponentName不为null即可,所以可通过下面方法来启动一个service:

        Intent intent = new Intent();
	ComponentName componentName = new ComponentName(getPackageName(),ServicesTest.class.getName());
	intent.setComponent(componentName);
	startService(intent);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值