您的位置:首页 > 移动开发 > Android开发

android Intent、pendingIntent机制详解

2015-05-12 16:43 337 查看


什么是Intent

Intent是一种运行时绑定(run-time binding)机制,它能在程序运行过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来完成请求。比如,有一个Activity希望打开网页浏览器查看某一网页的内容,那么这个Activity只需要发出WEB_SEARCH_ACTION给Android,Android就会根据Intent的请求内容,查询各组件注册时声明的IntentFilter,找到网页浏览器的Activity来浏览网页。

Android的三个基本组件——Activity,Service和Broadcast Receiver——都是通过Intent机制激活的,不同类型的组件有不同的传递Intent方式:

1.1 要激活一个新的Activity,或者让一个现有的Activity做新的操作,可以通过调用Context.startActivity()或者Activity.startActivityForResult()方法。

1.2 要启动一个新的Service,或者向一个已有的Service传递新的指令,调用Context.startService()方法或者调用Context.bindService()方法将调用此方法的上下文对象与Service绑定。

1.3 Context.sendBroadcast()、Context.sendOrderBroadcast()、Context.sendStickBroadcast()这三个方法可以发送Broadcast Intent。发送之后,所有已注册的并且拥有与之相匹配IntentFilter的BroadcastReceiver就会被激活。

Intent一旦发出,Android都会准确找到相匹配的一个或多个Activity,Service或者BroadcastReceiver作响应。所以,不同类型的Intent消息不会出现重叠,即Broadcast的Intent消息只会发送给BroadcastReceiver,而决不会发送给Activity或者Service。由startActivity()传递的消息也只会发给Activity,由startService()传递的Intent只会发送给Service。

Intent的构成

要在不同的activity之间传递数据,就要在intent中包含相应的内容,一般来说数据中最基本的应该包括:

Action:用来指明要实施的动作是什么,比如说ACTION_VIEW, ACTION_EDIT等。具体的可以查阅android SDK-> reference中的Android.content.intent类,里面的constants中定义了所有的action。

一些常用的Action:

ACTION_CALL activity 启动一个电话.

ACTION_EDIT activity 显示用户编辑的数据.

ACTION_MAIN activity 作为Task中第一个Activity启动

ACTION_SYNC activity 同步手机与数据服务器上的数据.

ACTION_BATTERY_LOW broadcast receiver 电池电量过低警告.

ACTION_HEADSET_PLUG broadcast receiver 插拔耳机警告

ACTION_SCREEN_ON broadcast receiver 屏幕变亮警告.

ACTION_TIMEZONE_CHANGED broadcast receiver 改变时区警告.

Data: 要事实的具体的数据,一般由一个Uri变量来表示

Category:一个字符串,包含了关于处理该intent的组件的种类的信息。一个intent对象可以有任意个category。intent类定义了许多category常数.

addCategory()方法为一个intent对象增加一个category,

removeCategory删除一个category,

getCategories()获取intent所有的category.

Type:显式指定Intent的数据类型(MIME)(多用途互联网邮件扩展,Multipurpose Internet Mail Extensions)。比如,一个组件是可以显示图片数据的而不能播放声音文件。很多情况下,data类型可在URI中找到,比如content:开头的URI,表明数据由设备上的content provider提供。但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

MIME类型有2种形式

1.1 单个记录的格式: vnd.android.cursor.item/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains/122(一条列车信息的uri)的MIME类型是vnd.android.cursor.item/vnd.example.rail

1.2 多个记录的格式:vnd.android.cursor.dir/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains (所有列车信息)的MIME类型是vnd.android.cursor.dir/vnd.example.rail

component:指定Intent的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。例如:

Intent it = new Intent(Activity.Main.this, Activity2.class); startActivity(it);

startActivity(it);

extras:附加信息,例如ACTION_TIMEZONE_CHANGED的intent有一个"time-zone"附加信息来指明新的时区,而ACTION_HEADSET_PLUG有一个“state”附加信息来指示耳机是被插入还是被拔出。intent对象有一系列put...()和set...()方法来设定和获取附加信息。 这些方法和Bundle对象很像。事实上附加信息可以使用putExtras()和getExtras()作为Bundle来读和写。例如:

//用Bundle传递数据 Intent it = new Intent(Activity.Main.this, Activity2.class); Bundle bundle=new Bundle(); bundle.putString("name", "This is from MainActivity!"); it.putExtras(bundle); startActivity(it); //获得数据 Bundle bundle=getIntent().getExtras(); String name=bundle.getString("name");

intent的解析:

在应用中,我们可以以两种形式来使用Intent:

1.1 显式Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

2.2 隐式Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于直接Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析将 Intent映射给可以处理此Intent的Activity、Service或Broadcast Receiver。

Intent解析机制

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有<intent-filter>及其中定义的Intent,通过PackageManager(注:PackageManager能够得到当前设备上所安装的

application package的信息)来查找能处理这个Intent的component。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方法如下:

1.1 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;

1.2 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

1.3 如果Intent中的数据不是content:类型的URI,而且Intent也没有明确指定type,将根据Intent中数据的scheme(比如 http:或者mailto:)进行匹配。同上,Intent 的scheme必须出现在目标组件的scheme列表中。

1.4 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。

实例:

1.无参数Activity跳转 

1.Intent it = new Intent(Activity.Main.this, Activity2.class);
2.startActivity(it);
2.向下一个Activity传递数据(使用Bundle和Intent.putExtras) 

1.Intent it = new Intent(Activity.Main.this, Activity2.class);
2.Bundle bundle=new Bundle();
3.bundle.putString("name", "This is from MainActivity!");
4.it.putExtras(bundle); // it.putExtra(“test”, "shuju”);
5.startActivity(it); // startActivityForResult(it,REQUEST_CODE);
对于数据的获取可以采用: 

1.Bundle bundle=getIntent().getExtras();
2.String name=bundle.getString("name");
3.向上一个Activity返回结果(使用setResult,针对startActivityForResult(it,REQUEST_CODE)启动的Activity) 

1. Intent intent=getIntent();
2. Bundle bundle2=new Bundle();
3. bundle2.putString("name", "This is from ShowMsg!");
4. intent.putExtras(bundle2);
5. setResult(RESULT_OK, intent);
4.回调上一个Activity的结果处理函数(onActivityResult) 

1.@Override
2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
3. // TODO Auto-generated method stub
4. super.onActivityResult(requestCode, resultCode, data);
5. if (requestCode==REQUEST_CODE){
6. if(resultCode==RESULT_CANCELED)
7. setTitle("cancle");
8. else if (resultCode==RESULT_OK) {
9. String temp=null;
10. Bundle bundle=data.getExtras();
11. if(bundle!=null) temp=bundle.getString("name");
12. setTitle(temp);
13. }
14. }
15. }
下面是转载来的其他的一些Intent用法实例(转自javaeye)

显示网页 

1.1. Uri uri = Uri.parse("http://google.com");
2. 2. Intent it = new Intent(Intent.ACTION_VIEW, uri);
3. 3. startActivity(it);
显示地图 

1. 1. Uri uri = Uri.parse("geo:38.899533,-77.036476");
2. 2. Intent it = new Intent(Intent.ACTION_VIEW, uri); 
3. 3. startActivity(it); 
4. 4. //其他 geo URI 範例
5. 5. //geo:latitude,longitude
6. 6. //geo:latitude,longitude?z=zoom
7. 7. //geo:0,0?q=my+street+address
8. 8. //geo:0,0?q=business+near+city
9. 9. //google.streetview:cbll=lat,lng&cbp=1,yaw,,pitch,zoom&mz=mapZoom
路径规划 

1. 1. Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
2. 2. Intent it = new Intent(Intent.ACTION_VIEW, uri);
3. 3. startActivity(it);
4. 4. //where startLat, startLng, endLat, endLng are a long with 6 decimals like: 50.123456
打电话 

1. 1. //叫出拨号程序
2. 2. Uri uri = Uri.parse("tel:0800000123");
3. 3. Intent it = new Intent(Intent.ACTION_DIAL, uri);
4. 4. startActivity(it);
5. 1. //直接打电话出去
6. 2. Uri uri = Uri.parse("tel:0800000123");
7. 3. Intent it = new Intent(Intent.ACTION_CALL, uri);
8. 4. startActivity(it);
9. 5. //用這個,要在 AndroidManifest.xml 中,加上
10. 6. //<uses-permission id="android.permission.CALL_PHONE" />
传送SMS/MMS 

1. 1. //调用短信程序
2. 2. Intent it = new Intent(Intent.ACTION_VIEW, uri);
3. 3. it.putExtra("sms_body", "The SMS text"); 
4. 4. it.setType("vnd.android-dir/mms-sms");
5. 5. startActivity(it);

1. 1. //传送消息
2. 2. Uri uri = Uri.parse("smsto://0800000123");
3. 3. Intent it = new Intent(Intent.ACTION_SENDTO, uri);
4. 4. it.putExtra("sms_body", "The SMS text");
5. 5. startActivity(it);

1. 1. //传送 MMS
2. 2. Uri uri = Uri.parse("content://media/external/images/media/23");
3. 3. Intent it = new Intent(Intent.ACTION_SEND); 
4. 4. it.putExtra("sms_body", "some text"); 
5. 5. it.putExtra(Intent.EXTRA_STREAM, uri);
6. 6. it.setType("image/png"); 
7. 7. startActivity(it);
传送 Email 

1. 1. Uri uri = Uri.parse("mailto:xxx@abc.com");
2. 2. Intent it = new Intent(Intent.ACTION_SENDTO, uri);
3. 3. startActivity(it);

1. 1. Intent it = new Intent(Intent.ACTION_SEND);
2. 2. it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
3. 3. it.putExtra(Intent.EXTRA_TEXT, "The email body text");
4. 4. it.setType("text/plain");
5. 5. startActivity(Intent.createChooser(it, "Choose Email Client"));

1. 1. Intent it=new Intent(Intent.ACTION_SEND); 
2. 2. String[] tos={"me@abc.com"}; 
3. 3. String[] ccs={"you@abc.com"}; 
4. 4. it.putExtra(Intent.EXTRA_EMAIL, tos); 
5. 5. it.putExtra(Intent.EXTRA_CC, ccs); 
6. 6. it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
7. 7. it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
8. 8. it.setType("message/rfc822"); 
9. 9. startActivity(Intent.createChooser(it, "Choose Email Client"));

1. 1. //传送附件
2. 2. Intent it = new Intent(Intent.ACTION_SEND);
3. 3. it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
4. 4. it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");
5. 5. sendIntent.setType("audio/mp3");
6. 6. startActivity(Intent.createChooser(it, "Choose Email Client"));
播放多媒体 

1. Uri uri = Uri.parse("file:///sdcard/song.mp3");
2. Intent it = new Intent(Intent.ACTION_VIEW, uri);
3. it.setType("audio/mp3");
4. startActivity(it);
5. Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
6. Intent it = new Intent(Intent.ACTION_VIEW, uri);
7. startActivity(it);
Market 相关 

1.1. //寻找某个应用
2.2. Uri uri = Uri.parse("market://search?q=pname:pkg_name");
3.3. Intent it = new Intent(Intent.ACTION_VIEW, uri);
4.4. startActivity(it);
5.5. //where pkg_name is the full package path for an application

1.1. //显示某个应用的相关信息
2.2. Uri uri = Uri.parse("market://details?id=app_id");
3.3. Intent it = new Intent(Intent.ACTION_VIEW, uri);
4.4. startActivity(it);
5.5. //where app_id is the application ID, find the ID 
6.6. //by clicking on your application on Market home 
7.7. //page, and notice the ID from the address bar
Uninstall 应用程序 

1.1. Uri uri = Uri.fromParts("package", strPackageName, null);
2.2. Intent it = new Intent(Intent.ACTION_DELETE, uri); 
3.3. startActivity(it);


什么是pengdingIntent

pendingIntent字面意义:等待的,未决定的Intent。

要得到一个pendingIntent对象,使用方法类的静态方法

getActivity(Context,
 int, Intent, int)


getBroadcast(Context,
 int, Intent, int)


getService(Context,
 int, Intent, int)  


分别对应着Intent的3个行为,跳转到一个activity组件、打开一个广播组件和打开一个服务组件。

可以看到,要得到这个对象,必须传入一个Intent作为参数,必须有context作为参数。
pendingIntent是一种特殊的Intent。主要的区别在于Intent的执行立刻的,而pendingIntent的执行不是立刻的。pendingIntent执行的操作实质上是参数传进来的Intent的操作,但是使用pendingIntent的目的在于它所包含的Intent的操作的执行是需要满足某些条件的。

主要的使用的地方和例子:通知Notificatio的发送,短消息SmsManager的发送和警报器AlarmManager的执行等等。

Intent和PendingIntent的区别

a. Intent是立即使用的,而PendingIntent可以等到事件发生后触发,PendingIntent可以cancel

b. Intent在程序结束后即终止,而PendingIntent在程序结束后依然有效

c. PendingIntent自带Context,而Intent需要在某个Context内运行

d. Intent在原task中运行,PendingIntent在新的task中运行

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

PendingIntent用于描述Intent及其最终的行为.

你可以通过getActivity(Context context, int requestCode, Intent intent, int flags)系列方法从系统取得一个用于启动一个Activity的PendingIntent对象,

可以通过getService(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于启动一个Service的PendingIntent对象

可以通过getBroadcast(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于向BroadcastReceiver的Intent广播的PendingIntent对象

返回的PendingIntent可以递交给别的应用程序,然后继续处理。这里的话你可以稍后才处理PendingIntent中描述的Intent及其最终行为。

当你把PendingIntent递交给别的程序进行处理时,PendingIntent仍然拥有PendingIntent原程序所拥有的权限(with
the same permissions and identity).当你从系统取得一个PendingIntent时,一定要非常小心才行。比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的话,你最好采用在Intent中显示指定目的component名字的方式,以确保Intent最终能发到目的,否则Intent最后可能不知道发到哪里了。一个PendingIntent就是Android系统中的一个token(节点,这个应该是Linux或C\C++用语)的一个对象引用,它描述了一些将用于retrieve的数据(这里,这些数据描述了Intent及其最终的行为)。

这就意味着即使PendingIntent原进程结束了的话,
PendingIntent本身仍然还存在,可在其他进程(PendingIntent被递交到的其他程序)中继续使用.如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent, 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent,而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数,让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。

通过FLAG_UPDATE_CURRENT参数的话,可以让新的Intent会更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。另外,我们也可以在PendingIntent的原进程中调用PendingIntent的cancel
()把其从系统中移除掉。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: