Android之Intent详解

来源:互联网 发布:linux终端删除~$ 编辑:程序博客网 时间:2024/05/02 03:01

1、Intent是一个将要执行的动作的抽象描述,一般是用来协助完成各个组件之间的通讯。Intent负责对应用中一次操作的动作及动作涉及的数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成对组件的调用。可以说,Intent起着媒介的作用,专门提供提供组件相互调用的相关信息,实现调用者和被调用者之间的控制。

 

2、Intent的构成

1)Action:用来指明要实施的动作是什么。如ACTION_VIEW, ACTION_EDIT等

2)Data:具体的数据,一般由Uri变量来表示

3)Category:指定将要执行的这个action的其它一些额外的信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。

4)Type:显示指定Intent的数据类型。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

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

6)Extra:附加信息,是其它所有附加信息的集合。使用extras可以为组件提供扩展信息。比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

 

3、Intent中data数据的Uri结构

android采用指向数据的一个URI来表示数需要操作的数据。

URI主要分三部分:scheme、authority和path,其中authority可分为host和port。格式:scheme://host:port/path

实例如下:

content://com.example.project:200/folder/subfolder/etc
\---------/  \---------------------------/ \---/ \--------------------------/
scheme                 host               port        path
                \--------------------------------/
                          authority   

4、Intent解析

应用程序的组件为了告诉Android自己能响应、处理哪些隐式Intent请求,可以声明一个甚至多个Intent Filter。每个Intent Filter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。比如之前请求网页浏览器这个例子中,网页浏览器程序的Intent Filter就应该声明它所希望接收的Intent Action是WEB_SEARCH_ACTION,以及与之相关的请求数据是网页地址URI格式。如何为组件声明自己的Intent Filter? 常见的方法是在AndroidManifest.xml文件中用属性< Intent-Filter>描述组件的Intent Filter。

<activity android:name="com.example.learn.MainActivity" android:label="@string/app_name" >    <intent-filter>        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />    </intent-filter></activity>

 

5、android解析Intent的流程

在应用中具体分成两种Intent:直接Intent 间接Intent

直接intent就是指定了component属性的intent(调用setComponent(componentName))。通过指定具体的组件类,通知应用启动对应的组件;
间接intent是没有指定component属性的intent,这些intent需要包含足够的信息,这样系统才能确定启动对应的组件;

对于直接Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析,将Intent映射给可以处理此Intent的Activity、Broadcaset receiver或Service。Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方法如下:

●  如果intent指明了action,则目标组件的intentFilter的action列表就必须包含有这个action,否则不能匹配;
●  如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
● 如果Intent中的数据不是content: 类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme(比如 http: 或者mailto:)进行匹配。同上,Intent 的scheme必须出现在目标组件的scheme列表中。
● 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEG
ORY,解析得到的目标组件必须至少包含这两个类别。


6、catetory的类别总结:

android.intent.category.ALTERNATIVE:ALTERNATIVE 种类指定,在某种数据类型的项目上可以替代默认执行的动作。例如,一个联系人的默认动作时浏览它,替代的可能是去编辑或删除它。   

android.intent.category.BROWSABLE:指定在浏览器中的动作。当 Intent 在浏览器中被引发,都会被指定成 BROWSABLE 种类。  

android.intent.category.DEFAULT :设置这个种类来让组件成为 Intent Filter 中定义的 data 的默认动作。这对使用显式 Intent 启动的 Activity 来说也是必要的。

android.intent.category.DEVELOPMENT_PREFERENCE   

android.intent.category.EMBED   

android.intent.category.HOME:HOME Activity 是设备启动(登陆屏幕)时显示的第一个 Activity 。通过指定 Intent Filter 为 HOME 种类而不指定动作的话,你正在将其设为本地 home 画面的替代。      

android.intent.category.INFO

android.intent.category.LAUNCHER:使用这个种类来让一个 Activity 作为应用程序的启动项。   

android.intent.category.MONKEY   

android.intent.category.OPENABLE   

android.intent.category.PREFERENCE    

android.intent.category.SELECTED_ALTERNATIVE:与 ALTERNATIVE 类似,但 ALTERNATIVE 总是使用下面所述的 Intent 解析来指向单一的动作。SELECTED_ALTERNATIVE在需要一个可能性列表时使用。   

android.intent.category.TAB

 

7、Intent有两种基本用法:一种是显示的Intent,即在构造intent对象时就指定接收者,这种方式与普通的函数调用类似。另一种是隐式的intent,即intent的发送者在构造intent对象时,但是并不关心接收者,有利于降低发送者和接收者之间的耦合。

 

8、bundle

android使用Intent.putSerializable()进行数据传递,或者使用Bundle进行数据传递。实质上都是进行的Serializable数据的操作,都是传递源数据的一份拷贝。

public void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.main);                // 定义一个Bundle按键        Button gotoBundle = (Button)findViewById(R.id.btnBundle);      // 设置监听事件        gotoBundle.setOnClickListener(new View.OnClickListener(){        @Override      public void onClick(View v) {         Intent intent = new Intent();         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);         intent.setClass(getApplicationContext(), GetBundleActivity.class);                           DataBean temp  = new DataBean();         temp.setID(1);         temp.setName("张三");         temp.setAddress("xx市xx路xx号");         temp.setMoblie("159xxxxxxxx");                           Log.i("AndroidbundleActivity", "新建时候的地址" + temp);                              Bundle bundle = new Bundle();         bundle.putSerializable("UserInfo", temp);                           // 设置intent          intent.putExtras(bundle);                           // 发送Activity          getApplicationContext().startActivity(intent);      }                });  }  
public void onCreate(Bundle savedInstanceState) {      // 初始化BundleActivity       super.onCreate(savedInstanceState);      setContentView(R.layout.bundle);                // 获取意图       Intent intent = getIntent();      Bundle bundle = intent.getExtras();                // 获取对象       DataBean temp = (DataBean) bundle.get("UserInfo");      Log.i("GetBundleActivity", "收到的地址" + temp);  }  

 

9、intent实例

1)无参数activity跳转

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

2)向下一个activity传递数据(使用bundle和putExtras)

Intent intent = new Intent(Activity.Main.this, Activity2.class);  Bundle bundle=new Bundle();  bundle.putString("name", "This is from MainActivity!");  intent.putExtras(bundle);  //startActivity(intent);  startActivityForResult(intent,REQUEST_CODE);  
Bundle bundle=getIntent().getExtras();  String name=bundle.getString("name");  

3)向上一个Activity返回结果(使用setResult,针对 startActivityForResult(it,REQUEST_CODE)启动的Activity)

Intent intent=getIntent();  Bundle bundle=new Bundle();  bundle.putString("name", "This is from Activity2!");  intent.putExtras(bundle);  setResult(RESULT_OK, intent);  


注解:

startActivityForResult(Intent intent, Int requestCode):requestCode >=0就好,随便用于在onActivityResult()区别哪个子模块回传的数据,如果还有C.java ,D甚至E子模块的话,每个区分开不同的requestCode就好。
setResut(int resultCode, Intent intent):resultCode 如果B子模块可能有几种不同的结果返回,可以用这个参数予以识别区分。这里还有个特殊的 RESULT_OK 值,没有特殊情况用它就好了。intent 传回给A的onActivityResult()
onActivityResult(int requestCode, int resultCode, Intent intent):如果不对requestCode和resultCode 加以识别区分的话,只要有其他activity setResult到了A  
onActivityResult()会无差别处理。

4)回调上一个Activity的结果处理函数(onActivityResult)
@Override      protected void onActivityResult(int requestCode, int resultCode, Intent data) {              // TODO Auto-generated method stub               super.onActivityResult(requestCode, resultCode, data);              if (requestCode==REQUEST_CODE){                     if(resultCode==RESULT_CANCELED)                               setTitle("cancle");                     else if (resultCode==RESULT_OK) {                              String temp=null;                              Bundle bundle=data.getExtras();                              if(bundle!=null)                 temp=bundle.getString("name");                              setTitle(temp);                     }               }      }