进程间通信之Binder理解之一

这篇文章 我觉得写进程间通信,写Binder的介绍,写的非常的好,读了以后对binder有了更深的理解。不过我觉得这篇文章写Binder,写的还是比较虚,都是一些跨进程啊什么的,不是很好理解。于是我根据这篇文章的理解,用App进程、类来模拟进程间通信的过程,自己手写了一个进程间通信。

App进程:模拟安卓系统

MyBinder类:模拟Binder类

Process接口:表示进程

ProcessA:A进程

ProcessB:B进程

SystemServiceManager:模拟系统SystemService类

所有进程Process都是用单例模式,表示单个进程

1.先看进程类

public interface IProcess {
}

空接口,就表示一个进程

2.MyBinder 类

public class MyBinder {
    //这个就是解决鸡生蛋蛋生鸡问题的那个预设的鸡
    public static final String FIRST_BINDER = "0";
    private static MyBinder sFirstBinder;
    //进程名称
    private String processName;
    //进程的binder
    private MyBinder processBinder;
    //进程
    private IProcess processProcxy;

    private Parcelable data;

    public MyBinder(String processName, MyBinder processBinder, IProcess processProcxy) {
        this.processName = processName;
        this.processBinder = processBinder;
        this.processProcxy = processProcxy;
        if (FIRST_BINDER.equals(processName)) {
            if (null == sFirstBinder) {
                sFirstBinder = this;
            } else {
                throw new RuntimeException("只能有一个初始化binder");
            }
        }
    }

    public String getProcessName() {
        return processName;
    }

    public void setProcessName(String processName) {
        this.processName = processName;
    }

    public MyBinder getProcessBinder() {
        return processBinder;
    }

    public void setProcessBinder(MyBinder processBinder) {
        this.processBinder = processBinder;
    }

    public IProcess getProcessProcxy() {
        return processProcxy;
    }

    public void setProcessProcxy(IProcess processProcxy) {
        this.processProcxy = processProcxy;
    }

    public static MyBinder getFristBinder() {
        return sFirstBinder;
    }

    public Parcelable getData() {
        return data;
    }

    public void setData(Parcelable data) {
        this.data = data;
    }
}

三个字段:

processName 进程名称,用于在systemservice中注册时用
processBinder 进程binder,用于在systemservice中注册时用
processProcxy 进程,记录当前进程的引用,可以通过binder拿到进程

还有一个sFirstBinder ,表示最原始的Binder,进程名字为0的进程,任意两个进程通信都先需要这个binder来开始

3.因为系统启动后,先创建的是SystemService进程,因此我们先看这个模拟类

public class SystemServiceManager implements IProcess {
    //单例模式表示进程
    private static volatile SystemServiceManager sSSMInstance;
    //SystemService进程中的Binder实体,其实就是那个最原始的鸡Binder
    private MyBinder mMyBinder;
    //保存所有其他进程的Binder引用,key为进程名,value为binder引用
    private HashMap<String, MyBinder> mAllBinder = new HashMap<>();

    //构造器中创建SystemService进程的Binder实体,并且这个Binder名称为0,其他任何进程都可以获取到
    private SystemServiceManager() {
        mMyBinder = new MyBinder(MyBinder.FIRST_BINDER, null, this);
    }

    public static SystemServiceManager getInstance() {
        if (null == sSSMInstance) {
            synchronized (SystemServiceManager.class) {
                if (null == sSSMInstance) {
                    sSSMInstance = new SystemServiceManager();
                }
            }
        }
        return sSSMInstance;
    }

    //其他进程通过这个方法将自己进程中的Binder引用在SystemService中注册
    public void registProcessBinder() {
        MyBinder processBinder = mMyBinder.getProcessBinder();
        if (null != processBinder) {
            mAllBinder.put(processBinder.getProcessName(), processBinder);
        }
    }

    //通过进程名获取进程Binder引用的方法
    public MyBinder getProcessBinder(String processName) {
        return mAllBinder.get(processName);
    }
}

4.ProcessA 进程A的代码

public class ProcessA implements IProcess {
    //单例模式模拟进程A
    private static volatile ProcessA sProcessA;
    //进程A中的Binder实体
    private MyBinder mMyBinder;

    private ProcessA() {
        //创建实体Binder
        mMyBinder = new MyBinder(getClass().getSimpleName(), null, this);
        //将Binder实体在SystemService中注册,注册过程是:通过Binder获取sFirstBinder---获取SystemService进程-----调用SystemService的注册方法(通过sFirstBinder将自己携带过去)
        MyBinder.getFristBinder().setProcessBinder(mMyBinder);
        ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).registProcessBinder();
    }

    public static ProcessA getInstance() {
        if (null == sProcessA) {
            synchronized (SystemServiceManager.class) {
                if (null == sProcessA) {
                    sProcessA = new ProcessA();
                }
            }
        }
        return sProcessA;
    }


    private String name = "我是进程A";

    public void getName(MyBinder binder) {
        binder.setData(new Data(name));
    }

    public void setName(MyBinder binder) {
        Data data = (Data) binder.getData();
        name = data.getData();
        Log.e("TAG", "setName: " + name);
    }

    /**
     * 获取进程B的name字段
     */
    public void getProcessBName() {
        //获取进程B的name字段,通过Binder获取sFirstBinder---获取SystemService进程-----获取B进程的Binder----获取B进程引用----调用B进程的方法
        MyBinder processBBinder = ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).getProcessBinder(ProcessB.class.getSimpleName());
        if (null != processBBinder) {
            ((ProcessB) processBBinder.getProcessProcxy()).getName(processBBinder);
            Log.e("TAG", "getProcessBName: " + ((Data) processBBinder.getData()).getData());
        }
    }

    /**
     * 获取进程B的name字段
     */
    public void setProcessBName() {
        //获取进程B的name字段,通过Binder获取sFirstBinder---获取SystemService进程-----获取B进程的Binder----获取B进程引用----调用B进程的方法
        MyBinder processBBinder = ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).getProcessBinder(ProcessB.class.getSimpleName());
        if (null != processBBinder) {
            mMyBinder.setData(new Data("A进程给B进程设置的名字"));
            ((ProcessB) processBBinder.getProcessProcxy()).setName(mMyBinder);
        }
    }
}

5.同样的原理写B进程

public class ProcessB implements IProcess {
    private static volatile ProcessB sProcessA;
    private MyBinder mMyBinder;

    private ProcessB() {
        mMyBinder = new MyBinder(getClass().getSimpleName(), null, this);
        MyBinder.getFristBinder().setProcessBinder(mMyBinder);
        ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).registProcessBinder();
    }

    public static ProcessB getInstance() {
        if (null == sProcessA) {
            synchronized (SystemServiceManager.class) {
                if (null == sProcessA) {
                    sProcessA = new ProcessB();
                }
            }
        }
        return sProcessA;
    }


    private String name = "我是进程B";

    //获取数据,需要服务端,也就是自己的binder传递数据
    public void getName(MyBinder binder) {
        binder.setData(new Data(name));
    }

    //设置数据,需要客户端,也就是对方服务端的binder传递数据
    public void setName(MyBinder binder) {
        Data data = (Data) binder.getData();
        name = data.getData();
        Log.e("TAG", "setName: " + name);
    }


    /**
     * 获取进程B的name字段
     */
    public void getProcessAName() {
        MyBinder processBBinder = ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).getProcessBinder(ProcessA.class.getSimpleName());
        if (null != processBBinder) {
            ((ProcessA) processBBinder.getProcessProcxy()).getName(processBBinder);
            Log.e("TAG", "getProcessAName: " + ((Data) processBBinder.getData()).getData());
        }
    }

    /**
     * 获取进程B的name字段
     */
    public void setProcessAName() {
        MyBinder processBBinder = ((SystemServiceManager) MyBinder.getFristBinder().getProcessProcxy()).getProcessBinder(ProcessA.class.getSimpleName());
        if (null != processBBinder) {
            //模拟数据的一次拷贝过程
            mMyBinder.setData(new Data("B进程给A进程设置的名字"));
            ((ProcessA) processBBinder.getProcessProcxy()).setName(mMyBinder);
        }
    }
}

6.最后我们看模拟系统代码

//模拟系统进程
public class MainActivity extends AppCompatActivity {

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

        //启动SystemService进程
        SystemServiceManager.getInstance();
        //启动A进程
        ProcessA.getInstance();
        //启动B进程
        ProcessB.getInstance();

        //模拟A进程中获取B进程名字,这个方法应该在A进程中调用
        ProcessA.getInstance().getProcessBName();
        //模拟A进程中设置B进程名字,这个方法应该在A进程中调用
        ProcessA.getInstance().setProcessBName();

        //模拟B进程中获取A进程名字,这个方法应该在B进程中调用
        ProcessB.getInstance().getProcessAName();
        //模拟B进程中设置A进程名字,这个方法应该在B进程中调用
        ProcessB.getInstance().setProcessAName();
    }
}

这样我们就简单模拟了一下进程间通信。ProcessA和ProcessB之间不会有任何联系,都是通过系统服务类SystemServiceManager来实现的,而任意两个进程之间的交流,又都是通过Binder实现的,而且跨进程数据是一次拷贝。

补一个跨进程传递的数据类:

public class Data implements Parcelable {
    private String data;

    public Data(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.data);
    }

    public Data() {
    }

    protected Data(Parcel in) {
        this.data = in.readString();
    }

    public static final Parcelable.Creator<Data> CREATOR = new Parcelable.Creator<Data>() {
        @Override
        public Data createFromParcel(Parcel source) {
            return new Data(source);
        }

        @Override
        public Data[] newArray(int size) {
            return new Data[size];
        }
    };
}

demo 下载地址为: demo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值