博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
aidl跨进程通讯
阅读量:5925 次
发布时间:2019-06-19

本文共 7802 字,大约阅读时间需要 26 分钟。

Activity如果想要调用Service中的方法就需要绑定服务,然后才能获取服务的代理对象。进一步调用服务中的方法。类似这样的代码:

首先去创建一个服务:

public class MyService extends Service {    @Nullable    @Override    public IBinder onBind(Intent intent) {        return new MyBinder();    }    class MyBinder extends Binder implements IService {        @Override        public void showToast() {            Show();        }    }    private void Show() {        Toast.makeText(this, "我是服务中的方法", Toast.LENGTH_SHORT).show();    }}复制代码

这里Iservice是为了解耦去定义的接口:

interface IService {    void showToast();}复制代码

我们在Activity中需要去获取binder对象,然后调用服务中的方法:

package remote.zz.remoteservice;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.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import java.util.List;/** * Created by Administrator on 2018/6/27. */public class MainActivity extends AppCompatActivity {    private MyServiceConnection conn;    private IService ser;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //绑定服务        Intent service = new Intent(this, MyService.class);        conn = new MyServiceConnection();        bindService(service, conn, Context.BIND_AUTO_CREATE);        //点击对象        findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //调用服务中的方法                ser.showToast();            }        });    }    //内部类    class MyServiceConnection implements ServiceConnection {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            //获取服务中代理对象            ser = (IService) service;        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    }    @Override    protected void onDestroy() {        //取消绑定,防止报错        unbindService(conn);        super.onDestroy();    }}复制代码

上边的代码是同一个应用中Activity调用Service的基本代码。

假如有这样一个需求,A应用绑定B应用的服务,并互相之间传递数据,这样的需求呢?这个时候你首先会想到用intent的bundle共享文件或者sp对象(并发会有问题,不建议使用),Messenger(它是封装aidl的,不好用)或者广播,当然这些手段是可以的。但是除了这些之外,我们还可以使用aidl实现跨应用之间的数据传递和调用。为了方便叙述,A应用称为本地应用,B应用成为远程服务应用。跨应用之间通讯其实内部也是使用Binder去做代理对象。只不过这个binder是系统帮我们生成的代码,但是我们需要按照步骤去创建需要的文件:

步骤:

1.先在远程服务应用B工程的main目录下建立一个名为aidl的文件夹,再右键该文件夹,在该文件夹下面新建一个名字与AndroidManifest.xml中的package相同的包,再右键该包,新建你所需的AIDL文件;

创建一个aidl文件,其实就是一个接口:

 IRemoteService.aidl

package remote.zz.remoteservice;//注意这里需要自己导入包import remote.zz.remoteservice.Book;interface IRemoteService {    List
getData(); //注意这里的in必须写上,表示传递的方向 void setData(in Book book);}复制代码

还需要创建一个Book数据类型,并且实现序列化:

package remote.zz.remoteservice;import android.os.Parcel;import android.os.Parcelable;//这个写到java文件夹下即可public class Book implements Parcelable {    public int bookId;    public String bookName;    public Book(int bookId, String bookName) {        this.bookId = bookId;        this.bookName = bookName;    }    public int describeContents() {        return 0;    }    public void writeToParcel(Parcel out, int flags) {        out.writeInt(bookId);        out.writeString(bookName);    }    public static final Parcelable.Creator
CREATOR = new Parcelable. Creator
() { public Book createFromParcel(Parcel in) { return new Book(in); } public Book[] newArray(int size) { return new Book[size]; } }; private Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public String toString() { return "Book{" + "bookId=" + bookId + ", bookName='" + bookName + '\'' + '}'; }}复制代码

同时需要创建一个Book.aidl文件

package remote.zz.remoteservice;//这里的包名就是book的包名parcelable Book;//被序列化的数据类复制代码

2.当你进入你的AIDL文件并编写好了之后,点击AS上方菜单栏中的Build->Make Project,之后便可以在当前工程的app/build/generated/source/aidl/debug中找到系统为我们生成的.java文件了。这个对用生成的java文件就是系统为你创建binder类。

对应的服务我们应该这样写:

package remote.zz.remoteservice;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2018/6/27. */public class RemoveService extends Service {    private ArrayList arr;    @Override    public void onCreate() {        super.onCreate();        arr = new ArrayList
(); arr.add(new Book(1001, "我与地坛")); arr.add(new Book(1002, "钢铁是怎样练成的")); } @Nullable @Override public IBinder onBind(Intent intent) { return new MyBinder(); } //系统为我们生成的binder,名字叫Stub, 可点进去查看源码 class MyBinder extends IRemoteService.Stub { @Override public List
getData() throws RemoteException { return arr; } @Override public void setData(Book book) throws RemoteException { arr.add(book); } }}复制代码

在清单文件别忘了配置过滤器,让其他应用可以开启服务

复制代码

那么本地应用A怎么调用呢?

同样先复制远程应用aidl文件夹到本地应用的mian下,然后在mian下创建同远程应用Book类一样的文件夹,把Book类复制到这个文件夹下边,然后去Build->Make Project,同样也会生成一个binder类,这个时候我们就可以调用远程的应用获取服务中的数据:

package local.zz.localapp;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import java.util.List;import remote.zz.remoteservice.Book;import remote.zz.remoteservice.IRemoteService;public class MainActivity extends AppCompatActivity {    private MyConnection conn;    private IRemoteService remote;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //隐私启动服务,5.0之后需要设置包名,否则报错        Intent service = new Intent();        service.setAction("zz.remove.service");        service.setPackage("remote.zz.remoteservice");        conn = new MyConnection();        bindService(service, conn, BIND_AUTO_CREATE);        findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    //获取远程服务数据                    List
data = remote.getData(); for (Book book : data) { } } catch (RemoteException e) { e.printStackTrace(); } } }); findViewById(R.id.tv2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { //调用远程方法传递数据 remote.setData(new Book(1003, "让子弹飞")); } catch (RemoteException e) { e.printStackTrace(); } } }); } class MyConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { //获取代理对象 remote = IRemoteService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } } @Override protected void onDestroy() { unbindService(conn); super.onDestroy(); }}复制代码

到此,aidl的使用完毕!

aidl可以传递aidl声明的接口,所以我们可以做一个观察者模式,动态去监听图书的变化,然后通知注册的观察者。

写这个demo时候遇到一个问题:如果本app的服务没有启动,另外app去绑定获取不到代理对象,还不知道原因是什么!

转载地址:http://plavx.baihongyu.com/

你可能感兴趣的文章
SCRT-SSH传输文件
查看>>
Python非常cool的svg格式chart生成库pygal
查看>>
Telnet部署与启动 windows&&linux
查看>>
行列式的乘法定理
查看>>
有1000瓶水,3个瓶子可以再换1瓶,一共可以喝多少瓶?
查看>>
Search in Rotated Sorted Array ||
查看>>
NUC_HomeWork1 -- POJ2067(最短路)
查看>>
卸载mysql
查看>>
二叉树的遍历
查看>>
The Distinguish of the share or static lib in MFC
查看>>
linux下内存释放问题
查看>>
让Java和JavaScript进行交互
查看>>
android 上传文件
查看>>
linux逻辑卷管理
查看>>
LINQ之路12:LINQ Operators之数据转换(Projecting)
查看>>
SQL Server:数据库角色
查看>>
分享8个超棒的基于HTML5和jQuery的开发教程
查看>>
JFreeChart开发_用JFreeChart增强JSP报表的用户体验
查看>>
SpringMVC+Swagger详细整合
查看>>
计算机视觉领域最全汇总(第2部分)
查看>>