Android 中的Binder跨进程通信机制与AIDL

如果对进程、线程概念还很懵懂的同学可以看一下之前发表的一篇博客,里面是基础概念:
IPC进程间通信/跨进程通信
http://blog.csdn.net/github_33304260/article/details/52895331
#为什么需要跨进程通信?
答:两个对象能直接互相访问的前提是两个对象在相同的内存地址空间中,如果两个对象那个在两个不同的进程中,比如ActivityManager和ActivityManagerService,不能直接互调需要跨进程技术,所以需要跨进程通信。那么问题来了,已有那么多跨进程手段,如上一篇讲的管道,Socket等,为什么还要大费周折弄一个Binder?
#为什么在Android中使用Binder进行跨进程通信?
答:之说以这么大费周折,那肯定有Binder的过人之处。
Socket开销大且效率不高;管道和队列拷贝次数过多,而且传统跨进程通信手段安全性不高,接收方无法识别UID、PID,对于移动设备的安全性和效率考虑设计出来Binder。那么Binder这么好究竟是什么东西呢?
#Binder是什么?
答:BInder是由四个模块组成,Binder Driver 、Binder Client、Binder Server、 Server Manager。
Binder Client相当于客户端,Binder Server相当于服务器, ServerManager相当于DNS服务器,Binder Driver 相当于一个路由器。
Binder Driver位于内核空间,主要负责Binder通信的建立,以及其在进程见得传递和Binder引用计数管理/数据包的传输等。Binder Server与 Binder Client之间的跨进程通信则通过Binder Driver转发。对于 Binder Client只需要知道自己要使用Binder的名字以及该binder实体在 Server Manager中的0号引用即可。ServerManager就是一个标准的BinderServer,并且在Android中约定其在Binder通信过程中唯一标识符永远是0。那说了这么多到底怎么进行跨进程呢?
#如何使用Binder进行跨进程通信呢?
答: Binder Driver 和ServerManager是底层的没必要实现,只需实现Binder Client和Binder Server。但是Binder Server代码在C中实现,并且逻辑复杂,所以Android提供了一个简单的方式–AIDL–来生成一个Binder Server。
下面看一下具体demo
github地址:
https://github.com/libin7278/DesignModle
新建一个AIDl
Android 中的Binder跨进程通信机制与AIDL_第1张图片

// IBackAidl.aidl
package com.mvp.libin.aidl_example;

// Declare any non-default types here with import statements

interface IBackAidl {
   /**
        * 开户
        * @param name
        * @param password
        * @return
        */
       String OpenAccount(String name,String password);

       /**
        * 存钱
        * @param money
        * @param account
        * @return
        */
       String saveMoney(int money,String account);

       /**
        * 取钱
        * @param money
        * @param account
        * @param password
        * @return
        */
       String tackMoney(int money,String account,String password);

       /**
        * 销户
        * @param account
        * @param password
        * @return
        */
       String closeAccount(String account,String password);
}

然后在build/generated可以看到生成的IBackAidl.java
这里贴出一部分

/**
        * 开户
        * @param name
        * @param password
        * @return
        */
@Override public java.lang.String OpenAccount(java.lang.String name, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_OpenAccount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
        * 存钱
        * @param money
        * @param account
        * @return
        */
@Override public java.lang.String saveMoney(int money, java.lang.String account) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
mRemote.transact(Stub.TRANSACTION_saveMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
        * 取钱
        * @param money
        * @param account
        * @param password
        * @return
        */
@Override public java.lang.String tackMoney(int money, java.lang.String account, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_tackMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
        * 销户
        * @param account
        * @param password
        * @return
        */
@Override public java.lang.String closeAccount(java.lang.String account, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_closeAccount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_OpenAccount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_saveMoney = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_tackMoney = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_closeAccount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
/**
        * 开户
        * @param name
        * @param password
        * @return
        */
public java.lang.String OpenAccount(java.lang.String name, java.lang.String password) throws android.os.RemoteException;
/**
        * 存钱
        * @param money
        * @param account
        * @return
        */
public java.lang.String saveMoney(int money, java.lang.String account) throws android.os.RemoteException;
/**
        * 取钱
        * @param money
        * @param account
        * @param password
        * @return
        */
public java.lang.String tackMoney(int money, java.lang.String account, java.lang.String password) throws android.os.RemoteException;
/**
        * 销户
        * @param account
        * @param password
        * @return
        */
public java.lang.String closeAccount(java.lang.String account, java.lang.String password) throws android.os.RemoteException;
}

package com.mvp.libin.aidl_example;

import android.os.Binder;

import java.util.UUID;

/**
 * Created by libin on 16/11/16.
 */

public class BanklBinder extends IBackAidl.Stub{
    @Override
    public String OpenAccount(String name, String password) {
        return name+"开户成功"+ UUID.randomUUID().toString();
    }

    @Override
    public String saveMoney(int money, String account) {
        return "账户:"+account+"存入"+money+"人民币";
    }

    @Override
    public String tackMoney(int money, String account, String password) {
        return "账户:"+account+"取出"+money+"人民币";
    }

    @Override
    public String closeAccount(String account, String password) {
        return "账户:"+account+"销户";
    }
}

//===================================>下面是本地服务
/*
 public class BanklBinder extends Binder implements IBank {
    @Override
    public String OpenAccount(String name, String password) {
        return name+"开户成功"+ UUID.randomUUID().toString();
    }

    @Override
    public String saveMoney(int money, String account) {
        return "账户:"+account+"存入"+money+"人民币";
    }

    @Override
    public String tackMoney(int money, String account, String password) {
        return "账户:"+account+"取出"+money+"人民币";
    }

    @Override
    public String closeAccount(String account, String password) {
        return "账户:"+account+"销户";
    }
}
*/

package com.mvp.libin.aidl_example;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

/**
 * Created by libin on 16/11/16.
 */

public class BankService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new BanklBinder();
    }
}

//====================================>
/**
 * 这里是模拟 所以可以把BankService看做 Binder Server
 * 现在接口有了,服务端也有了,接下来就是客户端了
 *
 */
package com.mvp.libin.aidl_example;

import android.content.ComponentName;
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.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private IBackAidl mBanklBinder; //服务端的Server对象

    private TextView tv;

    //用于绑定Server的ServerConnection对象
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBanklBinder =IBackAidl.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.tv);

        Intent intent = new Intent(this,BankService.class);
        intent.setAction("cn.augest.test.aidl.bank");
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);

        init(R.id.b1);
        init(R.id.b2);
        init(R.id.b3);
        init(R.id.b4);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }

    private void init(int id) {
        Button button = (Button) findViewById(id);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                    case R.id.b1:
                        try {
                            tv.setText(mBanklBinder.OpenAccount("libin", "123456"));
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case R.id.b2:
                        try {
                            tv.setText(mBanklBinder.saveMoney(12345, "libin"));
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case R.id.b3:
                        try {
                            tv.setText(mBanklBinder.tackMoney(123,"libin", "123456"));
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case R.id.b4:
                        try {
                            tv.setText(mBanklBinder.closeAccount("libin", "123456"));
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                }
            }
        });
    }
}

Android 中的Binder跨进程通信机制与AIDL_第2张图片

这下就能看到两个进程了!
不过要注意:
1)
android:process="cn.aigestudio.BinderServer"必须加入这个 才能新开启线程 上一篇已经讲过
2)

Intent intent = new Intent(this,BankService.class);
        intent.setAction("cn.augest.test.aidl.bank");
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);

必须显性,不然在安卓5.0会报错!!!!!

~~号外~~福利~~号外~~
程序员的福音: “老曾筋骨祛痛贴”,百年祖传配方,专治腰间盘肩周颈椎坐骨神经腰腿疼痛等,博主亲测效果非常棒,因长期久坐写代码,坐姿不规范导致脖子疼,腰椎疼,用过之后疼痛逐渐缓解,现在已无任何疼痛,用过后让你写代码一身轻松,so easy,妈妈再也不用担心我们写代码了。
购买链接: https://k.weidian.com/tja7GYzB

扫码下方二维码,关注公众号“伟大程序猿的诞生“,回复“膏药”领取优惠券
扫码关注公众号“伟大程序猿的诞生“,更多干货新鲜文章等着你~
Android 中的Binder跨进程通信机制与AIDL_第3张图片
公众号回复“资料获取”,获取更多干货哦~
公众号回复“膏药”,领取优惠券哦~

有问题添加本人微信号“fenghuokeji996” 或扫描博客导航栏本人二维码

你可能感兴趣的:(安卓菜鸟进阶,安卓菜鸟进阶)