您的位置:首页 > 移动开发 > Android开发

Android:Intent传递数据的几种类型和源码实现

2015-08-08 14:40 507 查看
[java] view
plaincopy

public class Intent implements Parcelable, Cloneable {   //... private String mAction;  

    private Uri mData;  

    private String mType;  

    private String mPackage;  

    private ComponentName mComponent;  

    private int mFlags;  

    private HashSet<String> mCategories;  

    private Bundle mExtras;  

    private Rect mSourceBounds;  

Intent也是继承了Parcelable的接口。

个人理解,Intent应该只是一个数据参数的载体,真正将两个Acitivity/Service通信起来的是Binder接口(C/S架构)。

第一类:简单或基本数据类型

[java] view
plaincopy

Intent putExtra(String name, int[] value)  

Intent putExtra(String name, float value)  

Intent putExtra(String name, byte[] value)  

Intent putExtra(String name, long[] value)  

Intent putExtra(String name, float[] value)  

Intent putExtra(String name, long value)  

Intent putExtra(String name, String[] value)  

Intent putExtra(String name, boolean value)  

Intent putExtra(String name, boolean[] value)  

Intent putExtra(String name, short value)  

Intent putExtra(String name, double value)  

Intent putExtra(String name, short[] value)  

Intent putExtra(String name, String value)  

Intent putExtra(String name, byte value)  

Intent putExtra(String name, char[] value)  

Intent putExtra(String name, CharSequence[] value)  

本质上仍然是通过一个Bundle(private Bundle mExtras;)来实现:

[java] view
plaincopy

public Intent putExtra(String name, long value) {  

     if (mExtras == null) {  

         mExtras = new Bundle();  

     }  

     mExtras.putLong(name, value);  

     return this;  

 }  

 第二类:传递一个Bundle

[java] view
plaincopy

public Intent putExtra(String name, Bundle value) {  

        if (mExtras == null) {  

            mExtras = new Bundle();  

        }  

        mExtras.putBundle(name, value);  

        return this;  

    }  

 第三类:传递Serializable对象

[java] view
plaincopy

public Intent putExtra(String name, Serializable value) {  

        if (mExtras == null) {  

            mExtras = new Bundle();  

        }  

        mExtras.putSerializable(name, value);  

        return this;  

    }  

 第四类:Parcelable对象

[java] view
plaincopy

public Intent putExtra(String name, Parcelable value) {  

        if (mExtras == null) {  

            mExtras = new Bundle();  

        }  

        mExtras.putParcelable(name, value);  

        return this;  

}  

public Intent putExtra(String name, Parcelable[] value) {  

        if (mExtras == null) {  

            mExtras = new Bundle();  

        }  

        mExtras.putParcelableArray(name, value);  

        return this;  

    }  

第五类:Intent

[java] view
plaincopy

public Intent putExtras(Intent src) {  

       if (src.mExtras != null) {  

           if (mExtras == null) {  

               mExtras = new Bundle(src.mExtras);  

           } else {  

               mExtras.putAll(src.mExtras);  

           }  

       }  

       return this;  

   }  

归根结底都是通过Bundle来实现数据封装。而Bundle则是通过Map的数据结构来存储数据。

mMap = new HashMap<String, Object>();

mParcelledData

两者同时只有一个有效。

一旦unparcel以后,mParcelledData

的数据将被填充到mMap中,同时值为null。在writeToParcel和readFromParcel中则直接使用mParcelledData.此时一般通过IBinder关联两个进程的通信。

关于Bundle则是实现了Parcelable接口的类,通过上面提到的HashMap和一个Parcel来存储数据。

[java] view
plaincopy

public final class Bundle implements Parcelable, Cloneable {  

    private static final String LOG_TAG = "Bundle";  

    public static final Bundle EMPTY;  

  

    static {  

        EMPTY = new Bundle();  

        EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>());  

    }  

  

    // Invariant - exactly one of mMap / mParcelledData will be null  

    // (except inside a call to unparcel)  

  

    /* package */ Map<String, Object> mMap = null;  

  

    /* 

     * If mParcelledData is non-null, then mMap will be null and the 

     * data are stored as a Parcel containing a Bundle.  When the data 

     * are unparcelled, mParcelledData willbe set to null. 

     */  

    /* package */ Parcel mParcelledData = null;  

[java] view
plaincopy

 public void putFloat(String key, float value) {  

        unparcel();//首先解析出mParcelledData到mMap  

        mMap.put(key, value);  

    }  

  

   

/* package */ synchronized void unparcel() {  

        if (mParcelledData == null) {  

            return;  

        }  

  

        int N = mParcelledData.readInt();  

        if (N < 0) {  

            return;  

        }  

        if (mMap == null) {  

            mMap = new HashMap<String, Object>();  

        }  

        mParcelledData.readMapInternal(mMap, N, mClassLoader);  

        mParcelledData.recycle();  

        mParcelledData = null;//回收以后值为null  

    }  

从上面我们可以看出Parcel的写入和读出顺序是一致的。如果元素是list读出时需要先new一个ArrayList传入,否则会报空指针异常。如下:

list = new ArrayList<String>();
in.readStringList(list);


 PS: 在自己使用时,read数据时误将前面int数据当作long读出,结果后面的顺序错乱,报如下异常,当类字段较多时务必保持写入和读取的类型及顺序一致。

11-21 20:14:10.317: E/AndroidRuntime(21114): Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@4126ed60: Unmarshalling unknown type code 3014773 at offset 164


 

4、高级功能上

Serializable序列化不保存静态变量,可以使用Transient关键字对部分字段不进行序列化,也可以覆盖writeObject、readObject方法以实现序列化过程自定义

 

其他:

android.os.BadParcelableException: ClassNotFoundException
when unmarshalling

 

参考:

http://developer.android.com/reference/android/os/Parcelable.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: