美文网首页
Parcelable实战

Parcelable实战

作者: 劲火星空 | 来源:发表于2019-11-18 14:44 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Parcelable实战

          本文链接:https://www.haomeiwen.com/subject/ubfbictx.html