Android进程间通信(2)-纯代码,非AIDL

上一篇文章中我们已经实现了进程间的通信,但是文章最后留了一个问题,就是实现进程间通信是不是只用通过aidl?答案是no,这篇文章我就带大家通过纯代码的方法实现以下进程间的通信。

1,服务端,我们新建一个Service,取名为MyCodeService.java,代码如下:

package com.wms.github.aidl.server;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

/**
 * Created by 王梦思 on 2017/5/25.
 */

public class MyCodeService extends Service {

    private static final String TAG = "MyService";

    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind...");
        //这里不能返回null,必须要返回我们创建的Binder对象
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind...");
        return super.onUnbind(intent);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Log.e(TAG, "onStart...");
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand...");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate...");
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy...");
        super.onDestroy();
    }

    /**
     * 这里一定要继承自String2UpperCase.Stub
     */
    class MyBinder extends Binder {
        private static final String DESCRIPTOR = "com.wms.MyBinder";

        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            //code是和操作对应,这个code和客户端code对应
            switch (code) {
                case 0x001:
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = _arg0.toUpperCase();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
}

在MyCodeService中我们将MyBinder直接继承自Binder对象,aidl中式继承自Android Studio自动生成的java文件。在MyBinder里面,我们重写了onTransact方法,这个方法是在客户端发送请求的时候会调用transact方法,而transact方法内部代码如下:

/**
     * Default implementation rewinds the parcels and calls onTransact.  On
     * the remote side, transact calls into the binder to do the IPC.
     */
    public final boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

在transact内部回调了onTransact方法,所以在客户端发送消息后,就会调用到MyCodeService中的 onTransact方法,处理完数据后直接返回给客户端。

注意别忘记了在AndroidManifest.xml文件中注册MyCodeService.java

<service
            android:name="com.wms.github.aidl.server.MyCodeService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.wms.github.aidl.server.MyCodeService"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

这样服务端的代码就完成了,其实很简单。

2,客户端,新建一个CodeActivity,代码如下:

package com.wms.github.aidl.client;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

/**
 * Created by 王梦思 on 2017/5/25.
 */

public class CodeActivity extends MainActivity {
    private EditText mEditText;
    private IBinder mBinder;
    private static final String DESCRIPTOR = "com.wms.MyBinder";

    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //当绑定成功后调用
            mBinder = service;
            Log.e("MainActivity", "onServiceConnected...");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBinder = null;
            Log.e("MainActivity", "onServiceDisconnected...");
        }
    };

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

        mEditText = (EditText) findViewById(R.id.id_edittext);

        findViewById(R.id.bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService();
            }
        });

        findViewById(R.id.unbind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unBindService();
            }
        });

        findViewById(R.id.invokeServer).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                invokeServer();
            }
        });
    }

    /**
     * 绑定服务
     */
    public void bindService() {
        Intent intent = new Intent();
        intent.setAction("com.wms.github.aidl.server.MyCodeService");
        //Android 5.0以上必须要加这句代码,不然报错
        intent.setPackage("com.wms.github.aidl.server");
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    public void unBindService() {
        unbindService(mServiceConn);
    }

    public void invokeServer() {
        String inputStr = mEditText.getText().toString().trim();
        try {
            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(inputStr);
                mBinder.transact(0x001, _data, _reply, 0);
                _reply.readException();
                result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            //重新显示到Edittext
            mEditText.setText(result);
        } catch (RemoteException e) {
            //这里会抛出远程异常
            e.printStackTrace();
        }
    }
}

这里需要注意的是,在onServiceConnected中,aidl实现进程通信的时候是调用Stub内部方法asInterface来生成一个String2Uppercase对象的,这里没有这么做,因为我们没有String2Uppercase类,这里直接在CodeActivity中保存onServiceConnected回调回来的ibinder,大家可能会疑问这个ibinder是什么呢?其实就是我们上一篇文章中所说的binder驱动,不明白的可以去看上一篇文章。

当点击调用服务端转换按钮时,会执行如下代码

String inputStr = mEditText.getText().toString().trim();
        try {
            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(inputStr);
                mBinder.transact(0x001, _data, _reply, 0);
                _reply.readException();
                result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            //重新显示到Edittext
            mEditText.setText(result);
        } catch (RemoteException e) {
            //这里会抛出远程异常
            e.printStackTrace();
        }

关键的代码就是mBinder.transact(0x001, _data, _reply, 0);
这行代码其实就是让Binder驱动传送数据给服务端,其实内部和aidl实现一模一样,只是这些操作aidl利用apt工具自动给我们生成了而已。大家可以去查看下aidl文件生成的java文件就明白了。

通过本文的分析,大家是不是更加清晰了aidl的机制呢?也解决了我们文章开头的问题,解决进程通信没必要非要写aidl,aidl只是一个辅助我们更简单实现通信的。其实android系统中很多地方都用到了代码的方式来获取系统服务。这里我就不展开说了,如果有兴趣可以去查看framework代码。

代码传送门 : http:github.com/wms1993/blog_aidl_demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值