Android学习笔记之Android应用核心Intent

来源:互联网 发布:域名访问tomcat项目 编辑:程序博客网 时间:2024/05/29 04:26

一个Android程序由多个组件组成,各个组件之间使用Intent进行通信。Intent对象中包含组件名称、动作、数据等内容。根据Intent中的内容,Android系统可以启动需要的组件。

实际上,Activity、Service和Broadcast Receiver这3三种核心组件都需要使用Intent来进行激活。Intent用于相同或者不同应用程序组件间的后期运行时绑定。


一、Intent对象


对于不同的组件,Android系统提供了不同的Intent发送机制进行激活。

①Intent对象可以船体给Context.startActivity()或Activity.startActivityForResult()方法来启动Activity或者让已经存在的Activity去做其他任务。Intent对象也可以作为Activity.setResult()方法的参数,将信息返回给调用startActivityForResult()方法的Activity。

②Intent对象可以传递给Context.startService()方法来初始化Service或者发送新指令到正在运行的Service。类似的,Intent对象可以传递Context.bindService()方法来建立调用组件和目标Service之间的链接。它可以有选择地初始化没有运行的服务。

③Intent对象可以传递给Context.sendBraodcast()、Context.sendOrderedBroadcast()或Context.sendStickyBroadcast()等广播方法,使其被发送给所有感兴趣的Broadcast Receiver。

原则上讲,Intent包含组件名称、动作、数据、种类、额外和标记等内容:

①组件名称(Component Name)

组件名称是指Intent目标组件的名称。它是一个ComponentName对象。组件名称可以使用setComponent()、setClass()或setClassName()方法设置,使用getComponent()方法读取。

②动作(Action)

Action是要给字符串,用来表示将要执行的动作。在广播Intent中,Action用来表示已经发生即将报告的动作。在Intent类中,定义了一些列动作常量,其目标组件包括Activity和Broadcast两类。

1)标准Activity动作   2)标准广播动作

除了预定义的动作,开发人员还可以自定义动作字符串来启动应用程序中的组件。这些字符串应该包含一个应用程序包名作为前缀,如com.dyzhou.SHOW_COLOR。Intent对象中的动作使用setAction()方法设置,使用getAction()方法读取。

③数据(Data)

Data表示操作数据的URI和MIME类型。不同动作与不同类型的数据规范匹配。例如,如果动作是ACTION_EDIT, 数据应该是包含用来编辑的文档的URI;如果动作是ACTION_CALL,数据应该是包含呼叫号码的tel:URI。类似的,如果动作是ACTION_VIEW而且数据是http:URI,接收的Activity用来下载和显示URI指向的数据。

在将Intent与处理它的数据的组件匹配时,除了数据的URI,也有必要了解其MIME类型。例如,能够显示图片数据的组件不应该用来播放音频文件。

在多种情况下,数据类型可以从URI中推断,尤其时content:URI。它表示数据存在于设备上并由ContentProvider控制。但是,类型信息也可以显式地设置到Intent对象中。setData()方法仅能指定数据的URI,setType()方法仅能指定数据的MIME类型,setDataAndType()方法可以同时设置URI和MIME类型。使用getData()方法可以读取URI,使用getType()方法可以读取类型。

④种类(Category)

Category是一个字符串,其中包含了应该处理当前Intent的组件类型的附加信息。在Intent对象中可以增加任意多个种类描述。 与动作类似,在Intent类中也预定义了一些种类常量。

addCategory()方法将种类增加到Intent对象中,removeCategory()方法删除上次增加的种类,getCategories()方法获得当前对象中包含的全部种类。

⑤额外(Extras)

Extras是一组键值时,其中包含了应该传递给处理Intent的组件的额外信息。

Intent对象中包含了多个putXXX()方法(如putExtra()方法)用来插入不同类型的额外数据,也包含了多个getXXX()方法(如getDoubleExtra()方法)来读取数据。这些方法与Bundle对象有些类似。实际上,额外可以通过putExtras()和getExtras()方法来作为Bundle设置和读取。

⑥标记(Flags)

Flags表示不同来源的标记。多数用于指示Android系统如何启动Activity(如activity属于哪个Task)以及启动后如何对待(如它是否属于近期的activity列表)。所有标记都定义在Intent类中。

注意:所有标记都是整数类型。


二、Intent使用


Intent可以分成显式和隐式两类。

①显式Intent通过组件名称来指定目标组件。由于其他应用程序的组件名称对于开发人员通常式位置的,显式Intent通常用于应用程序内部消息,例如Activity启动子Service或其他Activity。

②隐式Intent不指定组件名称,通常用于激活其他应用程序中的组件。

在使用Intent过滤器测试Intent对象时,对象中仅有3个方面与其相关:

动作

数据(包括URI和数据类型)

种类

额外和标记在决定哪个组件可以接收Intent时并无作用。


Intent过滤器

Activity、Service和BroadcastReceiver能定义多个Intent过滤器来通知系统它们可以处理哪些隐式Intent。每个过滤器描述组件的一种能力以及该组件可以接收的一组Intent。实际上,过滤器接收需要类型的Intent、拒绝不需要类型的Intent仅限于隐式Intent。对于显式Intent,无论内容如何,总可以发送给其目标,过滤器并不干预。

对于能够完成的工作及显示给用户的界面,组件都有独立的过滤器。

Intent过滤器时IntentFilter类的实例。然而,由于Android系统在启动组件前必须了解组件的能力,Intent过滤器通常不在Java代码中进行设置,而是使用<intent-filter>标签写在应用程序的配置文件中(唯一的例外是调用Context.registerReceiver()方法动态注册BroadcastReceiver的过滤器,它们通常直接创建为IntentFilter对象)。

过滤器中包含的域与Intent对象中动作、数据和分类域相对应。过滤器对于隐式Intent在这3个方面分别进行测试。仅有通过全部测试时,Intent对象才能发送给拥有过滤器的组件。由于组件可以包含多个过滤器,Intent对象在一个过滤器上失败并不代表不能通过其他测试。

1.动作测试

2.种类测试

3.数据测试


Android在一个APP中通过包名或类名启动另一个APP(以下三篇文章仅供参考)


一、

有时候需要从一个APP中启动另外一个APP,比如Twitter/微信等。

如果你不知道那个APP的Activity,但是知道包名(package name),那么可以使用如下的方法:


  1. Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.package.address");  
  2. startActivity(LaunchIntent);  


如果APP之间有合作关系,可以获得合作APP的清单文件(manifest),那么可以从该文件中获知package/activity,
可使用如下的方法来启动该APP特定活动界面:


  1. Intent intent = new Intent(Intent.ACTION_MAIN);  
  2. intent.setComponent(new ComponentName("com.package.address","com.package.address.MainActivity"));  
  3. startActivity(intent);  


如果要在启动APP时传递参数,可以在意图(Intent)中设置:


  1. intent.putExtra("firstKeyName","FirstKeyValue");  
  2. intent.putExtra("secondKeyName","SecondKeyValue");  

二、

1、最简单的情况:只有包名

      PackageManager packageManager = context.getPackageManager();      

   Intent it= packageManager.getLaunchIntentForPackage(pk_name); 

2、启动第三方指定页面。(这个方法有限制,第三方页面 Activity的属性Export=“true”)

   启动页貌似是默认是true,其他页面默认是false

   Intent intent = new Intent(pk_name);
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   ComponentName comp = new ComponentName("com.android.settings","com.android.settings.Settings");
   intent.setComponent(comp);
   startActivity(intent);

3、隐式启动第三方应用

   Intent intent = new Intent();

   intent.setAction(action);

   intent.addCategory(category);

   intent.setDataAndType("abc://www.baidu.com","image/gif");

   startActivity(intent);

   条件1:IntentFilter 至少有一个action 至少有一个Category 可以没有Data和Type

   条件2:如果有Data,参数中Data必须符合Data规则

   条件3:Action和Category必须同时匹配Activity中的一个Action和一个Category(Category 默认:android.intent.category.DEFAULT)

三、

开发有时需要在一个应用中启动另一个应用,比如Launcher加载所有的已安装的程序的列表,当点击图标时可以启动另一个应用。一般我们知道了另一个应用的包名和MainActivity的名字之后便可以直接通过如下代码来启动:


  1. Intent intent = new Intent(Intent.ACTION_MAIN);  
  2. intent.addCategory(Intent.CATEGORY_LAUNCHER);              
  3. ComponentName cn = new ComponentName(packageName, className);              
  4. intent.setComponent(cn);  
  5. startActivity(intent);  

但是更多的时候,我们一般都不知道目标应用程序的启动Activity的类名,而只知道包名,接下来就需要这么做了,我封装成了一个方法,如下所示:


  1. private void doStartApplicationWithPackageName(String packagename) {  
  2.   
  3.     // 通过包名获取此APP详细信息,包括Activities、services、versioncode、name等等  
  4.     PackageInfo packageinfo = null;  
  5.     try {  
  6.         packageinfo = getPackageManager().getPackageInfo(packagename, 0);  
  7.     } catch (NameNotFoundException e) {  
  8.         e.printStackTrace();  
  9.     }  
  10.     if (packageinfo == null) {  
  11.         return;  
  12.     }  
  13.   
  14.     // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent  
  15.     Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);  
  16.     resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  17.     resolveIntent.setPackage(packageinfo.packageName);  
  18.   
  19.     // 通过getPackageManager()的queryIntentActivities方法遍历  
  20.     List<ResolveInfo> resolveinfoList = getPackageManager()  
  21.             .queryIntentActivities(resolveIntent, 0);  
  22.   
  23.     ResolveInfo resolveinfo = resolveinfoList.iterator().next();  
  24.     if (resolveinfo != null) {  
  25.         // packagename = 参数packname  
  26.         String packageName = resolveinfo.activityInfo.packageName;  
  27.         // 这个就是我们要找的该APP的LAUNCHER的Activity[组织形式:packagename.mainActivityname]  
  28.         String className = resolveinfo.activityInfo.name;  
  29.         // LAUNCHER Intent  
  30.         Intent intent = new Intent(Intent.ACTION_MAIN);  
  31.         intent.addCategory(Intent.CATEGORY_LAUNCHER);  
  32.   
  33.         // 设置ComponentName参数1:packagename参数2:MainActivity路径  
  34.         ComponentName cn = new ComponentName(packageName, className);  
  35.   
  36.         intent.setComponent(cn);  
  37.         startActivity(intent);  
  38.     }  
  39. }