Android Intent详解
一、简介
在Android OS中,隐式Intent可以启动其它应用Activity。在显示Intent中,指定要启动的Activity类,OS会负责启动它。在隐式Intent中,描述清楚要完成的任务,OS会找到合适的应用,并在其中启动相应的Activity。
二、典型隐式Intent的组成
- 一个隐式Intent的主要组成部分:
1. 要执行的操作
通常以Intent类中的常量表示。例如,要访问查看某个URL,可以使用Intent.ACTION_VIEW;要发送邮件,可以使用Intent.ACTION_SEND。
2. 要访问数据的位置
可能是设备以外资源,如某个网页UIL,也可以是指向某个文件的URI,或者是指向ContentProvider中某条记录的某个内容URI(Content URI)。
3. 操作涉及的数据类型
指的是MIME形式的数据数据,如text/htme或audio/mpeg3。如果一个Intent包含某类数据的位置,那么通常可以从中推测出数据类型。
4. 可选类别
如果操作用于描述具体要做什么,那么类别通常用来描述我们何时、何地或者说如何使用某个Activity的。Android的android.intent.category.LAUNCHER类别表明,activity应该显示在顶级应用启动器中。而android.intent.category.INFO类别表明,虽然Activity向用户显示包信息,但它不应该显示在启动器中。
PS:一个Intent由四方面组成,分别为:动作(action)、 操作类别(category)、数据、数据类型。
动作(action):通过Intent类,指定activity做什么操作,比如:发送邮件。
类别(category):动作的描述,选择用哪些activity来完成任务。
数据:Intent传递的数据。
数据类型(MIME):传递数据的格式。
示例:
一个用来查看某个网址的简单隐式Intent会包括一个Intent.ACTION_VIEW操作,以及某个具体URL网址的URI数据。
基于以上信息,操作系统将启动适用应用的适用Activity(如果有多个适用应用可选,用户可自行如何选择)。
通过配置文件中的Intent过滤器设置,activity会对外宣称自己是适合处理ACTION_VIEW的Activity。如果是开发一款浏览器应用,为响应ACTION_VIEW操作,需要在Activity声明中包含以下过滤器:
1 <activity 2 android:name=".BrowserActivity" 3 android:label="@string/app_name"> 4 <intent-filter> 5 <action android:name="android.intent.action.VIEW"/> 6 <category android:name="android.intent.category.DEFAULT"/> 7 <data android:scheme="http" android:host="www.baidu.com"/> 8 </intent-filter> 9 </activity>
DEFAULT类别必须明确地在Intent过滤器中进行设置。Intent过滤器中的action元素告诉OS,activity能够处理指定的任务,DEFAULT类别告诉OS,activity愿意处理某项任务。
DEFAULT类别实际隐含添加到了几乎每一个隐式Intent中。(唯一的例外是LAUNCHER类别)
隐藏Intent启动OS中其它应用的与此Intent相匹配的activity:
1 Button choose = (Button)v.findViewById(R.id.choose_btn); 2 choose.setOnClickListener(new Button.OnClickListener() 3 { 4 @Override 5 public void onClick(View v) 6 { 7 Intent i = new Intent(Intent.ACTION_SEND); 8 i.setType("text/plain"); 9 i.putExtra(Intent.EXTRA_TEXT, "Choose"); 10 i.putExtra(Intent.EXTRA_SUBJECT, "Choose Suspect"); 11 i = Intent.createChooser(i, "Chooser"); 12 startActivity(i); 13 } 14 });
使用隐式Intent,通过startActivity(...)方法启动activity,启动外部应用,隐式的将类别附给Intent,启动的activity是应用中manifest文件中,对activity配置了DEFAULT类别。实际上调用startActivity(Intent)方法意味着“启动与发送的隐式Intent相匹配的默认Activity”。
前面说过,MAIN/LAUNCHER intent过滤器并不一定包含CATEGORY DEFAULT类别,因此,是否可以与通过startActivity(Intent)方法发送的隐式Intent匹配,谁也说不准。
在设备已经安装的应用中,使用隐式Intent对象,匹配相同类别的应用中的Activity。因为,不能确保Intent过滤器,一定设置了GATEGORY DEFAULT类别,所以,通过包管理器查找,PackageManager类设备已经安装应用的包管理器。
示例:通过PackageManager获取已安装的应用中与Intent相匹配的Activity列表:
1 // Intent对象,设置动作 2 Intent startIntent = new Intent(Intent.ACTION_MAIN); 3 // 设备Intent对象的操作类别 4 startIntent.addCategory(Intent.CATEGORY_LAUNCHER); 5 // 获取PackageManager对象 6 PackageManager pm = getActivity().getPackageManager(); 7 // 获取Activity列表,及相关应用包的信息和Activity信息 8 List<ResolveInfo> activities = pm.queryIntentActivities(startIntent, 0);
对象获取的Activity列表排序,按字母排序:
1 // new Comparator<T>(){}此写法是对Comparator类的compare(...)覆盖重写 2 Collections.sort(activities, new Comparator<ResolveInfo>() 3 { 4 // 重写排序方法的实现 5 @Override 6 public int compare(ResolveInfo lhs, ResolveInfo rhs) 7 { 8 // 获取PackManager对象 9 PackageManager pm = getActivity().getPackageManager(); 10 // loadLabel(...)方法是按字母排序 11 int ret = String.CASE_INSENSITIVE_ORDER.compare(lhs.loadLabel(pm).toString(), 12 rhs.loadLabel(pm).toString()); 13 return ret; 14 } 15 });
在列表ListView上显示应用名称列表:
1 // 使用匿名内部类,创建适配器。在列表中显示 2 ArrayAdapter<ResolveInfo> adapter = new ArrayAdapter<ResolveInfo>(getActivity(), 3 android.R.layout.simple_list_item_1, activities) 4 { 5 // 覆盖基类的getView(...)方法 6 @Override 7 public View getView(int pos, View converView, ViewGroup parent) 8 { 9 View v = super.getView(pos, converView, parent); 10 // 获取PackageManager对象 11 PackageManager pm = getActivity().getPackageManager(); 12 // 获取指定包的相关信息 13 ResolveInfo info = getItem(pos); 14 TextView tv = (TextView)v; 15 tv.setText(info.loadLabel(pm)); 16 tv.setTextColor(Color.rgb(255, 64, 129)); 17 18 return v; 19 } 20 }; 21 // 指定适配器对象 22 setListAdapter(adapter);
PS:ArrayAdapter<T>对象创建就使用的匿名内部类。
通过显示Intent对象启动指定的Activity:
1 @Override 2 public void onListItemClick(ListView listView, View view, int pos, long id) 3 { 4 // 获取选定应用的应用信息,包括包信息及Activity信息 5 ResolveInfo resolveInfo = (ResolveInfo)listView.getAdapter().getItem(pos); 6 // 获取指定的Activity信息 7 ActivityInfo activityInfo = resolveInfo.activityInfo; 8 9 if (null == activityInfo) 10 { 11 return; 12 } 13 // 创建显示的Intent对象 14 Intent i = new Intent(Intent.ACTION_MAIN); 15 // 指定要启动的Activity信息,包名和Activity名 16 i.setClassName(activityInfo.applicationInfo.packageName, activityInfo.name); 17 startActivity(i); 18 }