android菜鸟学习笔记11----Intent的两点补充
关于Intent的两点补充:
1.隐式Intent启动组件,会有一个Intent解析的过程,若找不到能够处理该Intent的组件,程序就会异常终止。一个合理的做法是,在使用Intent实例启动组件如:startActivity(intent)之前,最好能判断一下该调用能否解析为一个Activity。为了实现该功能,Intent提供了一个方法:
ComponentName resolveActivity(PackageManager pm) :该方法接收一个包管理器对象作为参数,通过查找该包管理器,返回能够处理该Intent的Activity的Component对象,没有找到能处理该Inent的组件时则返回null。
Intent intent1 = new Intent(); intent1.setAction(Intent.ACTION_VIEW); intent1.setType("text/html"); Log.i("tag",intent1.toString()); ComponentName resolveActivity = intent1.resolveActivity(getPackageManager()); Log.i("tag",resolveActivity.getClassName()); Log.i("tag",resolveActivity.getPackageName()); Log.i("tag",resolveActivity.toString()); startActivity(intent1);
NormalActivity中配置<intent-filter>
1 <activity android:name=".NormalActivity"> 2 3 <intent-filter > 4 5 <action android:name="android.intent.action.VIEW"/> 6 7 <category android:name="android.intent.category.DEFAULT"/> 8 9 <data android:mimeType="text/html"/> 10 11 </intent-filter> 12 13 </activity>
运行信息:
可见解析到cn.csc.lifecycle.NormalActivity能够处理该Intent。
若找不到能够处理该Intent的组件时,会返回null,所以,安全的启动Activity的做法是:
1 if(intent1.resolveActivity(getPackageManager())!=null){ 2 3 startActivity(intent1); 4 5 }
当然,可以加上找不到能处理intent1的组件的提示信息等。
注意,若用多个组件都能处理该Intent实例时,如:
1 Intent intent1 = new Intent(); 2 3 intent1.setAction(Intent.ACTION_VIEW); 4 5 intent1.setData(Uri.parse("http://www.baidu.com")); 6 7 Log.i("tag",intent1.toString()); 8 9 ComponentName resolveActivity = intent1.resolveActivity(getPackageManager()); 10 11 Log.i("tag",resolveActivity.toString()); 12 13 startActivity(intent1);
1 <activity android:name=".NormalActivity"> 2 3 <intent-filter > 4 5 <action android:name="android.intent.action.VIEW"/> 6 7 <category android:name="android.intent.category.DEFAULT"/> 8 9 <data android:scheme="http"/> 10 11 </intent-filter> 12 13 </activity>
此时,浏览器和NormalActivity都能处理该Intent实例。
运行效果:
返回的Component信息为:
这个ResolverActivity其实就是一个选择打开程序的对话框,当有多个组件能处理Intent实例,但是没有设置默认的处理程序时,就会交由ResolverActivty来处理,而ResolverActivity的做法就是把所有能处理的都显示在一个列表中,由用户决定采用哪个来处理。当我们勾选了下面的use by default for this action时,之后选择的组件将会作为该Intent的默认处理程序,该设置会保存在手机或者模拟器中,下次在出现该Intent时,直接使用设置的默认组件去处理,而不再转到ResolverActivity。
如,这里我选择了Browser作为默认处理程序,下次再启动改程序,输出的运行信息:
2.关于使用Intent在Activity之间传递数据,在之前都是传递些内置类型的数据,若想传递自定义类型的数据,应该怎么办呢?
注意到在Intent中有下面两对方法:
Serializable getSerializableExtra(String name)
Intent putExtra(String name, Serializable value)
放入/获取Serializable类型的值。
<T extends Parcelable> T getParcelableExtra(String name)
Intent putExtra(String name, Parcelable value)
放入/获取Parcelable类型的值。
Serializable和Parcelable都是接口,即要想使用Intent传递自定义类型的数据,则自定义类型的数据应当事先Serializable接口或者Parcelable接口。
Serializable接口:
java.io.Serializable是一个空的起到标记作用的接口。标记实现该接口,只需要在类定义时声明实现该接口即可。实现该接口的类表明能够被序列化和反序列化,对大多数的类来说已然足够了,当然,若想更细粒度的操纵序列化过程,可以实现下面这两个方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
一般情况下,都用不到的。
这里简单声明实现该接口,如:
1 import java.io.Serializable; 2 3 4 5 public class MyData implements Serializable { 6 7 private String stringData; 8 9 private int intData; 10 11 public MyData(String stringData, int intData) { 12 13 super(); 14 15 this.stringData = stringData; 16 17 this.intData = intData; 18 19 } 20 21 public String getStringData() { 22 23 return stringData; 24 25 } 26 27 public void setStringData(String stringData) { 28 29 this.stringData = stringData; 30 31 } 32 33 public int getIntData() { 34 35 return intData; 36 37 } 38 39 public void setIntData(int intData) { 40 41 this.intData = intData; 42 43 } 44 45 }
之后,便可以传递MyData类型数据了:
1 MyData data1 = new MyData(“aaa”,111); 2 3 Intent intent1 = new Intent(); 4 5 intent1.putExtra(“mydata”, data1);
取得该数据:
1 MyData data1 = (MyData)getIntent.getSerializableExtra(“data1”);
Parcelable接口:相比Serializable要复杂一点,需要实现里面的抽象方法。
android.os.Parcelable接口,帮助文档中,有一个典型的实现例子如下,可以用作参考,自己实现该接口时,模仿即可:
1 public class MyParcelable implements Parcelable { 2 3 private int mData; 4 5 public int describeContents() { 6 7 return 0; 8 9 } 10 11 public void writeToParcel(Parcel out, int flags) { 12 13 out.writeInt(mData); 14 15 } 16 17 public static final Parcelable.Creator<MyParcelable> CREATOR 18 19 = new Parcelable.Creator<MyParcelable>() { 20 21 public MyParcelable createFromParcel(Parcel in) { 22 23 return new MyParcelable(in); 24 25 } 26 27 public MyParcelable[] newArray(int size) { 28 29 return new MyParcelable[size]; 30 31 } 32 33 }; 34 35 private MyParcelable(Parcel in) { 36 37 mData = in.readInt(); 38 39 } 40 41 }
定义各种内置类型的数据,然后在writeToParcel分别根据不同的类型调用对应类型的
out.writeXXX(mData);在构造方法中,分别调用in.readXX()即可。
然后就可以调用Intent putExtra(String name, Parcelable value)去放入该自定义类型数据,调用<T extends Parcelable> T getParcelableExtra(String name)获取该自定义类型数据。