Android之AIDL
来源:互联网 发布:淘宝玩具商城 编辑:程序博客网 时间:2024/06/06 01:51
本文只是记录一些零碎的东西
最近在做一些下载的东西,下载的过程放在service里,其实开一个子线程也是可以的,不管怎么样,都是需要通信的
今天过来扒一扒AIDL,官方API:https://developer.android.com/guide/components/aidl.html
环境:android studio 2.1.2
这个说白了其实就是java接口通信,只是换了个样子,看看怎么实现,假设我现在有个下载的任务,需要显示下载进度,然后模拟一个新闻的app后台,查询所有新闻,新增一个新闻,模拟测试嘛,不要较真
项目地址:https://github.com/CL-window/aidl_example
先新建一个新闻类,实现Parcelable,需要实现的方法 alt+enter 快捷键搞定,完整的类,需要注意一下 in out 区别,看注释
package slack.cl.com.aidl.bean;import android.os.Parcel;import android.os.Parcelable;/** * <p>Description: 新闻类 需要序列化 Parcelable </p> * 对参数 in out 的理解:aidl里会需要用到d * in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端, * 而 inout 则表示数据可在服务端与客户端之间双向流通 * in out 都是相对服务端来说的 * Created by slack on 2016/9/27 11:34 . */public class News implements Parcelable{ public String title;// 标题 public String author;// 作者 public String context;// 内容 public String time;// 时间 public News() {} public News(String title, String author, String context, String time) { this.title = title; this.author = author; this.context = context; this.time = time; } protected News(Parcel in) { title = in.readString(); author = in.readString(); context = in.readString(); time = in.readString(); } public static final Creator<News> CREATOR = new Creator<News>() { @Override public News createFromParcel(Parcel in) { return new News(in); } @Override public News[] newArray(int size) { return new News[size]; } }; @Override public int describeContents() { return 0; } // 默认 in @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(title); parcel.writeString(author); parcel.writeString(context); parcel.writeString(time); } /** * 参数是一个Parcel,用它来存储与传输数据 out * @param dest */ public void readFromParcel(Parcel dest) { //注意,此处的读值顺序应当是和writeToParcel()方法中一致的 title = dest.readString(); author = dest.readString(); context = dest.readString(); time = dest.readString(); } @Override public String toString() { return "News{" + "title='" + title + '\'' + ", author='" + author + '\'' + ", context='" + context + '\'' + ", time='" + time + '\'' + '}'; }}
接下来是aidl文件的新建,IDE有提供新建
因为需要传一个序列化的对象,本例需要两个aidl文件
// News.aidl aidl 1package slack.cl.com.aidl.bean;//这个文件的作用是引入了一个序列化对象 News 供其他的AIDL文件使用// 否则易报 couldn't find import for class ... 意思就是找不到这个类。//注意:News.aidl与News.java的 package 应当是一样的//注意parcelable是小写parcelable News;
第二个文件,类似接口文件啦,里面写方法,本例主要为
// IDownLoadAidlInterface.aidl aidl 2package slack.cl.com.aidl;//导入所需要使用的非默认支持数据类型的包import slack.cl.com.aidl.bean.News;interface IDownLoadAidlInterface {//所有的返回值前都不需要加任何东西,不管是什么数据类型// activity --> service void downLoadUpdate();// 模拟下载 News addNews(in News news);// in 相对服务端来说是数据流入,也可是使用inout// service --> activity int onDownLoadProgress();// 模拟下载进度 List<News> getNews();// 所有的新闻}
reBuild一下项目,如果没有报错就会生成aidl的java文件
看一下这个生成的文件,
public static abstract class Stub extends android.os.Binder implements slack.cl.com.aidl.IDownLoadAidlInterface原来Stub类就是继承于Binder类,只是所返回的IBinder对象比较特别,是一个实现了AIDL接口的Binder
整个文件基于动态反射
/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:\\slack\\demo\\MyApplication\\aidl\\src\\main\\aidl\\slack\\cl\\com\\aidl\\IDownLoadAidlInterface.aidl */package slack.cl.com.aidl;public interface IDownLoadAidlInterface extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements slack.cl.com.aidl.IDownLoadAidlInterface { private static final java.lang.String DESCRIPTOR = "slack.cl.com.aidl.IDownLoadAidlInterface"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an slack.cl.com.aidl.IDownLoadAidlInterface interface, * generating a proxy if needed. */ public static slack.cl.com.aidl.IDownLoadAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof slack.cl.com.aidl.IDownLoadAidlInterface))) { return ((slack.cl.com.aidl.IDownLoadAidlInterface) iin); } return new slack.cl.com.aidl.IDownLoadAidlInterface.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_downLoadUpdate: { data.enforceInterface(DESCRIPTOR); this.downLoadUpdate(); reply.writeNoException(); return true; } case TRANSACTION_addNews: { data.enforceInterface(DESCRIPTOR); slack.cl.com.aidl.bean.News _arg0; if ((0 != data.readInt())) { _arg0 = slack.cl.com.aidl.bean.News.CREATOR.createFromParcel(data); } else { _arg0 = null; } slack.cl.com.aidl.bean.News _result = this.addNews(_arg0); reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_onDownLoadProgress: { data.enforceInterface(DESCRIPTOR); int _result = this.onDownLoadProgress(); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_getNews: { data.enforceInterface(DESCRIPTOR); java.util.List<slack.cl.com.aidl.bean.News> _result = this.getNews(); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements slack.cl.com.aidl.IDownLoadAidlInterface { 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; }//所有的返回值前都不需要加任何东西,不管是什么数据类型// activity --> service @Override public void downLoadUpdate() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_downLoadUpdate, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public slack.cl.com.aidl.bean.News addNews(slack.cl.com.aidl.bean.News news) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); slack.cl.com.aidl.bean.News _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((news != null)) { _data.writeInt(1); news.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addNews, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = slack.cl.com.aidl.bean.News.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int onDownLoadProgress() 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); mRemote.transact(Stub.TRANSACTION_onDownLoadProgress, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.util.List<slack.cl.com.aidl.bean.News> getNews() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<slack.cl.com.aidl.bean.News> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getNews, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(slack.cl.com.aidl.bean.News.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_downLoadUpdate = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addNews = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_onDownLoadProgress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_getNews = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); }//所有的返回值前都不需要加任何东西,不管是什么数据类型// activity --> service public void downLoadUpdate() throws android.os.RemoteException; public slack.cl.com.aidl.bean.News addNews(slack.cl.com.aidl.bean.News news) throws android.os.RemoteException; public int onDownLoadProgress() throws android.os.RemoteException; public java.util.List<slack.cl.com.aidl.bean.News> getNews() throws android.os.RemoteException;}接着就到service类了,模拟了一下
service有两种启动,一种直接start,一种bind,需要了解bind的可以好好看看音乐播放器,那个主要是使用bind
service里 需要有实现aidl接口的类
package slack.cl.com.aidl.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import java.util.ArrayList;import java.util.List;import slack.cl.com.aidl.IDownLoadAidlInterface;import slack.cl.com.aidl.bean.News;public class DownLoadService extends Service { public final String TAG = "slack"; // this.getClass().getSimpleName(); private List<News> newsList = new ArrayList<>(); // bindService 时调用,返回任何你想返回给activity的IBinder类型数据 @Override public IBinder onBind(Intent intent) { Log.i(TAG,"onBind..."); return stub; // TODO: Return the communication channel to the service.// throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG,"onCreate..."); initData(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG,"onStartCommand..."); // 此处可以接收 data return START_NOT_STICKY; // 下面这个会 在service被kill 后自动重启// return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.i(TAG,"onDestroy..."); super.onDestroy(); } // test private void initData(){ for (int i = 0;i < 5; i++){ newsList.add(new News("title"+i,"author"+i,"context"+i,"time"+i)); } } int progress = 0; // 实现aidl Stub接口 build-->generated-->sources-->aidl-->debug IDownLoadAidlInterface.Stub stub = new IDownLoadAidlInterface.Stub() { @Override public void downLoadUpdate() throws RemoteException { Log.i(TAG,"downLoadUpdate..."); progress = 0; } @Override public News addNews(News news) throws RemoteException { Log.i(TAG,"addNews..."); newsList.add(0,news); return news; } @Override public int onDownLoadProgress() throws RemoteException {// Log.i(TAG,"onDownLoadProgress..."); return progress += 5; } @Override public List<News> getNews() throws RemoteException { Log.i(TAG,"getNews..."); return newsList; } };}
测试的activity
package slack.cl.com.aidl;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import slack.cl.com.aidl.bean.News;import slack.cl.com.aidl.service.DownLoadService;public class MainActivity extends AppCompatActivity { private final String TAG = "slack"; // getClass().getSimpleName(); private Intent serviceIntent; private IDownLoadAidlInterface mAIDLmanager; private boolean mIsBind; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStop() { super.onStop(); if(mIsBind){ unbindService(mServiceConnection); mIsBind = false; } } ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "service connected..."); // 获得service里onBind 返回对象 mAIDLmanager = IDownLoadAidlInterface.Stub.asInterface(iBinder); mIsBind = true; if(mAIDLmanager == null){ return; } getNews(null); } @Override public void onServiceDisconnected(ComponentName componentName) { Log.i(TAG, "service disConnected..."); mIsBind = false; } }; // 显式启动service public void startServices(View view) { if(serviceIntent == null){ serviceIntent = new Intent(this,DownLoadService.class); } startService(serviceIntent); } // 通讯,肯定是建立在bind基础上,就跟打电话一样,先接通 public void bindServices(View view) { if(!mIsBind) { if(serviceIntent == null){ serviceIntent = new Intent(this,DownLoadService.class); } bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); } } public void addNews(View view) { if(mAIDLmanager == null){ return; } try { mAIDLmanager.addNews(new News("11","11","11","11")); } catch (RemoteException e) { e.printStackTrace(); } } public void downLoad(View view) { if(mAIDLmanager == null){ return; } try { mAIDLmanager.downLoadUpdate(); // 获取下载进度 new Thread(new Runnable() { @Override public void run() { int progress; try { while ((progress = mAIDLmanager.onDownLoadProgress()) < 100){ Log.i(TAG,"progress:" + progress ); } } catch (RemoteException e) { e.printStackTrace(); } } }).start(); } catch (RemoteException e) { e.printStackTrace(); } } public void getNews(View view) { if(mAIDLmanager == null){ return; } try { Log.i(TAG ,"news:"+ mAIDLmanager.getNews().toString()); } catch (RemoteException e) { e.printStackTrace(); } }}
结果基本完成预期,本文只是简单模拟一下。
- - - - - - - - - - - - -分割线 - - - - - - - - - - - - - - -- - - - -
细细分析一下,基于动态代理生成的aidl 的 .java 文件
先看看在哪里使用的,在activity的bindService 的参数 ServiceConnection的onServiceConnected里面
mAIDLmanager = IDownLoadAidlInterface.Stub.asInterface(iBinder);
而asInterface 的返回值是 return new slack.cl.com.aidl.IDownLoadAidlInterface.Stub.Proxy(obj);
Proxy类,没错,返回的是这个代理类,代理类也实现里aidl接口
分析addNews
@Override public slack.cl.com.aidl.bean.News addNews(slack.cl.com.aidl.bean.News news) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); slack.cl.com.aidl.bean.News _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((news != null)) { _data.writeInt(1); news.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addNews, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = slack.cl.com.aidl.bean.News.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; }
看看这句 mRemote.transact(Stub.TRANSACTION_addNews, _data, _reply, 0); Android Native层Binder.transact()函数调用 Binder.onTransact() 函数,native层代码,这里不分析,看看onTransact
case TRANSACTION_addNews: { data.enforceInterface(DESCRIPTOR); slack.cl.com.aidl.bean.News _arg0; if ((0 != data.readInt())) { _arg0 = slack.cl.com.aidl.bean.News.CREATOR.createFromParcel(data); } else { _arg0 = null; } slack.cl.com.aidl.bean.News _result = this.addNews(_arg0); reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; }1._arg0 = slack.cl.com.aidl.bean.News.CREATOR.createFromParcel(data); 调用我们的Bean对象news里实现序列化接口生成的CREATOR,新建了一个对象
2.slack.cl.com.aidl.bean.News _result = this.addNews(_arg0);// 调用addNews方法
3._result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);// 写序列化
如此看来,aidl也没有想象中那么高大上嘛
- Android Service 之 AIDL
- Android之AIDL
- android 之 AIDL
- Android 之工具aidl
- Android之AIDL
- Android之AIDL使用
- Android之AIDL
- Android服务之AIDL
- Android IPC之AIDL
- Android IPC 之AIDL
- Android之AIDL
- Android之AIDL服务
- Android IPC之AIDL
- Android之AIDL
- Android之AIDL
- Android 之工具aidl
- Android IPC 之 AIDL
- Android之AIDL
- 输入法把底部导航栏顶上去
- C#把内存里的utf8字符串转成C#内部使用的Unicode
- 【bzoj1034】[ZJOI2008]泡泡堂BNB
- SpringMVC文件上传
- 常用shell命令
- Android之AIDL
- mongoose $where、find查询
- 【Python开发】Python:itertools模块
- RNN,LSTM 反向传播算法的思考 & RNN,LSTM可以模块化的分析
- android编译命令
- File文件读写(转)
- ODI数据抽取教程_02创建简单项目
- 转 -- 编写可靠shell脚本的8个建议
- 刷APP任务平台可靠吗?