android studio使用Aidl跨进程调用服务

来源:互联网 发布:王奕霏编程 编辑:程序博客网 时间:2024/06/03 20:13

以前就知道其大概代码流程,但是一直没有敲代码去实现,今天将其实现了,android studio下编写也遇到了一些小细节的问题,特此记录一下。
既然是模拟Aidl通讯,那么当然要编写两个应用了,一个提供服务给另一个应用调用,那么开始吧。
一、服务提供方应用编写
①.为了更全面一些,我编写了一个自定义类Book在Aidl之中传递,不同进程间传递自定义对象必须实现Parcelable接口,Serializable是不行的哦。Book类如下:

package com.lbb.aidltest.bean;import android.os.Parcel;import android.os.Parcelable;/** * 作者:李少波 * 邮箱:lishaobo@seengene.com * 日期:16/10/20 */public class Book implements Parcelable{    private String name;    private int id;    public Book(String name, int id) {        this.name = name;        this.id = id;    }    protected Book(Parcel in) {        name = in.readString();        id = in.readInt();    }    public static final Creator<Book> CREATOR = new Creator<Book>() {        @Override        public Book createFromParcel(Parcel in) {            return new Book(in);        }        @Override        public Book[] newArray(int size) {            return new Book[size];        }    };    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel parcel, int i) {        parcel.writeString(name);        parcel.writeInt(id);    }}

②.编写.Aidl文件,因为此处用到了自定义类的对象的传递,所以需要编写两类aidl文件,分别是定义服务接口的和定义自定义类的aidl文件。
a.定义服务接口。右键-new-aidl-aidl file,文件名随便定义,可以是服务的类名前边加I。就像一个接口文件一样声明对外开放的方法即可,此处需要注意的是:如果用到了自定义类,则需要显示的import进来,此处需要显示import com.lbb.aidltest.bean.Book,否则会”Execution failed for task :app:compileDebugAidl”。我的接口定义文件如下:

// IAidlInterface.aidlpackage com.lbb.aidltest;import com.lbb.aidltest.bean.Book;interface IAidlInterface { Book getBookByIndex(int index);}

b.定义需要在进程间传递的自定义类同名的.aidl文件,此处是Book.aidl。这一步不能右键创建aidl file了,因为输入Book会提示”Interface Name must be unique”,导致无法下一步。所以只能在aidl文件夹下创建和Book一样的包路径,并在路径下new-file,填入Book.aidl,手动输入文件内容如下(全程系统无任何提示输入。。汗):

package com.lbb.aidltest.bean;parcelable Book;

③.万事俱备,创建自己的AidlService继承自Service,在onBind中返回一个.Stub自类的对象供其它app中使用,我的服务代码如下:

package com.lbb.aidltest;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;import com.lbb.aidltest.bean.Book;/** * 作者:李少波 * 邮箱:lishaobo@seengene.com * 日期:16/10/20 */public class AidlService extends Service {    IAidlInterface.Stub mStub = new IAidlInterface.Stub() {        @Override        public Book getBookByIndex(int index) throws RemoteException {            Book book = null;            if(index ==0){                book = new Book("第一本书",0);            }            return book;        }    };    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mStub;    }}

至此服务供应方代码编写完毕,对了,还有一点很重要,记得在mainfest中声明服务的隐式intent-filter,因为其它app都是用隐式方式调用这个服务的:

 <service android:name=".AidlService"><intent-filter><action android:name="com.lbb.aidltest.AidlService"></action></intent-filter> </service>

二、调用其它app中可以被调用的服务。此处我调用我上一个app中的服务,前提是安装了上一个app哦。。使用过程分两步:
①.带上包名拷贝上一个app中的bean和aidl文件(包括自定义类以及接口的都要),也就是使用端要和提供端的bean的包路径以及aidl的包路径是一样的,没有路径创造路径也要保证一样。
②.在Activity中愉快的引用其他app服务吧,这里是隐式调用的,如果直接隐式调用在android 5.0之后的环境下会报”只能显式启动Service”的错误,此处用了一个网上荡的方法,可以用隐式打开服务了,我是这样使用的:

public class MainActivity extends Activity {    private IAidlInterface aidlService;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final Intent intent = new Intent();        intent.setAction("com.lbb.aidltest.AidlService");        final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));        bindService(eintent,serviceConnection, Service.BIND_AUTO_CREATE);    }    private ServiceConnection serviceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            aidlService = IAidlInterface.Stub.asInterface(iBinder);            try {                Book book = aidlService.getBookByIndex(0);                Log.d(MainActivity.class.getSimpleName(),"book名字: "+book.getName());            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName componentName) {        }    };    @Override    protected void onDestroy() {        super.onDestroy();        unbindService(serviceConnection);    }    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {        // Retrieve all services that can match the given intent        PackageManager pm = context.getPackageManager();        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);        // Make sure only one match was found        if (resolveInfo == null || resolveInfo.size() != 1) {            return null;        }        // Get component info and create ComponentName        ResolveInfo serviceInfo = resolveInfo.get(0);        String packageName = serviceInfo.serviceInfo.packageName;        String className = serviceInfo.serviceInfo.name;        ComponentName component = new ComponentName(packageName, className);        // Create a new intent. Use the old one for extras and such reuse        Intent explicitIntent = new Intent(implicitIntent);        // Set the component to be explicit        explicitIntent.setComponent(component);        return explicitIntent;    }}

三、小结
1.提供端接口aidl文件创建需要手动import 自定义类,自定义类的aidl需要全手工填写包名并parcelable Book;
2.使用端要拷贝提供端的bean和aidl文件,并且在android 5.0以上系统需要用以上的方式来使得隐式bindService变为显式bind。
3.aidl调用第一个应用服务,不需要启动第一个应用哦

demo下载链接:
http://download.csdn.net/detail/lishaobo211985/9659733

0 0
原创粉丝点击