Binder or AIDL的最简单实践
1.前言:
在Android开发中多进程的合理使用+进程间通信的IPC是一个比较难的点。特别是Android特有的Binder机制,非常复杂,对于应用层开发的初级开发工程师强求深入理解Binder机制是不现实的。 
其实Android 的开发人员已经为我们考虑到,提供了方便我们使用Binder的方法。 
这就是AIDL: Android Interface definition language Android接口定义语言 
我们按照要求简单书写一个AIDL文件,当前的IDE,比如Android Sudio 会根据这个自动生成一个用于Binder通信的Java类 
通过这个类,我们就不需要关心如何通过Java代码实现Binder通信,我们只要会使用编写的AIDL文件自动生成的类即可 
很难理解?
原理是这样的:如果我们要通过Java写Binder的IPC通信代码,对于菜鸟的我们很难写出来,又因为其实Java代码进行Binder通信过程都是类似的,所以谷歌就创造了AIDL文件,我们写好AIDL文件,就帮我们生成对应的Java代码,省去我们理解Binder的抽象过程(电脑帮我们写代码,哈哈)
2.从一个最简单的AIDL实例出发:
在应用层开发中,使用到AIDL的常见场景通常如下: 
 
我们有一个Service,举例:下载文件的DownloadService,为了:
- 不让这个DownloadService占用App的UI进程内存资源
- DownService奔溃不影响App的UI进程 
 我们需要在AndroidManifest里面注册DownloadService的时候通过 android:process=":remote"指定这个Service运行在一个
 独立的私有进程(进程名为应用包名:remote)中(请百度 android:process=""的用法)
<service
         android:name=".DownloadService"
         android:process=":remote" />- 因为DownloadService运行在一个独立进程,App默认的UI进程需要和它通信就是IPC,具体来说就是使用Binder
3.下面一步步演示具体的实践步骤:
我们希望有一个MainActivity代表当前的App的进程,DownloadService运行在另外的一个进程 
然后: 
MainActivity可以通过bindService 绑定DownloadService 
然后Binder实现IPC(进程间通信)调用DownloadService的两个功能:
public List<DownloadTask> getDownloadTasks();//获取当前所有的下载任务
public void addDownloadTask(DownloadTask task)//新增一个下载任务3.1新建两个组件:MainActivity和DownloadService
MainActivity.java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}DownloadService.java
public class DownloadService extends Service {
    private static final String TAG = "DownloadService";
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;//注意:这里我们后面需要返回一个IBinder
    }
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
}AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lijian.binderdemo">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name=".DownloadService"
            android:process=":remote" />
    </application>
</manifest>3.2创建代表下载任务的JavaBean DownloadTask
/**
* 下载任务的JavaBean
* 为了Binder传输,必须实现Parcelable序列化
* Created by lijian on 2017/3/23.
*/
public class DownloadTask implements Parcelable {
    public int taskId;
    public String fileName;
    public String downloadUrl;
    public DownloadTask(int taksId, String fileName, String downloadUrl) {
        this.taskId = taksId;
        this.fileName = fileName;
        this.downloadUrl = downloadUrl;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.taskId);
        dest.writeString(this.fileName);
        dest.writeString(this.downloadUrl);
    }
    protected DownloadTask(Parcel in) {
        this.taskId = in.readInt();
        this.fileName = in.readString();
        this.downloadUrl = in.readString();
    }
    public static final Parcelable.Creator<DownloadTask> CREATOR = new Parcelable.Creator<DownloadTask>() {
        @Override
        public DownloadTask createFromParcel(Parcel source) {
            return new DownloadTask(source);
        }
        @Override
        public DownloadTask[] newArray(int size) {
            return new DownloadTask[size];
        }
    };
    @Override
    public String toString() {
        return "DownloadTask{" +
                "taskId=" + taskId +
                ", fileName='" + fileName + '\'' +
                ", downloadUrl='" + downloadUrl + '\'' +
                "}\n";
    }
}
观察DownloadTask代码,可以看到DownloadTask实现了序列化接口, 
因为DownloadTask是需要IPC,在两个进程之间传输的,经过 
对象-》序列化-》反序列化-》重新生成一个对象的过程 
注意:由于这个DownloadTask需要在AIDL中使用,所以我们需要在AIDL声明它: 

也就是DownloadTask.aidl
// DownloadTask.aidl
package com.lijian.binderdemo;//AIDL需要声明包名
// Declare any non-default types here with import statements
parcelable DownloadTask;
3.3创建IDownload.aidl
aidl名称是Android interface defined language,顾名思义,aidl是用于定义接口的,然后,编译器自动帮助我们生成用于Binder IPC的代码
// IDownload.aidl
package com.lijian.binderdemo;
// Declare any non-default types here with import statements
import com.lijian.binderdemo.DownloadTask;
interface IDownload {
    List<DownloadTask> getTasks();
    void addTask(in DownloadTask task);//使用in 表明这是一个输入的变量
}有代码可以看到我们定义了一个接口 IDownload  
它声明了两个方法
- List getTasks(); 
- void addTask(in DownloadTask task); 
 build一下,奇迹发生了:
   
 这里生成了一个IDownload的Java接口,它是根据我们编写的IDownload.aidl自动生成的,它的作用是方便Binder进行IPC通信
/*
 * This file is auto-generated.  DO NOT MODIFY.
* Original file: G:\\Android_demo\\BinderDemo\\app\\src\\main\\aidl\\com\\lijian\\binderdemo\\IDownload.aidl
*/
package com.lijian.binderdemo;
public interface IDownload extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.lijian.binderdemo.IDownload
{
private static final java.lang.String DESCRIPTOR = "com.lijian.binderdemo.IDownload";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.lijian.binderdemo.IDownload interface,
* generating a proxy if needed.
*/
public static com.lijian.binderdemo.IDownload asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lijian.binderdemo.IDownload))) {
return ((com.lijian.binderdemo.IDownload)iin);
}
return new com.lijian.binderdemo.IDownload.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_getTasks:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.lijian.binderdemo.DownloadTask> _result = this.getTasks();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addTask:
{
data.enforceInterface(DESCRIPTOR);
com.lijian.binderdemo.DownloadTask _arg0;
if ((0!=data.readInt())) {
_arg0 = com.lijian.binderdemo.DownloadTask.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addTask(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.lijian.binderdemo.IDownload
{
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 java.util.List<com.lijian.binderdemo.DownloadTask> getTasks() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.lijian.binderdemo.DownloadTask> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getTasks, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.lijian.binderdemo.DownloadTask.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addTask(com.lijian.binderdemo.DownloadTask task) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((task!=null)) {
_data.writeInt(1);
task.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addTask, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getTasks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addTask = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.lijian.binderdemo.DownloadTask> getTasks() throws android.os.RemoteException;
public void addTask(com.lijian.binderdemo.DownloadTask task) throws android.os.RemoteException;
}
代码看似很困惑,其实不然,层次还是很分明的,我们一层一层剥离代码分析
3.3.1 IDownload Interface
public interface IDownload extends android.os.IInterface{
    //省略代码
    public java.util.List<com.lijian.binderdemo.DownloadTask> getTasks() throws android.os.RemoteException;
    public void addTask(com.lijian.binderdemo.DownloadTask task) throws android.os.RemoteException;
}根据我们定义的IDownload.aidl文件,里面声明了两个方法,所以生成了一个Java代码 
IDownload Interface ,extends android.os.IInterface,
android.os.IInterface Binder接口的基础class,在定义一个新的Binder Interface,必须继承这个接口 IInterface
/**
 * Base class for Binder interfaces.  When defining a new interface,
* you must derive it from IInterface.
*/
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}
IDownload java声明了我们定义在对应的AIDL的方法,唯一不同的是声明了这些方法可能会抛出 Remote调用的的Exception异常
public java.util.List<com.lijian.binderdemo.DownloadTask> getTasks() throws android.os.RemoteException;
public void addTask(com.lijian.binderdemo.DownloadTask task) throws android.os.RemoteException;3.3.2 public static abstract class Stub
在上面我们曾经说过Client调用的其实是影子,真身在Server进程。 
IDownload 有静态内部类辅助我们的在Client操作影子,在Server创建真身:
它就是public static abstract class Stub
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.lijian.binderdemo.IDownload
{
private static final java.lang.String DESCRIPTOR = "com.lijian.binderdemo.IDownload";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.lijian.binderdemo.IDownload interface,
* generating a proxy if needed.
*/
public static com.lijian.binderdemo.IDownload asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lijian.binderdemo.IDownload))) {
return ((com.lijian.binderdemo.IDownload)iin);
}
return new com.lijian.binderdemo.IDownload.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_getTasks:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.lijian.binderdemo.DownloadTask> _result = this.getTasks();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addTask:
{
data.enforceInterface(DESCRIPTOR);
com.lijian.binderdemo.DownloadTask _arg0;
if ((0!=data.readInt())) {
_arg0 = com.lijian.binderdemo.DownloadTask.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addTask(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.lijian.binderdemo.IDownload
{
    //省略代码
}
static final int TRANSACTION_getTasks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addTask = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}为了更清晰

可以看到里面就
三个常量
- private static final java.lang.String DESCRIPTOR = "com.lijian.binderdemo.IDownload";
- static final int TRANSACTION_getTasks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
- static final int TRANSACTION_addTask = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
Stub的构造方法
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}一个静态方法:public static com.lijian.binderdemo.IDownload asInterface(android.os.IBinder obj)
这个方法可以把一个IBinder转换为 com.lijian.binderdemo.IDownload interface
/**
* Cast an IBinder object into an com.lijian.binderdemo.IDownload interface,
* generating a proxy if needed.
*/
public static com.lijian.binderdemo.IDownload asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lijian.binderdemo.IDownload))) {
return ((com.lijian.binderdemo.IDownload)iin);//说明这是一个本地调用而不是IPC调用,直接返回真身即可,真身直接调用,不需要binder,效率更高
}
return new com.lijian.binderdemo.IDownload.Stub.Proxy(obj);//说明这是是IPC调用,返回一个Proxy,代理类,通过他进行Binder 调用
}
两个成员方法:
- public android.os.IBinder asBinder()
@Override
 public android.os.IBinder asBinder(){
    return this;
}- public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 
 这个方法运行在Server端的Binder线程池,观察它的参数:
 int code:用于标识不同的方法
 android.os.Parcel data:用于传递Client的参数
 android.os.Parcel reply,用于写入Server的返回值
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
switch (code)//通过code Client通过Binder调用的是哪一个方法
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getTasks:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.lijian.binderdemo.DownloadTask> _result = this.getTasks();//这个是接口的具体实现
reply.writeNoException();//写入Binder remote调用没有异常
reply.writeTypedList(_result);//写入返回值
return true;
}
case TRANSACTION_addTask:
{
data.enforceInterface(DESCRIPTOR);
com.lijian.binderdemo.DownloadTask _arg0;
if ((0!=data.readInt())) {
_arg0 = com.lijian.binderdemo.DownloadTask.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addTask(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}总结:
分析了IDownload.java 后,我们可以看到通过IDownload.aidl生成的代码,其实最终我们需要的也只是java代码,也就是说,如果我们熟悉了自动生成代码的套路,其实,不需要aidl,手写Java代码实现AIDL调用也是可以的。
4. 生成的IDownload.java 接口的使用:
4.1 Server端:
public class DownloadService extends Service {
    private static final String TAG = "DownloadService";
    private List<DownloadTask> mTasks = new CopyOnWriteArrayList<>();
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
//注意这个方法,这就是定义的接口具体实现,理所当然的具体功能应该有Server实现
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new IDownload.Stub() {
            @Override
            public List<DownloadTask> getTasks() throws RemoteException {
                return mTasks;
            }
            @Override
            public void addTask(DownloadTask task) throws RemoteException {
                if (mTasks != null) {
                    mTasks.add(task);
                }
            }
        };
    }
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
}
4.2 Client端:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";
    private IDownload download;//注意这里
    private Button addTaskBtn;
    private TextView addTaskInfo;
    private Button getTasksBtn;
    private TextView getTasksInfo;
    private int index = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindDownloadService();
        setContentView(R.layout.activity_main);
        setupView();
    }
    private void setupView() {
        addTaskBtn = (Button) findViewById(R.id.btn_add_task);
        getTasksBtn = (Button) findViewById(R.id.btn_get_tasks);
        addTaskInfo = (TextView) findViewById(R.id.tv_add_task_info);
        getTasksInfo = (TextView) findViewById(R.id.tv_tasks_info);
        addTaskBtn.setOnClickListener(this);
        getTasksBtn.setOnClickListener(this);
    }
    private void bindDownloadService() {
        Intent intent = new Intent(this, DownloadService.class);
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                download = IDownload.Stub.asInterface(service);//我们把bindService返回的 IBinder Service转换为一个接口实例
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        }, Context.BIND_AUTO_CREATE);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_get_tasks:
                getTasks();
                break;
            case R.id.btn_add_task:
                addTask();
                break;
            default:
                break;
        }
    }
    private void addTask() {
        if (download != null) {
            DownloadTask task = new DownloadTask(index++, "下载文件" + index, "www.baidu.com/" + index + ".txt");
            try {
                download.addTask(task);//这里就可以调用接口实例,看到没有,Binder的IPC操作对于Client端来说就是简化为调用一个对象了
                addTaskInfo.setText(task.toString());
            } catch (RemoteException e) {
                Log.w(TAG, e.toString());//Binder调用可能尝试RemoteException,需要捕获异常
            }
        }
    }
    private void getTasks() {
        if (download != null) {
            try {
                List<DownloadTask> tasks = download.getTasks();/这里就可以调用接口实例
                getTasksInfo.setText(tasks == null ? "no task" : tasks.toString());
            } catch (RemoteException e) {
                Log.w(TAG, e.toString());
            }
        }
    }
}
总结:
public class DownloadService extends Service {
    private static final String TAG = "DownloadService";
    private List<DownloadTask> mTasks = new CopyOnWriteArrayList<>();
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
//注意这个方法,这就是定义的接口具体实现,理所当然的具体功能应该有Server实现
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new IDownload.Stub() {
            @Override
            public List<DownloadTask> getTasks() throws RemoteException {
                return mTasks;
            }
            @Override
            public void addTask(DownloadTask task) throws RemoteException {
                if (mTasks != null) {
                    mTasks.add(task);
                }
            }
        };
    }
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
}public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";
    private IDownload download;//注意这里
    private Button addTaskBtn;
    private TextView addTaskInfo;
    private Button getTasksBtn;
    private TextView getTasksInfo;
    private int index = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindDownloadService();
        setContentView(R.layout.activity_main);
        setupView();
    }
    private void setupView() {
        addTaskBtn = (Button) findViewById(R.id.btn_add_task);
        getTasksBtn = (Button) findViewById(R.id.btn_get_tasks);
        addTaskInfo = (TextView) findViewById(R.id.tv_add_task_info);
        getTasksInfo = (TextView) findViewById(R.id.tv_tasks_info);
        addTaskBtn.setOnClickListener(this);
        getTasksBtn.setOnClickListener(this);
    }
    private void bindDownloadService() {
        Intent intent = new Intent(this, DownloadService.class);
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                download = IDownload.Stub.asInterface(service);//我们把bindService返回的 IBinder Service转换为一个接口实例
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        }, Context.BIND_AUTO_CREATE);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_get_tasks:
                getTasks();
                break;
            case R.id.btn_add_task:
                addTask();
                break;
            default:
                break;
        }
    }
    private void addTask() {
        if (download != null) {
            DownloadTask task = new DownloadTask(index++, "下载文件" + index, "www.baidu.com/" + index + ".txt");
            try {
                download.addTask(task);//这里就可以调用接口实例,看到没有,Binder的IPC操作对于Client端来说就是简化为调用一个对象了
                addTaskInfo.setText(task.toString());
            } catch (RemoteException e) {
                Log.w(TAG, e.toString());//Binder调用可能尝试RemoteException,需要捕获异常
            }
        }
    }
    private void getTasks() {
        if (download != null) {
            try {
                List<DownloadTask> tasks = download.getTasks();/这里就可以调用接口实例
                getTasksInfo.setText(tasks == null ? "no task" : tasks.toString());
            } catch (RemoteException e) {
                Log.w(TAG, e.toString());
            }
        }
    }
}通过文字来阐述解析是比较困难的,具体可以参考Github上的代码: 
https://github.com/bylijian/BinderDemo 
注意,请查看git记录,这个是比较早的提交,和最新的代码不一样,具体参考截图高亮部分
 
 
另外,这个Demo还有更多的的演示代码,都值得看一看。
Binder or AIDL的最简单实践的更多相关文章
- Thrift简单实践
		0.什么是RPC RPC(Remote Procedure Call - 远程过程调用),是通过网络从远程计算机上请求服务,而不需要了解底层网路技术的细节.简单点说,就是像调用本地服务(方法)一样调用 ... 
- Java 异步处理简单实践
		Java 异步处理简单实践 http://www.cnblogs.com/fangfan/p/4047932.html 同步与异步 通常同步意味着一个任务的某个处理过程会对多个线程在用串行化处理,而异 ... 
- Android 设计随便说说之简单实践(合理组合)
		上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ... 
- c#中,委托Func的简单实践
		c# 委托Func的简单实践最近才真正的接触委托,所以针对Func类型的委托,做一个实践练习. 首先说一些我对委托的初级理解:"就是把方法当做参数,传进委托方法里". 我平时用到的 ... 
- kafka原理和实践(二)spring-kafka简单实践
		系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ... 
- SQL知识以及SQL语句简单实践
		综述 大家都知道SQL是结构化查询语言,是关系数据库的标准语言,是一个综合的,功能极强的同时又简洁易学的,它集级数据查询(Data Quest),数据操纵(Data Manipulation),数据定 ... 
- Android : 跟我学Binder --- (2) AIDL分析及手动实现
		目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ... 
- android 进程间通信  messenger 是什么  binder 跟 aidl 区别  intent 进程间 通讯?  android  消息机制 进程间  android  进程间 可以用 handler么  messenger 与 handler 机制   messenger 机制 是不是 就是 handler 机制 或   , 是不是就是 消息机制  android messenge
		韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ... 
- ZooKeeper分布式锁简单实践
		ZooKeeper分布式锁简单实践 在分布式解决方案中,Zookeeper是一个分布式协调工具.当多个JVM客户端,同时在ZooKeeper上创建相同的一个临时节点,因为临时节点路径是保证唯一,只要谁 ... 
随机推荐
- php中的list()用法中要注意的地方
			php中list()函数是用数组对一列值进行赋值, 该函数只用于数字索引的数组,且假定数字索引从0开始.(这句话很重要,是从索引0开始为变量赋值,如果对应的数字索引不存在,则对应位的变量也为空值.) ... 
- ubuntu安装gnome桌面
			1. apt install gnome-shell 2. apt install ubuntu-gnome-desktop 3. apt install unity-tweak-tool 4. ap ... 
- JMessage Android 端开发详解
			目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 IM 应用会需要有哪些功能? 用户注册 / 登 ... 
- css 移动端图片等比显示处理
			第一次写博文,心情有点小小的激动~~~~~ 刚开始做移动端项目的时候遇到了一些优化的问题,比如,打开网页在2g或者3g的情况下加载网页,刚开始渲染的时候,遇到图片文件未请求,图片的高度会为0,当然,如 ... 
- Comparable比较器和Comparator比较器
			1.Comparable比较器 在Arrays类中存在sort()排序方法,此方法可以直接对对象数组进行排序. public static void sort(Object[] a 根据元素的自然顺序 ... 
- Entity Framework添加记录时获取自增ID值
			与Entity Framework相伴的日子痛并快乐着.今天和大家分享一下一个快乐,两个痛苦. 先说快乐的吧.Entity Framework在将数据插入数据库时,如果主键字段是自增标识列,会将该自增 ... 
- BZOJ - 3263 三维偏序
			题意:定义元素为有序组(a,b,c),若存在x组(a_i,b_i,c_i)分别小于等于(a,b,c),则该元素的等级为x,求[0,n-1]等级的个数 cdq分治练手题,对a简单排序并去重,对b进行分治 ... 
- php引擎文件php.ini优化参数
			无论是Apache环境还是nginx环境,php.ini都适合,php-fpm.conf适合nginx+fcgi的配置. 生产环境php.ini(php.ini-production) php.ini ... 
- Linux I2C驱动--用户态驱动简单示例
			1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0 2. I ... 
- Delphi XE   TStringBuilder
			function T_SunnySky_SDK.JoinItems(AParamDic: TDictionary<string, string>): string; var sb : TS ... 
