Intent
Intent:执行的操作以及用于这个操作的数据和其它属性,相当于网页中的url。如下图所示,在打开一个应用的时候,Intent是作为一个重要的数据载体的。
下面来看看 Android OS 如何根据 Intent 来找到满足触发条件的 Activity,Service 或是Broadcast Receiver. 借用 SQL 数据库的概念可以更好的理解。
SELECT (Activitives|Services|Broadcast Receivers) AS Target FROM (List in AndroidManifest.xml) WHERE Intent Meet Target’s (Intent Filter)
从 AndroidManifest.xml 中定义的 Activities,Services 和 Broadcast Receiver 列表中查找符合 Intent 条件的 Activities,Services,或是 Broadcast Receivers
所有能活被激活的 Activity,Service 和 Broadcast Receiver 都必须在 AndroidManifest.xml,否则 Android OS 无法查询到该目标,相当于数据库中无记录,即使你在代码中定义了该Activity,Service 或 Broadcast Receiver
开启一个Activity的流程:
(1)Intent intent = new Intent();
(2)intent.setAction("....");
(3)intent.addCategory("....");
(4)intent.setData(Uri.parse("...."));//设置data的scheme、host、path条件
(5)intent.setDataAndType(Uri.parse(""),String type);//同时设置data的scheme、host、path、type条件
(6)startActivity(intent);
priority
网上很多文章中都写到这样一种方法,提高service的优先级别可以用Android:priority = “1000” 的方式来提供servie 的存活时间。其实这是一种没有效果的做法
google文档是这样解释的:链接
1. 优先级的概念用于描述控件的 intent的filter的类型。 这个属性只对activity 和 receivers 是有意义的。
2. 隐式调用activity的情况下: 如果多个activity 满足响应 的条件, 系统只会触发 priority 高的那个activity。
3. 有序广播发出的情况下:如果多个receiver满足响应的条件,系统会优先触发prioriyt搞的那个receiver。
4. priority 必须是整数,默认是0 范围是[-1000, 1000], 默认为0,值越大优先级越高
action
来指定响应的动作名。动作名必须是独一无二的字符串,一个好的习惯是使用基于 Java 包的命名方式的命名系统。最常见的就是:
<action android:name="android.intent.action.MAIN"/>
我们也可以自定义Action,比如com.flysnow.intent.ACTION_ADD,定义Action的时候最好能表明意思,
要做什么,这样我们的Intent中的数据才好填充。
Intent对象的getAction()可以获取动作,使用setAction()可以设置动作
使用隐式Intent出现android.content.ActivityNotFoundException: No Activity found to handle Intent
Category
Category指定了用于处理Intent的组件的类型信息
<category android:name="android.intent.category.DEFAULT"/> <!--此句一般都要加 -->
最常见的:
<category android:name="android.intent.category.LAUNCHER"/>
一个Intent可以添加多个Category,使用addCategory()方法即可,使用removeCategory()删除一个已经添加的类别。Android的Intent类里定义了很多常用的类别,可以参考使用。
Data
Data,其实就是一个URI,用于执行一个Action时所用到的数据的URI和MIME。
不同的Action有不同的数据规格,比如ACTION_EDIT动作,数据就可以能包含一个用于编辑文档的URI,如果是一个ACTION_CALL动作,那么数据就是一个包含了tel:6546541的数据字段,所以上面提到的自定义Action时要规范命名。数据的URI和类型对于Intent的匹配是很重要的,Android往往根据数据的URI和MIME找到能处理该Intent的最佳目标组件。
每个data定义一个URI和数据类型(MIME),URI由4个属性来定义,分别是android:scheme,android:host,android:port,android:path.这个四个属性构成如下格式的URI: scheme://host:port/path 如:content://com.flysnow.intent:8080/show/view。其中content就是scheme,com.flysnow.intent就是host,8080就是port,show/view就是path…如果有经常使用ContentProvider的应该熟悉。。我们经常定义的authority不就是host+port吗?还有这几个元素都是可选的,但是不是随便用就可以的,port要依赖于host,没有host,port就会被忽略,不起作用,同样,如果要使用host+port(authority)就必须指定scheme。而path则依赖于scheme和authority。。
还有一个很重要的类型就是mimeType,这个属性用于指定内容的类型,也就是这个组件可以处理哪些类型的内容。。如text/plain表示无格式文本类型,mimeType也支持通配符,使用text/*则表示所有文本类型。通过使用它,你可以很方便的开发出关联打开诸如txt文件,pdf文件的应用。后面的两个自理将会演示txt文件查看器,图片查看器的例子。。MIME可以参考http://www.w3school.com.cn/media/media_mimeref.asp。这里有所有的内容类型的定义。
注意:
情况1:
<data
android:host="www.xiazdong.com"
android:scheme="xiazdong"/>
intent.setData(Uri.parse("xiazdong://www.xiazdong.com/xia"));
情况2:
在<data>中多了一个android:mimeType="text/*",此时不能使用intent.setData,而要使用intent.setDataAndType();
<data
android:host="www.xiazdong.com"
android:scheme="xiazdong" android:mimeType="text/*"/>
- intent.setDataAndType(Uri.parse("xiazdong://www.xiazdong.com/xia"), "text/plain"); //匹配了text/*
注意的点
- Action一般设置一个,Category可以设置多个。
- 使用隐式Intent必须要加上,打开的时候不用add,因为每个Intent默认加上了
<category android:name="android.intent.category.DEFAULT"/>
例子
一、
xml定义:
<activity android:name=".PackageManagerDemo.PackagerManagerActivity">
<intent-filter android:priority="0">
<action android:name="com.bourne.ACTION_PACKAGEMANAGER"/>
<category android:name="android.intent.category.DEFAULT"/> <!--此句一般都要加 -->
<category android:name="com.bourne.CATEGORY_PACKAGEMANAGER"></category>
<data
android:host="www.xiazdong.com"
android:mimeType="text/plain"
android:scheme="xiazdong">
</data>
</intent-filter>
</activity>
启动Activity:
public void onClickAction(View view) {
String ACTION_PACKAGEMANAGER="com.bourne.ACTION_PACKAGEMANAGER";
String CATEGORY_PACKAGEMANAGER="com.bourne.CATEGORY_PACKAGEMANAGER";
Intent intent = new Intent();
intent.setAction(ACTION_PACKAGEMANAGER);
intent.addCategory(CATEGORY_PACKAGEMANAGER);
intent.setDataAndType(Uri.parse("xiazdong://www.xiazdong.com/xia"), "text/plain"); //匹配了text/*
startActivity(intent);
}
被打开的Activity:
//获取该Activity对应的Intent的Action属性
String action=getIntent().getAction();
//显示Action属性
Logout.e("Action为:"+action);
//获取该Activity对应的Intent的Category
Set<String> cates=getIntent().getCategories();
//显示Category属性
Logout.e("Category属性为:"+cates);
效果:
二、
Uri、setAction、setData通过按钮启动其他程序:
<uses-permission android:name="android.permission.CALL_PHONE"/>
//通过隐式意图启动其他程序
private void btn2Click()//浏览某个网页
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data = Uri.parse("http://www.163.com");
intent.setData(data);
startActivity(intent);
}
private void btn1Click()//通过按钮启动拨号
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);//自动拨号需要设置权限,CALL_PHONE
//intent.setAction(Intent.ACTION_DIAL);//跳转到拨号界面
//Uri.fromFile(file)打开某个文件
Uri data = Uri.parse("tel:110");//号码的uri标示符格式
intent.setData(data);
startActivity(intent);
}
打开另外一个项目:
Uri data = Uri.parse("http://www.163.com/note");
intent.setDataAndType(data, "mnt/png");
startActivity(intent);
<intent-filter>
<action android:name="com.example.aex60" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" android:host="www.163.com" android:path="/note"
android:mimeType="mnt/png"/>
</intent-filter>
三、打电话
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class CallActivity extends Activity {
private EditText etPhone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call);
etPhone = (EditText) findViewById(R.id.etPhone);
}
// ACTION_CALL方式拨打电话(直接拨打)
public void onClickActionCall(View v) {
//这里的Intent.ACTION_CALL实际就是一个特定的字符串,
//ACTION_CALL = "android.intent.action.CALL",
//告诉系统我要直接拨号了。
call(Intent.ACTION_CALL);
}
// ACTION_DIAL方式拨打电话(打开拨号界面)
public void onClickActionDial(View v) {
//同理,这里的Intent.ACTION_DIAL也是一个特定的字符串
//ACTION_DIAL = "android.intent.action.DIAL"
//告诉系统我要打开拨号界面,并把要拨的号显示在拨号界面上,由用户决定是否要拨打。
call(Intent.ACTION_DIAL);
}
private void call(String action){
String phone = etPhone.getText().toString();
if(phone!=null&&phone.trim().length()>0){
//这里"tel:"+电话号码 是固定格式,系统一看是以"tel:"开头的,就知道后面应该是电话号码。
Intent intent = new Intent(action, Uri.parse("tel:" + phone.trim()));
startActivity(intent);//调用上面这个intent实现拨号
}else{
Toast.makeText(this, "电话号码不能为空", Toast.LENGTH_LONG).show();
}
}
}
参考文章: