欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详解Android中通过Intent类实现组件间调用的方法

程序员文章站 2024-03-01 11:51:28
intent是android中用来调用其它组件的类,通过intent,我们可以非常方便的调用activity,broadcast receiver和service。...

intent是android中用来调用其它组件的类,通过intent,我们可以非常方便的调用activity,broadcast receiver和service。

intent intent = new intent(intent.action_view);
intent.setdata(uri.parse("http://www.baidu.com"));
startactivity(intent);

上面这段代码可以用来调用第三方的activity(启动第三方浏览器来打开百度首页)。
intent有隐式和显式之分,上面的

intent intent = new intent(intent.action_view);

所创建的intent被称为隐式intent。构建隐式intent需要一个表示action的字符串(例如intent.action_view,其值为" android.intent.action.view"),android会寻找能够处理该action的activity(在manifest文件中的该activity下的intent-filter中声明),并且调用他。
有时候可能多个activity都声明能够处理某一个action,例如:

<activity
  android:name=".activity1">
  <intent-filter>
    <action android:name="com.abc.def" />
    <category android:name="android.intent.category.default" />
  </intent-filter>
</activity>
<activity
  android:name=".activity2">
  <intent-filter>
    <action android:name="com.abc.def" />
    <category android:name="android.intent.category.default" />
  </intent-filter>
</activity>

上面activity1和activity2都声明能够处理“com.abc.def”的action,因此当我们执行以下代码时

intent intent = new intent("com.abc.def");
startactivity(intent);

activity1和activity2都符合要求,android将弹出"complete action using"的对话框来让用户选择一个要执行的activity。

值得注意的是,要想能够匹配隐式intent的调用,必须包含default的category(就是<category android:name="android.intent.category.default"/>),而若要匹配显式intent,则不需要该category。

对于隐式intent,除了action之外,还可以提供多种信息来帮助android选择最佳匹配。还可以添加的其他信息包括:host,mimetype,path,pathpattern,pathprefix,port,scheme。

例如为上面activity2在manifest中的配置添加一个mimetype的属性:

<activity
  android:name=".activity2">
  <intent-filter>
    <action android:name="com.abc.def" />
    <category android:name="android.intent.category.default" />
    <data android:mimetype="abc/def"/>
  </intent-filter>
</activity>

那么:

intent intent = new intent("com.abc.def");
startactivity(intent);//只有activity1符合

/********************************************/
intent intent = new intent("com.abc.def");
intent.settype("abc/def");
startactivity(intent);//只有activity2符合

如果在创建intent的时候,指明了要调用的类(例如new intent(xxactivity.this, xx.class),或者通过setcomponent来指定),那么这样的intent被称为显示intent。

对于显式intent,因为他已经指明了要调用的具体的类,所以android会忽略掉其action,category以及data属性。(个人觉得显示intent调用比隐式的更快些)

serializable vs parcelable
android 主要是通过intent来实现组件之间的相互调用,同时还可以传递附加的数据。这些数据主要是存储在bundle之中(当调用intent.putextras(bundle)时,android会复制bundle中的数据,而不是引用,因此再修改bundle中的数据并不会改变intent中携带的数据)。

bundle之中可以存放基本数据类型以及实现了serializable或parcelable接口的类。

当我们要向bundle中存放一个类obj(包含两个int成员的简单类),可以让它实现serializable或parcelable接口,如下所示:

1.serializable


public class obj implements serializable {
  private int a;
  private int b;
  public obj(int a, int b) {
    this.a = a;
    this.b = b;
  }
  
  @override
  public string tostring() {
    return "obj: [" + a + ", " + b + "]";
  }
}

我们可以通过intent.putextra("obj", new obj(1, 2));来将其放入intent中,然后通过 obj = (obj) intent.getserializableextra("obj");来将其取出。
2.parcelable


public class objpar implements parcelable {
  private int a;
  private int b;
  public objpar(int a, int b) {
    this.a = a;
    this.b = b;
  }
  
  @override
  public string tostring() {
    return "obj: [" + a + ", " + b + "]";
  }
  @override
  public int describecontents() {
    return 0;
  }
  @override
  public void writetoparcel(parcel dest, int flags) {
    dest.writeint(a);
    dest.writeint(b);
  }
  
  public static final parcelable.creator<objpar> creator = new creator<objpar>() {
    
    @override
    public objpar[] newarray(int size) {
      return new objpar[size];
    }
    
    @override
    public objpar createfromparcel(parcel source) {
      
      return new objpar(source.readint(), source.readint());
    }
  };
}

我们可以通过intent.putextra("objpar", new objpar(1, 2));来将其放入intent中,然后通过 objpar =  (objpar) intent.getparcelableextra("objpar"); 来将其取出。
以上是两种向bundle中存放object对象的方法,明显可以看出实现serializable接口更加简单,因为他是一个标记性的接口,并不需要实现某个具体方法。相比而言实现parcelable接口就显得相对复杂一些,但这样带来的好处是性能的大幅提高。这是因为当我们实现serializable接口后,真正的序列化工作是由jdk来完成,他需要通过反射来获取成员变量,因为反射的性能并不高,因此这种序列化方式速度慢。然而实现parcelable接口时,我们提供了该接口中定义方法的实现(writetoparcel实现序列化,createfromparcel实现反序列化),这就避免了反射的使用,因此这种方式速度快。

那么这两种方式,性能差别有多大呢?下面是国外网站上的一个测试结果:serializable耗时是parcelable的10倍左右

 详解Android中通过Intent类实现组件间调用的方法