Parcelable實戰

Android開發過程中,無法將對象的引用傳給Activities或者Fragments,我們需要將這些對象放到一個Intent或者Bundle裏面,然後再傳遞,這就需要用到序列化和反序列化。

  • 序列化分類
  • Parcelable原理
  • Parcelable使用
  • 回調接口傳遞
  • 注意事項

序列化分類

(1)Serializable 是java的序列化技術,使用簡單,頻繁的IO操作,效率低

(2)Parcelable 是Android爲我們提供的序列化的接口,使用稍微複雜,內存操作,效率高

(3)Parcelable不能使用在要將數據存儲在磁盤上的情況,因爲Parcelable在外界有變化的情況下不能很好的保證數據的持續性。儘管Serializable效率低點,但此時還是建議使用Serializable。存儲到設備或者網絡傳輸上選擇Serializable。

Parcelable原理

(1)Parcelable是Android特有的序列化API,它的出現是爲了解決Serializable在序列化的過程中消耗資源嚴重的問題,但是因爲本身使用需要手動處理序列化和反序列化過程,會與具體的代碼綁定,使用較爲繁瑣,一般只獲取內存數據的時候使用。

(2)Parcelable依賴於Parcel,Parcel的意思是包裝,實現原理是在內存中建立一塊共享數據塊,序列化和反序列化均是操作這一塊的數據,如此來實現。
在這裏插入圖片描述

Parcelable使用

1、首先創建一個ParcelBean對象,繼承自Parcelable,這個就是我們要將其序列化的對象,對象裏邊的屬性有數值、boolean、字符串、對象、數組和鏈表等各種類型,重點是看下各種類型的序列化和反序列化的方式。

import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;

public class ParcelBean implements Parcelable{

    public int count;
    public boolean flag;
    public String name;
    public ParcelItemBean itemBean;
    public List<ParcelItemBean> itmeList = new ArrayList<>();
    public String[] array;
    //回調接口對象
    public ParcelCallbackBean parcelCallbackBean;

    public ParcelBean() {
        super();
    }

    public ParcelBean(Parcel source) {
        super();
        count = source.readInt();
        flag = source.readByte() != 0;
        name = source.readString();
        itemBean= source.readParcelable(ParcelItemBean.class.getClassLoader()); // 讀取對象需要提供一個類加載器去讀取,因爲寫入的時候寫入了類的相關信息
        source.readTypedList(itmeList, ParcelItemBean.CREATOR); //對應writeTypeList
        array = source.createStringArray();
        //回調接口
        parcelCallbackBean= source.readParcelable(ParcelCallbackBean.class.getClassLoader());
    }

    public static final Creator<ParcelBean> CREATOR = new Creator<ParcelBean>() {
        @Override
        public ParcelBean createFromParcel(Parcel in) {
            return new ParcelBean(in);
        }

        @Override
        public ParcelBean[] newArray(int size) {
            return new ParcelBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(count);
        dest.writeByte((byte) (flag ? 1 : 0));
        dest.writeString(name);
        dest.writeParcelable(itemBean, flags);
        dest.writeTypedList(itmeList);
        dest.writeStringArray(array);
        //回調接口對象
        dest.writeParcelable(parcelCallbackBean, flags);
    }
}

2、裏邊有一個ParcelItemBean的子對象,如下

import android.os.Parcel;
import android.os.Parcelable;

public class ParcelItemBean implements Parcelable {
    public String itemName;

    public ParcelItemBean(){
        super();
    }

    protected ParcelItemBean(Parcel in) {
        super();
        itemName = in.readString();
    }

    public static final Creator<ParcelItemBean> CREATOR = new Creator<ParcelItemBean>() {
        @Override
        public ParcelItemBean createFromParcel(Parcel in) {
            return new ParcelItemBean(in);
        }

        @Override
        public ParcelItemBean[] newArray(int size) {
            return new ParcelItemBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(itemName);
    }
}

3、對象序列化後需要通過Activity來加到ParcelableActivity的Intent中發送出去

import java.util.ArrayList;

public class ParcelableActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_parcelable);

        initView();
    }

    private void initView() {
        findViewById(R.id.parcel).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.parcel:
                parcelSend();
                break;
            default:
                break;
        }
    }

    private void parcelSend() {
        ParcelBean parcelBean = new ParcelBean();
        parcelBean.name = "lisi";
        parcelBean.flag = false;
        parcelBean.count = 66;
        //寫入對象
        ParcelItemBean parcelItemBean = new ParcelItemBean();
        parcelItemBean.itemName = "itmeNNN";
        parcelBean.itemBean = parcelItemBean;
        //寫入list
        ParcelItemBean itemBean1 = new ParcelItemBean();
        itemBean1.itemName = "item111";
        ParcelItemBean itemBean2 = new ParcelItemBean();
        itemBean2.itemName = "item222";
        ArrayList<ParcelItemBean> beanList = new ArrayList<>();
        beanList.add(itemBean1);
        beanList.add(itemBean2);
        parcelBean.itmeList = beanList;
        //寫入數組
        String array[] = new String[]{"num1", "num2", "num3"};
        parcelBean.array = array;
        //寫入回調接口
        ParcelCallbackListenerBinder.CallbackListener callbackListener = new ParcelCallbackListenerBinder.CallbackListener() {
            @Override
            public void onComplete(Object obj) {
                Log.d("parcel_call_back", "callBackComplete");
            }

            @Override
            public void onError(String msg) {
                Log.d("parcel_call_back", "callBackError");
            }

            @Override
            public void onCancel() {
                Log.d("parcel_call_back", "callBackCancel");
            }
        };
        ParcelCallbackListenerBinder.ClickCallbackListener clickCallbackListener = new ParcelCallbackListenerBinder.ClickCallbackListener() {
            @Override
            public void onClick(String channel) {
                Log.d("parcel_call_back", "clickCallBack"+channel);
            }
        };
        ParcelCallbackBean parcelCallbackBean = new ParcelCallbackBean(new ParcelCallbackListenerBinder(callbackListener, clickCallbackListener));
        parcelBean.parcelCallbackBean = parcelCallbackBean;

        Intent intent = new Intent(this, ParcelReceiveActivity.class);
        intent.putExtra("keyName", "zhangsan");
        intent.putExtra("parcel", parcelBean);
        startActivity(intent);

    }
}

4、上面是發送的Activity,還需要一個接收的ParcelReceiveActivity


public class ParcelReceiveActivity extends AppCompatActivity implements View.OnClickListener {

    ParcelCallbackBean mParcelCallbackBean;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_parcel_receive);

        initView();
    }

    private void initView() {
        findViewById(R.id.click_callback).setOnClickListener(this);
        Intent intent = getIntent();
        Log.d("ParcelReceiveActivity", "keyName = "+intent.getStringExtra("keyName"));

        ParcelBean parcelBean = intent.getParcelableExtra("parcel");
        Log.d("ParcelReceiveActivity", "parcelBean.name = "+parcelBean.name);
        Log.d("ParcelReceiveActivity", "parcelBean.flag = "+parcelBean.flag);
        Log.d("ParcelReceiveActivity", "parcelBean.count = "+parcelBean.count);
        Log.d("ParcelReceiveActivity", "parcelBean.itemBean.itemName = "+parcelBean.itemBean.itemName);
        Log.d("ParcelReceiveActivity", "parcelBean.itmeList.get(0).itemName = "+parcelBean.itmeList.get(0).itemName);
        Log.d("ParcelReceiveActivity", "parcelBean.itmeList.get(1).itemName = "+parcelBean.itmeList.get(1).itemName);
        Log.d("ParcelReceiveActivity", "parcelBean.array[0] = "+parcelBean.array[0]);
        Log.d("ParcelReceiveActivity", "parcelBean.array[1] = "+parcelBean.array[1]);

        //獲取傳遞過來的接口對象
        mParcelCallbackBean = parcelBean.parcelCallbackBean;


    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.click_callback:
                clickCallBack();
                break;
            default:
                break;
        }
    }

    private void clickCallBack() {
        mParcelCallbackBean.parcelCallbackListenerBinder.getClickCallbackListener().onClick("我是傳遞過來的點擊事件");
    }
}

5、在接收的Activity裏邊打印Log,如下

    ParcelReceiveActivity: keyName = zhangsan
    parcelBean.name = lisi
    parcelBean.flag = false
    parcelBean.count = 66
    parcelBean.itemBean.itemName = itmeNNN
    parcelBean.itmeList.get(0).itemName = item111
    parcelBean.itmeList.get(1).itemName = item222
    parcelBean.array[0] = num1
    parcelBean.array[1] = num2

回調接口傳遞

上面有一個回調接口的對象的傳遞,這裏單獨拿出來說一下,首先建立一個ParcelCallbackListenerBinder對象,繼承自Binder,用來管理這兩個回調接口

import android.os.Binder;

public class ParcelCallbackListenerBinder extends Binder{
    public CallbackListener callbackListener;
    public ClickCallbackListener clickCallbackListener;

    public ParcelCallbackListenerBinder(CallbackListener callbackListener, ClickCallbackListener clickCallbackListener) {
        this.callbackListener = callbackListener;
        this.clickCallbackListener = clickCallbackListener;
    }

    public CallbackListener getCallbackListener() {
        return callbackListener;
    }

    public ClickCallbackListener getClickCallbackListener() {
        return clickCallbackListener;
    }


    public static interface CallbackListener {
        void onComplete(Object obj);

        void onError(String msg);

        void onCancel();
    }

    public static interface ClickCallbackListener {
        void onClick(String channel);
    }
}

然後再將這個封裝的回調接口,封裝到ParcelCallbackBean中,這個也是繼承自Parcelable的

import android.os.Parcel;
import android.os.Parcelable;

import com.jd.test.phototest.activity.interfac.ParcelCallbackListenerBinder;

public class ParcelCallbackBean implements Parcelable{

    public ParcelCallbackListenerBinder parcelCallbackListenerBinder;

    public ParcelCallbackBean(ParcelCallbackListenerBinder binder) {
        parcelCallbackListenerBinder = binder;
    }

    protected ParcelCallbackBean(Parcel source) {
        Object object = source.readValue(ParcelCallbackListenerBinder.class.getClassLoader());
        if (object instanceof ParcelCallbackListenerBinder) {
            parcelCallbackListenerBinder = (ParcelCallbackListenerBinder) object;
        }
    }

    public static final Creator<ParcelCallbackBean> CREATOR = new Creator<ParcelCallbackBean>() {
        @Override
        public ParcelCallbackBean createFromParcel(Parcel in) {
            return new ParcelCallbackBean(in);
        }

        @Override
        public ParcelCallbackBean[] newArray(int size) {
            return new ParcelCallbackBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(parcelCallbackListenerBinder);
    }
}

在ParcelReceiveActivity裏進行回調,通過clickCallBack方法進行回調,在ParcelableActivity裏進行回調的接收。我們來看一下點擊回調的結果

parcel_call_back: clickCallBack我是傳遞過來的點擊事件
parcel_call_back: clickCallBack我是傳遞過來的點擊事件
parcel_call_back: clickCallBack我是傳遞過來的點擊事件

注意事項

(1)Parcelable使用的時候要注意ParcelBean和writeToParcel也就是讀寫時各個屬性的順序,一定要一致,不然會存在問題。

(2)接口回調的ParcelCallbackListenerBinder類要繼承自Binder,這個問啥我還沒搞清楚,猜測應該和Parcelable底層使用的Binder進程通信有關,歡迎各位大佬指教。

尊重作者,尊重原創,參考文章:
https://www.jianshu.com/p/df35baa91541
https://blog.csdn.net/hacker_crazy/article/details/80840868
https://www.cnblogs.com/tangZH/p/10998065.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章