zoukankan      html  css  js  c++  java
  • Android间的进程通讯(传递复杂对象)

    Android间的进程通讯(传递复杂对象)

    完成对复杂对象的序列化

    在Android中传递复杂数据类型的时候要通过将序列化,在Android中提供了一个接口Parcelable来实现对对象的序列化。

    下面对需要传输的对象进行序列化操作,首先看自定义的类Person。

    package com.example.service_parcelable_conmmute.bean;
    
    import android.graphics.Bitmap;
    /**
     * 用来传输的对象结构
     * @author Xinyuyu
     *
     */
    public class Person {
        private String name;
        private String age;
        private Bitmap figure;
        
        public Person(){
            
        }
        public Person(String name, String age, Bitmap figure){
            this.name = name;
            this.age = age;
            this.figure =figure;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAge() {
            return age;
        }
        public void setAge(String age) {
            this.age = age;
        }
        public Bitmap getFigure() {
            return figure;
        }
        public void setFigure(Bitmap figure) {
            this.figure = figure;
        }
    }

    这个类就是一般的JavaBean包含了一些get/set方法,我们要做的就是在进程之间传递该对象的值。所以就要将该对象进行序列化,下面实现一个类来完成该任务。

    建立ParcelablePerson类,来完成对Person的序列化和反序列化的操作。其代码如下:

    public class ParcelablePerson implements Parcelable {
        Person person = new Person();
        
        public Person getPerson() {
            return person;
        }
        public void setPerson(Person person) {
            this.person = person;
        }
        public ParcelablePerson(Person person){
            this.person = person;
        }
        public ParcelablePerson(Parcel source){
            person.setName(source.readString());
            person.setAge(source.readString());
            person.setFigure((Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
        }
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(person.getName());
            dest.writeString(person.getAge());
            dest.writeParcelable(person.getFigure(), PARCELABLE_WRITE_RETURN_VALUE);
        }
        
        public static final Parcelable.Creator<ParcelablePerson> CREATOR = new Parcelable.Creator<ParcelablePerson>(){
    
            @Override
            public ParcelablePerson createFromParcel(Parcel source) {
                return new ParcelablePerson(source);
            }
            @Override
            public ParcelablePerson[] newArray(int size) {
                return new ParcelablePerson[size];
            }
        };
    }

    这段代码中完成了对Person对象的序列化与反序列化,实现Parcelable接口要做的就是来重写几个方法(分别完成序列化和反序列化),writeToParcel(Parcel dest, int flags)完成的就是对对象的序列化

    其中的参数Parcel是一个容器,将对象放入其中就是序列化的过程。而CREATOR中的createFormParcel(Parcel source)来完成的就是反序列化,可以返回一个复杂的对象。实现了这写,就完成了对复杂对象的序列化和反序列化操作,这样我们就可以对它进行传输了。

    完成绑定服务,完成进程中的通讯

    以上我们只是完成了对一个复杂对象的序列化,下面我们要做的是建立服务,并且完成传输。

    首先我们要做的是创建一个服务,在Android中创建一个服务要做的就是去实现Service接口。下面是发送对象的一个服务代码

    public class ServiceForSendObject extends Service {
        private static final String MSG = "MESSAGE";
        private ParcelablePerson parcelablePerson;
        private Person person;
        // =====================================
        SendObject.Stub sendBinder = new Stub(){
    
            @Override
            public ParcelablePerson getPersonInfo() throws RemoteException {
                Log.i(MSG, "调用getPersonInfo()接口实现,返回一个序列化的对象");
                return parcelablePerson;
            }};
        // =====================================
        
        @Override
        public void onCreate() {
            person = new Person("xinyuyu", "25", BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_launcher)));
            parcelablePerson = new ParcelablePerson(person);
            super.onCreate();
            Log.i(MSG, "回调onCreate()创建服务");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(MSG, "回调onStartCommand()启动服务");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.i(MSG, "回调onUnbind解绑服务");
            return super.onUnbind(intent);
        }
    
        @Override
        public void onDestroy() {
            Log.i(MSG, "回调onDestroy销毁服务");
            super.onDestroy();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.i(MSG, "回调onBind()方法绑定服务");
            return sendBinder;
        }
    }

    在该段代码中输出各个阶段的一些信息,关键是在onCreat()方法中完成实例化一个对象,并且对该对象完成序列化操作。在分割线之间的代码是关键代码,注意在IBinder()中返回的是一个SendObject.Stub对象。而这个类是如何生成的呢?我们在完成进程间传输的时候需要用到Android中的AIDL语言来定义一个接口,下面我们来建立一个名为SendObject的aidl文件,SendObject.aidl

    package com.example.service_parcelable_conmmute_service.aidl;
    
    import com.example.service_parcelable_conmmute.bean.ParcelablePerson;
    
    interface SendObject {
        ParcelablePerson getPersonInfo();
    }

    这个接口中的import会报错,这时候需要在建立一个AIDL文件,将其名字设置为和序列化类一样,这里就起做ParcelablePerson.aidl。其内容如下

    package com.example.service_parcelable_conmmute.bean;

    parcelable ParcelablePerson;

    完成这些就不会有错误了。

    这时候你会发现在gen目录下有一个和你的aidl名字一样Java文件即SendObject.java。而我们使用的SendObject.Stub就在其中。打开这个文件看一下,你会发现SendObject.Stub是这样一个类,实现了SendObject接口并且继承了android.os.Binder类。这样我们就重写SendObject方法,将其实现功能。就是分割线直接的代码。

    public static abstract class Stub extends android.os.Binder 
    implements com.example.service_parcelable_conmmute_service.aidl.SendObject

    还要注意一点进程间的服务通讯应该更改AndroidManifest.xml文件的属性,如下

    <service android:name="com.example.service_parcelable_conmmute.service.ServiceForSendObject"
    android:process=":remote">
    <intent-filter>
            <action android:name="com.example.service_parcelable_conmmute.service.SEND_OBJECT"/>
                <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </service>

    这样可以完成隐式的传递Intent。完成了这些,服务端就完成了。这个时候可以运行下代码。

    启动界面

    点击初始化服务后,可以看到服务开始运行

    红色框中为我们的服务。

    点击两按钮后LogCat输出的信息

    从中可以看出来这个服务的生命周期。

    以上我们就完成了服务端的工作了,下面来进行客户端的完成。

    在客户端我们首先需要的是将服务端写好的那些AIDL文件和实体类拷贝到该工程下(连同包名进行拷贝)如下图

    然后我们所要完成的就是完成客户端的activity程序了。将俩个程序进行联系的就是我们的SendObject接口。看下面代码

    public class A extends Activity {
        
        private Button show_button;
        private TextView show_name_age;
        private ImageView show_image;
        private Button unbind_ser;
        private SendObject sendObject;
        private ParcelablePerson parcelablePerson;
        private Person person;
        private ServiceConnection connection = new ServiceConnection(){
            
            // 建立绑定后service程序调用onBind()方法,返回一个IBinder对象
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                sendObject = SendObject.Stub.asInterface(service);    
                try {
                    parcelablePerson = sendObject.getPersonInfo();
                    person = parcelablePerson.getPerson();
                    Log.i("", person.getName());    
                    show_name_age.setText(person.getName() + "
    " + person.getAge());
                    show_image.setImageBitmap(person.getFigure());
                    
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.i("", "error");            
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            
            
            super.onCreate(savedInstanceState);
            setContentView(R.layout.a);
            show_button = (Button)this.findViewById(R.id.button1);
            show_name_age = (TextView)this.findViewById(R.id.textView1);
            show_image = (ImageView)this.findViewById(R.id.imageView1);
            unbind_ser = (Button)this.findViewById(R.id.button2);
            
            show_button.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // 隐式传递intent
                    Intent intent = new Intent();
                    intent.setAction("com.example.service_parcelable_conmmute.service.SEND_OBJECT");
                    bindService(intent, connection, BIND_AUTO_CREATE);
                }});
            // 解除绑定(服务会在activity销毁后自动销毁)
            unbind_ser.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    unbindService(connection);  
                }
                
            });
    
        }
    }

    将该程序与服务进行绑定就用到了bindService()方法,看该方法中的参数,第一个是一个intent,第二个是一个ServiceConnection类,与服务建立连接,接收到onBind()传输的数据。从这个方法中我们就得到了传递过来的对象。运行客户端程序

    点击第一个按钮后会显示出来一个Person对象的信息。这就说明数据从服务端传输了过来。

    LogCat输出的信息

  • 相关阅读:
    【五】服务熔断、降级 —— Hystrix(豪猪)
    32. Springboot 系列(八)动态Banner与图片转字符图案的手动实现
    31.【微服务架构】SpringCloud之Feign(五)
    新SQL temp
    lombok踩坑与思考
    lombok注解介绍
    叉乘实现角色和敌人的位置判断(左上,左下,右上,右下)
    2维,3维向量单位化
    2个2D向量计算交点的夹角和补角
    Unity编辑器-创建单独编辑框,折叠框,提示框
  • 原文地址:https://www.cnblogs.com/xinyuyu/p/3718678.html
Copyright © 2011-2022 走看看