aidl跨进程通讯

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<Book> 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<Book> CREATOR = new Parcelable.
            Creator<Book>() {
        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<Book>();
        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<Book> getData() throws RemoteException {
            return arr;
        }

        @Override
        public void setData(Book book) throws RemoteException {
            arr.add(book);
        }
    }


}复制代码

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

<!--提供远程服务的服务,5.0之后必须写  android:exported="true"-->
<service
    android:name=".RemoveService"
    android:exported="true">
    <intent-filter>
        <action android:name="zz.remove.service" />
    </intent-filter>
</service>复制代码

那么本地应用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<Book> 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去绑定获取不到代理对象,还不知道原因是什么!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值