第一部分
使用的AIDL文件的方法:
AIDL接口文件的处理:
在客户端将AIDL文件拷贝到自己的工程中:
1.main 文件夹下建立aidl文件夹.将AIDL文件复制进去,如果是引入已经写好的aidl文件,那么包就应该是该aidl文件中的包名(切记!)并把提供的aidl文件复制到下面
2.rebuild后 在build/generated/source/aidl/debug下就可以见到自动生成的Java文件
绑定服务:
Intent intent =new Intent();
intent.setAction("com.cuizehui.ADD");// service 文件要声明意图 5.0后要设置包名!
bindService(intent,conn, Context.BIND_AUTO_CREATE);
成功后,获取Binder:
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mservice = MytestAIDL.Stub.asInterface(service);
//这个就是我们获取的Binder!!!!!!!接下来就可以用它操作远程服务了!
Log.d("绑定远程服务","成功");
}
//这个方法只有在 服务被收回等异常时才会调用,如果服务不存在,则不会调用
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("绑定失败","失败");
}
};
如果服务不存在的话可以通过
bindservice 的返回值进行判断 是否存在
创建远程服务并生成AIDL文件的方法:
生成AIDL文件:
(要便称AIDL文件就是接口文件。) 那么android studio 中怎么搞呢?
1.android studio 中就直接new aidl 文件就好啦 !然后把接口方法添加一下像这样:
// MytestAIDL.aidl
package com.example.cuizehui.aidlfarservice;
// Declare any non-default types here with import statements
interface MytestAIDL {
int add(int x,int y);
}
rebuild .即可看到
在build/generated/source/aidl/debug下就可以见到自动生成的Java文件.这个生成的java文件。给我们自动生成了一个内部类:
package com.example.cuizehui.aidlfarservice;
// Declare any non-default types here with import statements
public interface MytestAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.cuizehui.aidlfarservice.MytestAIDL
{
private static final java.lang.String DESCRIPTOR = "com.example.cuizehui.aidlfarservice.MytestAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.cuizehui.aidlfarservice.MytestAIDL interface,
* generating a proxy if needed.
*/
public static com.example.cuizehui.aidlfarservice.MytestAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.cuizehui.aidlfarservice.MytestAIDL))) {
return ((com.example.cuizehui.aidlfarservice.MytestAIDL)iin);
}
return new com.example.cuizehui.aidlfarservice.MytestAIDL.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_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.cuizehui.aidlfarservice.MytestAIDL
{
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 int add(int x, int y) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(x);
_data.writeInt(y);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int add(int x, int y) throws android.os.RemoteException;
}
创建远程服务:
1.修改Onbind方法 返回远程的IBinder对象:
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MiddlePerson();
}
2.还要把binder 的继承也给改了 . 就是本地服务的Binder,正常的话本地服务是要继承binder类并实现方法接口的。
但是AIDL 生成的java文件 已经继承了binder ,并且实现了上面接口文件的接口类型。。棒棒哒。。所以直接修改继承这个内部类,并实现方法就好啦!
内部类的名字就是AIDL文件的名字.stub (请看上面源码)
public class RomateService extends Service {
public RomateService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MiddlePerson();
}
private class MiddlePerson extends MytestAIDL.Stub{
@Override
public int add(int x, int y) throws RemoteException {
return x+y;
}
}
}
3.不要忘记了销毁时处理标记等。
时至今时: 就写好远程服务啦。
第二部分
AIDL 监听器处理:
//业务场景:
/**
* 客户端给服务端一个监听,并写了具体的监听方法。(监听数据更新了没)
* 服务端拿到了这个监听器后,当自己的数据更新了,就执行监听器内的方法。这是就是观察者模式。
*/
服务端AIDL修改:
AIDL 中的接口类型也必须为AIDL类型的。不允许定义普通接口。
// MytestAIDL.aidl
package com.example.cuizehui.aidlfarservice;
import com.example.cuizehui.aidlfarservice.IOnArrivedListenter ;
// Declare any non-default types here with import statements
interface MytestAIDL {
//远程服务的方法
int add(int x,int y);
//绑定监听
void registerListener(IOnArrivedListenter listner);
//解绑监听
void unregisterListener(IOnArrivedListenter listner);
}
注意导包!问题!!
定义的接口:
// IOnArrivedListenter.aidl
package com.example.cuizehui.aidlfarservice;
// Declare any non-default types here with import statements
interface IOnArrivedListenter {
void onNewArrived();
}
服务端对于监听器的逻辑处理:
保证线程同步存放多个监听的容器:
由于可能有很多监听器,所以这里我们提供一个List来存储 客户端的监听器s。
//binder 本来是线程不同步的, 这里我们使用CopyOnWriteArrayList来进行自动的线程同步。这样做的目的是可能有许多个监听都注册了
private CopyOnWriteArrayList<IOnArrivedListenter> mListenerList=new CopyOnWriteArrayList<IOnArrivedListenter>();
注册:
@Override
public void registerListener(IOnArrivedListenter listner) throws RemoteException {
if(!mListenerList.contains(listner)){
if(listner!=null){
mListenerList.add(listner);
}
else {
Log.d("传过来的监听器就是空的","!");
}
}
else {
Log.d("tag","已经存在了");
}
}
执行监听器中的方法:
//当有数据更新后就执行这个方法。
//当绑定成功后 还是需要调用接口中方法,这时通过Listenerlist 中的Listener 调用接口内方法
private void onNewArrived() throws RemoteException {
Log.d("绑定监听器的个数",""+mListenerList.size());
//下面才是调用的接口方法。
for(int i=0 ;i<mListenerList.size();i++){
Log.d("绑定监听器的个数",""+mListenerList.size());
IOnArrivedListenter listenter = mListenerList.get(i);
//调用接口的方法 这个方法是在客户端实现的!
listenter.onNewArrived();
}
}
可是实现同步并解注的容器:
但是注意上面这种方式不能完成解注:
原理:
因为是序列化 和反序列化的过程,所以 不是同一个对象。 引入一个新的类
RemoteCallbackList,但是这个类并不是list 必须按照他的方式遍历(beginBroadcast, finishBroadcast)配对使用
这个类底层是一个MAP 存放类 IBinder 和对应的Callback.
使用方式: 用这类类代替上面这个CopyOnWriteArrayList
private RemoteCallbackList<IOnArrivedListenter> mListenerList=new RemoteCallbackList<IOnArrivedListenter>();
修改,register 和unregistListener 两个方法 很简单。
public void registerListener(IOnArrivedListenter listner) throws RemoteException {
mListenerList.register(listner);
}
@Override
public void unregisterListener(IOnArrivedListenter listner) throws RemoteException {
mListenerList.unregister(listner);
}
}
当要调用listener 中的监听方法时,这样处理
final int N=mListenerList.beginBroadcast();
for(int i=0; i<N;i++){
IOnArrivedListenter l = mListenerList.getBroadcastItem(i);
if(l!=null){
try {
l.onNewArrived();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
mListenerList.finishBroadcast();
客户端注册监听使用:
1实现监听器(注意还是AIDL文件接口内部类 的实现)
private IOnArrivedListenter listener=new IOnArrivedListenter.Stub(){
@Override
public void onNewArrived() throws RemoteException {
Log.d("执行客户端的监听方法","!");
}
};
2.
mservice.registerListener(listener);
3.在这之前的AIDL文件还是要生成java文件的就不讲了。
服务死亡代理:
另细节注意:当服务端死亡时,客户端并不知道,这时如何处理?
原理:Binder这两个方法linkToDeath 和unlinkToDeath方法 设置死亡代理。
给服务端设置死亡代理,本质也就是上文的监听者模式吧。当监听器监听到服务死亡。设置重新连接。
实现方式:
1.在客户端中声明IBinder类DeathRecipient对象,是IBinder类的一个接口:
//实现IBinder类中提供的死亡代理的接口
private IBinder.DeathRecipient mDeathRecipent=new IBinder.DeathRecipient(){
@Override
public void binderDied() {
if(mservice==null)
return;
mservice.asBinder().unlinkToDeath(mDeathRecipent,0);
mservice=null;
//如果
}
};
这里的mService就是我们返回的IBinder. 代码的意思是如果他死亡了 那么我们重新连接。
2.绑定时同时设置死亡代理,
mservice = MytestAIDL.Stub.asInterface(service);
//设置死亡代理!
try {
service.linkToDeath(mDeathRecipent,0);
} catch (RemoteException e) {
e.printStackTrace();
}
传输序列化对象:
三步:
1实现序列化:
package com.example.cuizehui.estoredataservice;
import android.os.Parcel;
import android.os.Parcelable;
import org.litepal.crud.DataSupport;
/**
* Created by cuizehui on 17-9-19.
*/
public class ShopDaTa extends DataSupport implements Parcelable {
//详细图片地址
String picadress;
//商品描述
String productdic;
//商店名
String shopName;
//店铺名
String productName;
//缩略图地址
String picsmalladress;
//商品价格
String price;
//快递价格
String mailprice;
//图片字节数组
byte[] bitmaps ;
byte[] bitmapbig ;
protected ShopDaTa(Parcel in) {
picadress = in.readString();
productdic = in.readString();
shopName = in.readString();
productName = in.readString();
picsmalladress = in.readString();
price = in.readString();
mailprice = in.readString();
bitmaps = in.createByteArray();
bitmapbig = in.createByteArray();
}
public static final Creator<ShopDaTa> CREATOR = new Creator<ShopDaTa>() {
@Override
public ShopDaTa createFromParcel(Parcel in) {
return new ShopDaTa(in);
}
@Override
public ShopDaTa[] newArray(int size) {
return new ShopDaTa[size];
}
};
public byte[] getBitmaps() {
return bitmaps;
}
public void setBitmaps(byte[] bitmaps) {
this.bitmaps = bitmaps;
}
public byte[] getBitmapbig() {
return bitmapbig;
}
public void setBitmapbig(byte[] bitmapbig) {
this.bitmapbig = bitmapbig;
}
public ShopDaTa() {
}
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getPicadress() {
return picadress;
}
public void setPicadress(String picadress) {
this.picadress = picadress;
}
public String getProductdic() {
return productdic;
}
public void setProductdic(String productdic) {
this.productdic = productdic;
}
public String getPicsmalladress() {
return picsmalladress;
}
public void setPicsmalladress(String picsmalladress) {
this.picsmalladress = picsmalladress;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getMailprice() {
return mailprice;
}
public void setMailprice(String mailprice) {
this.mailprice = mailprice;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(picadress);
parcel.writeString(productdic);
parcel.writeString(shopName);
parcel.writeString(productName);
parcel.writeString(picsmalladress);
parcel.writeString(price);
parcel.writeString(mailprice);
parcel.writeByteArray(bitmaps);
parcel.writeByteArray(bitmapbig);
}
}
特别注意:包名路径 和 Java文件相同, 文件名 就是Java文件名.aidl. 出现同名文件无法创建情况,先填别的然后修改
3.在要远程调用对象的AIDL中 导包
// IDataAidlInterface.aidl
package com.example.cuizehui.estoredataservice;
// Declare any non-default types here with import statements
import com.example.cuizehui.estoredataservice.ShopDaTa;
interface IDataAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
List<ShopDaTa> getShopDaTaList();
}
注意最好和数据aidl 文件在一个包下,并且 注意路径问题!
获取字节数据:
public void provideServiceData(){
//调用远程服务
Intent intent =new Intent();
intent.setAction("com.cuizehui.dataservice");
intent.setPackage("com.example.cuizehui.estoredataservice");
mainActivity.bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mservice = IDataAidlInterface.Stub.asInterface(iBinder);
//操作远程服务
List<com.example.cuizehui.estoredataservice.ShopDaTa> shopDaTas;
try {
shopDaTas=mservice.getShopDaTaList();
ArrayList<ShopDaTa> arrayList=new ArrayList<>();
for (int i=0;i<shopDaTas.size();i++){
ShopDaTa shopDaTa=new ShopDaTa();
shopDaTa.setPicadress(shopDaTas.get(i).getPicadress());
shopDaTa.setPrice(shopDaTas.get(i).getPrice());
shopDaTa.setProductName(shopDaTas.get(i).getProductName());
shopDaTa.setShopName(shopDaTas.get(i).getShopName());
shopDaTa.setProductdic(shopDaTas.get(i).getProductdic());
shopDaTa.setMailprice(shopDaTas.get(i).getMailprice());
byte[] bytes;
if(shopDaTas.get(i).getBitmaps()!=null){
bytes=shopDaTas.get(i).getBitmaps();
Log.d("bitmap_log",bytes.length+"!null");
shopDaTa.setBitmaps(bytes);
}
else {
Log.d("bitmap","null");
}
Log.d("context",shopDaTas.get(i).getProductName()+"");
arrayList.add(shopDaTa);
}
homeViewpagerLVAdapter1=new HomeViewpagerLVAdapter(arrayList,mainActivity);
Toast.makeText(mainActivity,shopDaTas.size()+""+":"+arrayList.size(),Toast.LENGTH_SHORT).show();
//refrush
initView();
initEvent();
} catch (RemoteException e) {
e.printStackTrace();
}
Log.d("绑定远程服务","成功");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("绑定失败","失败");
}
}, mainActivity.BIND_AUTO_CREATE);
}
实现的机制: