Android AIDL创建Service
简述:
1. Android开发中会用到Service这个类,Service用于实现进程间方法的调用,UI中调用音乐播放服务就用到Service,起到跨进程通信的作用
2. AIDL: Android Interface Definition Language,Android内部进程通信接口的描述语言,通过他可以定义进程间通信接口,结合service在后台运作,暴露接口用来和当前程序通信
3,.Android 提供了Parcel类型,Parcel用作封装数据的容器,封装后的数据可以通过Intent或IPC传递,除了基本类型之外,只有实现了Parcelable接口的类才能被放入Parcel
本文参考:
http://blog.csdn.net/stonecao/article/details/6425019
http://blog.csdn.net/liuhe688/article/details/6409708
http://blog.sina.com.cn/s/blog_78e3ae430100pxba.html
知识点:
1. Android service
2. AIDL的使用,在aidl文件中复杂类型的导入
3. Parcelable接口的使用
项目工程文件目录
其中gen下的com.atp.aidl是AIDL自带生成的(clean->build之后就能生成)
代码:
com.atp.aidl包
Fruit.java
package com.atp.aidl;import android.os.Parcel;import android.os.Parcelable;public class Fruit implements Parcelable {private String name;private Integer size;public Fruit(String name, Integer size) {this.name = name;this.size = size;}public Fruit(Parcel source) { readFromParcel(source);}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getsize() {return size;}public void setsize(Integer size) {this.size = size;}@Overridepublic String toString() {return "[name: " + name + ", size: " + size + "]";} //AIDL needs CREATOR static final android.os.Parcelable.Creator<T> to call service public static final Parcelable.Creator<Fruit> CREATOR = new Parcelable.Creator<Fruit>() { @Override public Fruit createFromParcel(Parcel source) { return new Fruit(source); } @Override public Fruit[] newArray(int size) { return new Fruit[size]; } }; @Overridepublic int describeContents() {return 0;}//write and read must in the same sequence@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(size);} public void readFromParcel(Parcel source) { name = source.readString(); size = source.readInt(); } }
Fruit.aidl 复杂类型的aidl文件
package com.atp.aidl;parcelable Fruit;
ITestService.aidl的接口文件
package com.atp.aidl;import com.atp.aidl.Fruit;interface ITestService {String getSomething();Fruit getFruit();}
com.atp.service包
package com.atp.service;import com.atp.aidl.Fruit;import com.atp.aidl.ITestService;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;public class MyService extends Service{public static final String TAG = "com.atp.ui.MyService";private class MyServiceImpl extends ITestService.Stub{@Overridepublic String getSomething() throws RemoteException {Log.e(TAG, "getSomething");return "Apple";}@Overridepublic Fruit getFruit() throws RemoteException {Fruit fruit = new Fruit("Banana", 10);return fruit;}}@Overridepublic IBinder onBind(Intent arg0) {//return implementation of AIDLreturn new MyServiceImpl();}@Overridepublic void onDestroy() {Log.e(TAG, "Release MyService");super.onDestroy();}}
com.atp.ui包
MainActivity.java
package com.atp.ui;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.atp.R;import com.atp.aidl.Fruit;import com.atp.aidl.ITestService;import com.atp.service.MyService;public class MainActivity extends Activity {public static final String TAG = "com.atp.ui.MainActivity";private Button myBtn = null;private TextView myTv = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main_activity);myBtn = (Button) findViewById(R.id.myBtn);myTv = (TextView) findViewById(R.id.myTv);myBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {bindMyService();}});}private ITestService iService = null;private ServiceConnection conn = new ServiceConnection(){private String resultFromService;private Fruit fruitFromService;@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//return AIDL object,then call methods of AIDLiService = ITestService.Stub.asInterface(service);try {resultFromService = iService.getSomething();fruitFromService = iService.getFruit();} catch (RemoteException e) {Log.e(TAG, "Error while call on iService!");e.printStackTrace();}Log.e(TAG, "something is:" + resultFromService);myTv.setText("something is:" + resultFromService + "\n"+ "fruit: " + fruitFromService.toString());}@Overridepublic void onServiceDisconnected(ComponentName arg0) {Log.i(TAG, "release iService");}}; private void bindMyService(){ Intent intent = new Intent(this, MyService.class); startService(intent); bindService(intent, conn, Context.BIND_AUTO_CREATE); } }
视图xml文件
main_activity.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mainRelativeLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/myBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start" android:textSize="22dip" /> <TextView android:id="@+id/myTv" android:layout_width="500dip" android:layout_height="100dip" android:layout_below="@id/myBtn" android:text="Text Area" android:textSize="22dip"/></RelativeLayout>
下面是在AndroidManifest.xml注册这个service
其中对于android:process这一属性的解释:
android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.atp" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".ui.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".service.MyService" android:process=":remote"> <intent-filter> <action android:name=".aidl.ITestService" /> </intent-filter> </service> </application></manifest>
这是由com.atp.aidl下的aidl文件 自动generate出来的文件
ITestService.java
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Users\\anialy.anialy-PC\\Desktop\\eclipse_work_space_2\\AndroidTestProject\\src\\com\\atp\\aidl\\ITestService.aidl */package com.atp.aidl;public interface ITestService extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.atp.aidl.ITestService{private static final java.lang.String DESCRIPTOR = "com.atp.aidl.ITestService";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.atp.aidl.ITestService interface, * generating a proxy if needed. */public static com.atp.aidl.ITestService asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.atp.aidl.ITestService))) {return ((com.atp.aidl.ITestService)iin);}return new com.atp.aidl.ITestService.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_getSomething:{data.enforceInterface(DESCRIPTOR);java.lang.String _result = this.getSomething();reply.writeNoException();reply.writeString(_result);return true;}case TRANSACTION_getFruit:{data.enforceInterface(DESCRIPTOR);com.atp.aidl.Fruit _result = this.getFruit();reply.writeNoException();if ((_result!=null)) {reply.writeInt(1);_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.atp.aidl.ITestService{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}@Override public java.lang.String getSomething() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getSomething, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}@Override public com.atp.aidl.Fruit getFruit() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();com.atp.aidl.Fruit _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getFruit, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {_result = com.atp.aidl.Fruit.CREATOR.createFromParcel(_reply);}else {_result = null;}}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_getSomething = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getFruit = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);}public java.lang.String getSomething() throws android.os.RemoteException;public com.atp.aidl.Fruit getFruit() throws android.os.RemoteException;}
效果,点击之后获取service中的方法,返回所需的数据: