Android Coding

使用AIDL(二)传递数据

2016-07-27  本文已影响468人  李俊的博客

AIDL默认支持的数据类型

IData.aidl

package jun.server;

// Declare any non-default types here with import statements

interface IBaseData {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    // 不支持short类型
    void basicTypes(byte aByte, int anInt, long aLong,
            boolean aBoolean,
            float aFloat, double aDouble,
            char aChar,
            String aString, CharSequence aCharSequence,
            inout List<String> aList);
}

除short外的Java八大基本数据类型,String、CharSequence、包含前面支持的数据类型的List。

传递自定义数据类型

1、服务端

1)创建自定义数据类型Person类必须继承Parcelable,这样对象才能使用于传输或存储。
app/src/main/java/jun.server.model/Person.java

public class Person implements Parcelable {

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(Parcel source) {

        this.name = source.readString();
        this.age = source.readInt();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(name);
        dest.writeInt(age);
    }

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

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2)创建Person类对应的AIDL文件
app/src/main/aidl/jun.server.model/Person.aidl

// Person.aidl
package jun.server.model;

// Declare any non-default types here with import statements

parcelable Person;

3)创建AIDL接口文件
ICustomData.aidl

// ICustomData.aidl
package jun.server;

// Declare any non-default types here with import statements

// 注意:Person.aidl和Person.java的位置要一致
// 需要导入自定义数据的类型
import jun.server.model.Person;

interface ICustomData {

    List<Person> add(in Person person);
}

其中add(in Person person)里面有个in这是什么意思?
  首先Person在发送方发送之前作为输出需要进行打包才能够传输,然后在接收方收到后作为输入需要进行拆包还原。而无论是打包还是拆包都非常消耗资源,所以如果只是作为输入那就是in,只是作为输出就是out,同时作为输入输出就是inout。这里由于Person是从客户端传过来的,所以是作为输入也就是in。

4)创建服务
RemoteService.java

/**
 * 远程Service
 */
public class RemoteService extends Service {
    
    private ArrayList<Person> persons;

    // 解释:Stub是继承Binder的
    ICustomData.Stub mBinder = new ICustomData.Stub() {

        @Override
        public List<Person> add(Person person) throws RemoteException {
            persons.add(person);
            return persons;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 服务销毁前将Binder置空,方便垃圾回收器回收资源。
        mBinder = null;
    }
}

5)记得注册Service

<service android:name=".RemoteService">
    <intent-filter>
        <action android:name="jun.server.RemoteService"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</service>
2、客户端

1)直接将服务端的Person.aidl、ICustomData.aidl和Person.java拷贝到客户端
app/src/main/aidl/jun.server.model/Person.aidl
app/src/main/aidl/jun.server/ICustomData.aidl
app/src/main/java/jun.server.model/Person.java
注意:包名一样。
  2)创建Activity的布局
activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="绑定服务"/>

    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解除绑定"/>

    <Button
        android:id="@+id/invoke_method"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="调用远程服务的方法"/>
</LinearLayout>

3)在Activity中绑定远程服务并调用它的方法

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private ICustomData mICustomData;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 拿到远程服务的代理
            mICustomData = ICustomData.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mICustomData = null;
        }
    };

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

        findViewById(R.id.bind_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 设置Intent目标是jun.server包的RemoteService
                Intent intent = new Intent("jun.server.RemoteService");
                intent.setPackage("jun.server");
                bindService(intent, serviceConnection, BIND_AUTO_CREATE);
                Toast.makeText(MainActivity.this, "已绑定服务", Toast.LENGTH_SHORT).show();
            }
        });

        findViewById(R.id.unbind_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (serviceConnection != null) {
                    unbindService(serviceConnection);
                    // 解除绑定时需要回收mIStudent连接资源
                    mICustomData = null;
                    Toast.makeText(MainActivity.this, "已解除绑定", Toast.LENGTH_SHORT).show();
                }
            }
        });

        findViewById(R.id.invoke_method).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mICustomData != null) {
                    try {
                        List<Person> persons = mICustomData.add(new Person("Tom", 18));
                        Log.i(TAG, persons.toString());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "请先绑定服务", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
3、运行

先运行服务端再运行客户端,点击“绑定服务”按钮让客户端绑定服务端的服务,再点击“调用远程服务的方法”按钮调用服务端的getName()方法,最后点击“解除绑定”按钮解除绑定。运行结果如下:

I/MainActivity: [Person{name='Tom', age=18}]

参考

墨客网:AIDL-小白成长记(视频教程)

上一篇下一篇

猜你喜欢

热点阅读