安卓基础知识-跨进程通信IPC篇-1. Intent

时间:2024-04-25 22:26:24

参考:安卓Intent 详解

简介和作用

intent本意是“目的、意向、意图”。Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来响应。
安卓 Intent 是一种在 Android应用程序之间或者应用内部传递信息的机制。它可以用于启动活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver),以及传递数据和操作等。

分类

  • 显式intent:通过在intent中明确设置想要启动组件的类名,来显式地向安卓系统表达本次启动的目的。

  • 隐式intent:在intent中不会显式设置欲启动的组件类名,而是通过设置action、category等信息,安卓系统会自动根据各个组件在AM文件中设置的intent-filter来进行过滤和匹配,匹配成功的组件将会被启动。如果匹配到不止一个组件,将会通过弹窗的方式让用户选择处理该intent的组件。

安卓系统匹配隐式intent的过程:

  1. 加载安装所有的intent-filter的组件
  2. 剔除action匹配失败的组件
  3. 剔除URI数据匹配失败的组件
  4. 剔除category匹配失败的组件
  5. 如果匹配到的组件数量大于1,按照优先级返回最高优先级的组件。

常见操作

创建intent

import android.content.Intent;

Intent intent = new Intent(); // 空构造
Intent intent = new Intent(String action); // 隐式intent,传入action
Intent intent = new Intent(String action, Uri uri); // 隐式intent
Intent intent = new Intent(Context packageContext, Class<?> cls); // 显式intent,参数1是当前组件的context,参数2是目标组件的类名
Intent intent = new Intent(String action, Uri uri, Context packageContext, Class<?> cls); // 显式intent

设置component目的组件(显式intent)

Component属性明确指定Intent的目标组件的类名称。(属于显示Intent)
如果component这个属性有指定的话,将直接使用它指定的组件。指定了这个属性以后,Intent的其它所有属性都是可选的。

Intent intent = new Intent();
ComponentName component = new ComponentName(MainActivity.this, SecondActivity.class);
intent.setComponent(component);
startActivity(intent);

// 简写成
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);

设置action动作

action表示intent欲要完成的动作,在Intent类中,定义了一批量的动作,比如ACTION_VIEW,ACTION_PICK等, 基本涵盖了常用动作。
action也可以是一个用户定义的字符串,用于标识一个用户自定义的 Android 应用程序组件。
一个 Intent Filter 可以包含多个 Action,但是一个intent对象只可以设置一个action。
在 AndroidManifest.xml 的Activity 定义时,可以在其intent-filter节点指定一个Action列表用于标识 Activity所能接受的“动作”。

添加category类别

只有action和category中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应intent。
用户在AM中声明安卓组件时,如果这个组件没有特别的category,则需要显式地将DEFAULT类型的category添加到category列表中,因为当调用startActivity()方法的时候会自动将这个DEFAULT 类型的category添加到Intent中。
自定义类别: 在Intent添加类别可以添加多个类别,那就要求这些类别能同时被匹配上,才算该intent被组件匹配成功。
操作Activity的时候,如果没有类别,须加上默认类别。

<activity android:name=".SecondActivity">
    <intent-filter>
         <action android:name="com.example.XXXX.MY_ACTION1"/> // action1
		 <action android:name="com.example.XXXX.MY_ACTION2"/> // action2,intent-filter中可以设置多个action
		 
		 <category android:name="com.example.XXXX.MY_CATEGORY" /> // 声明自定义类别
         <category android:name="android.intent.category.DEFAULT" /> // 需要显式地声明DEFAULT category
    </intent-filter>            
</activity>
Intent intent = new Intent();
intent.setAction("com.example.XXXX.MY_ACTION1");
intent.addCategory("com.example.XXXX.MY_CATEGORY");
startActivity(intent);

// 简写成
Intent intent = new Intent("com.example.XXXX.MY_ACTION1"); // 隐式intent,调用Intent(String action)构造函数。
startActivity(intent);

设置data数据和type类型

Data属性是Android要访问的数据,和action和category声明方式相同,也是在intent-filter中。
多个组件匹配成功显示优先级高的; 相同显示列表。
Data是用一个uri对象来表示的,uri代表数据的地址,属于一种标识符。通常情况下,我们使用action+data属性的组合来描述一个意图:做什么
使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如应用程序中需要展示一个网页,没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。
android:scheme、android:path、android:port、android:mimeType、android:host等,通过这些属性来对应一个典型的Uri格式scheme://host:port/path。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));                
startActivity(intent); 

在自定义的安卓组件中也可以通过声明data来匹配这个intent:

<activity android:name=".SecondActivity">
    <intent-filter android:priority="-1"> // 设置intent-filter的优先级
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT" />
         <data android:scheme="http" android:host="www.baidu.com"/>                 
    </intent-filter>            
</activity>

Type属性用于明确指定Data属性的数据类型或MIME类型,但是通常来说,当Intent不指定Data属性时,Type属性才会起作用,否则Android系统将会根据Data属性值来分析数据的类型,所以无需指定Type属性。
data和type属性一般只需要一个,通过setData方法会把type属性设置为null,相反设置setType方法会把data设置为null,如果想要两个属性同时设置,要使用Intent.setDataAndType()方法。

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data = Uri.parse("file:///storage/sdcard0/平凡之路.mp3");
intent.setDataAndType(data, "audio/mp3"); // 打开指定路径的指定类型的文件
startActivity(intent);

设置和读取扩展数据extras

通过intent.putExtra(String,XXX)方法以键值对的方式传递数据,其中XXX可代表基本数据类型、数组等。
获取数据通过intent.getXXXExtra(String)方法,其中XXX可代表基本数据类型、数组等。
Intent传递Serializable对象:

intent.putExtra("person",person); //  其中person是实现了Serializable接口的可序列化对象
Person person = (Person) getIntent().getSerializableExtra("person");
···
Intent传递Parcelable对象:

intent.putExtra(“person”,person); // 其中person是实现了Parcelable接口的可序列化对象
Person person = (Person) getIntent().getParcelableExtra(“person”);
···

设置flags标志位

一个程序启动后系统会为这个程序分配一个task供其使用,另外同一个task里面可以拥有不同应用程序的activity。那么,同一个程序能不能拥有多个task?这就涉及到加载activity的启动模式,这个需要单独讲一下。
注:android中一组逻辑上在一起的activity被叫做task,自己认为可以理解成一个activity堆栈。

常见用法

  • 启动活动:使用Context.startActivity() 或 Activity.startActivityForResult(),传入一个intent来启动一个activity。使用 Activity.setResult(),传入一个intent来从activity中返回结果。
  • 启动服务或者绑定服务:将intent对象传给Context.startService()来启动一个service或者传消息给一个运行的service。将intent对象传给 Context.bindService()来绑定一个service。
  • 给广播接收器发送广播:将intent对象传给 Context.sendBroadcast(),Context.sendOrderedBroadcast(),或者Context.sendStickyBroadcast()等广播方法,则它们被传给 broadcast receiver。