Parcelable實(shí)戰(zhàn)

Android開發(fā)過程中谤祖,無法將對(duì)象的引用傳給Activities或者Fragments油宜,我們需要將這些對(duì)象放到一個(gè)Intent或者Bundle里面昂勉,然后再傳遞敲街,這就需要用到序列化和反序列化。

  • 序列化分類
  • Parcelable原理
  • Parcelable使用
  • 回調(diào)接口傳遞
  • 注意事項(xiàng)

序列化分類

(1)Serializable 是java的序列化技術(shù),使用簡(jiǎn)單摆尝,頻繁的IO操作温艇,效率低

(2)Parcelable 是Android為我們提供的序列化的接口,使用稍微復(fù)雜堕汞,內(nèi)存操作勺爱,效率高

(3)Parcelable不能使用在要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況,因?yàn)镻arcelable在外界有變化的情況下不能很好的保證數(shù)據(jù)的持續(xù)性讯检。盡管Serializable效率低點(diǎn)琐鲁,但此時(shí)還是建議使用Serializable。存儲(chǔ)到設(shè)備或者網(wǎng)絡(luò)傳輸上選擇Serializable人灼。

Parcelable原理

(1)Parcelable是Android特有的序列化API围段,它的出現(xiàn)是為了解決Serializable在序列化的過程中消耗資源嚴(yán)重的問題,但是因?yàn)楸旧硎褂眯枰謩?dòng)處理序列化和反序列化過程投放,會(huì)與具體的代碼綁定奈泪,使用較為繁瑣,一般只獲取內(nèi)存數(shù)據(jù)的時(shí)候使用灸芳。

(2)Parcelable依賴于Parcel段磨,Parcel的意思是包裝,實(shí)現(xiàn)原理是在內(nèi)存中建立一塊共享數(shù)據(jù)塊耗绿,序列化和反序列化均是操作這一塊的數(shù)據(jù)苹支,如此來實(shí)現(xiàn)。


在這里插入圖片描述

Parcelable使用

1误阻、首先創(chuàng)建一個(gè)ParcelBean對(duì)象债蜜,繼承自Parcelable,這個(gè)就是我們要將其序列化的對(duì)象究反,對(duì)象里邊的屬性有數(shù)值寻定、boolean、字符串精耐、對(duì)象狼速、數(shù)組和鏈表等各種類型,重點(diǎn)是看下各種類型的序列化和反序列化的方式卦停。

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;
    //回調(diào)接口對(duì)象
    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()); // 讀取對(duì)象需要提供一個(gè)類加載器去讀取,因?yàn)閷懭氲臅r(shí)候?qū)懭肓祟惖南嚓P(guān)信息
        source.readTypedList(itmeList, ParcelItemBean.CREATOR); //對(duì)應(yīng)writeTypeList
        array = source.createStringArray();
        //回調(diào)接口
        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);
        //回調(diào)接口對(duì)象
        dest.writeParcelable(parcelCallbackBean, flags);
    }
}

2向胡、里邊有一個(gè)ParcelItemBean的子對(duì)象,如下

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惊完、對(duì)象序列化后需要通過Activity來加到ParcelableActivity的Intent中發(fā)送出去

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;
        //寫入對(duì)象
        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;
        //寫入數(shù)組
        String array[] = new String[]{"num1", "num2", "num3"};
        parcelBean.array = array;
        //寫入回調(diào)接口
        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僵芹、上面是發(fā)送的Activity,還需要一個(gè)接收的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]);

        //獲取傳遞過來的接口對(duì)象
        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("我是傳遞過來的點(diǎn)擊事件");
    }
}

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

回調(diào)接口傳遞

上面有一個(gè)回調(diào)接口的對(duì)象的傳遞,這里單獨(dú)拿出來說一下,首先建立一個(gè)ParcelCallbackListenerBinder對(duì)象件豌,繼承自Binder疮方,用來管理這兩個(gè)回調(diào)接口

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);
    }
}

然后再將這個(gè)封裝的回調(diào)接口,封裝到ParcelCallbackBean中茧彤,這個(gè)也是繼承自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里進(jìn)行回調(diào)骡显,通過clickCallBack方法進(jìn)行回調(diào),在ParcelableActivity里進(jìn)行回調(diào)的接收棘街。我們來看一下點(diǎn)擊回調(diào)的結(jié)果

parcel_call_back: clickCallBack我是傳遞過來的點(diǎn)擊事件
parcel_call_back: clickCallBack我是傳遞過來的點(diǎn)擊事件
parcel_call_back: clickCallBack我是傳遞過來的點(diǎn)擊事件

注意事項(xiàng)

(1)Parcelable使用的時(shí)候要注意ParcelBean和writeToParcel也就是讀寫時(shí)各個(gè)屬性的順序蟆盐,一定要一致承边,不然會(huì)存在問題遭殉。

(2)接口回調(diào)的ParcelCallbackListenerBinder類要繼承自Binder,這個(gè)問啥我還沒搞清楚博助,猜測(cè)應(yīng)該和Parcelable底層使用的Binder進(jìn)程通信有關(guān)险污,歡迎各位大佬指教。

尊重作者富岳,尊重原創(chuàng)蛔糯,參考文章:
http://www.reibang.com/p/df35baa91541
https://blog.csdn.net/hacker_crazy/article/details/80840868
https://www.cnblogs.com/tangZH/p/10998065.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窖式,隨后出現(xiàn)的幾起案子蚁飒,更是在濱河造成了極大的恐慌,老刑警劉巖萝喘,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淮逻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡阁簸,警方通過查閱死者的電腦和手機(jī)爬早,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來启妹,“玉大人筛严,你說我怎么就攤上這事∪拿祝” “怎么了桨啃?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)檬输。 經(jīng)常有香客問我优幸,道長(zhǎng),這世上最難降的妖魔是什么褪猛? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任网杆,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碳却。我一直安慰自己队秩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布昼浦。 她就那樣靜靜地躺著馍资,像睡著了一般。 火紅的嫁衣襯著肌膚如雪关噪。 梳的紋絲不亂的頭發(fā)上鸟蟹,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音使兔,去河邊找鬼建钥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛虐沥,可吹牛的內(nèi)容都是我干的熊经。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼欲险,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼镐依!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起天试,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤槐壳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后喜每,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體务唐,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年灼卢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绍哎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鞋真,死狀恐怖崇堰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涩咖,我是刑警寧澤海诲,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站檩互,受9級(jí)特大地震影響特幔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闸昨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一蚯斯、第九天 我趴在偏房一處隱蔽的房頂上張望薄风。 院中可真熱鬧,春花似錦拍嵌、人聲如沸遭赂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撇他。三九已至,卻和暖如春狈蚤,著一層夾襖步出監(jiān)牢的瞬間困肩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工脆侮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锌畸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓他嚷,卻偏偏與公主長(zhǎng)得像蹋绽,于是被迫代替她去往敵國(guó)和親芭毙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筋蓖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容