Android进程间通信(2)-纯代码,非AIDL
来源:互联网 发布:apache storm 教程 编辑:程序博客网 时间:2024/06/11 15:44
上一篇文章中我们已经实现了进程间的通信,但是文章最后留了一个问题,就是实现进程间通信是不是只用通过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
- Android进程间通信(2)-纯代码,非AIDL
- android AIDL 进程间通信
- android aidl进程间通信
- Android 进程间通信AIDL
- Android进程间通信--AIDL
- Android进程间通信--AIDL
- android 进程间通信(aidl)
- android AIDL进程间通信
- android进程间通信:AIDL
- Android AIDL 进程间通信
- Android进程间通信AIDL
- Android进程间通信---AIDL
- Android 进程间通信AIDL
- Android进程间通信-AIDL
- android 进程通信aidl
- android 进程通信--aidl
- android进程间通信:使用AIDL
- android进程间通信:使用AIDL
- spring bean加载--从缓存中获取beanspring bean加载--从缓存中获取bean【转】
- 【RecycleView加分割线】Android RecycleView列表布局添加分割线如此简单
- 小细节!!!!(二维树状数组的相关操作)
- 要创建一个事件驱动的程序需要下面的步骤
- MySQL查看和新增表分区
- Android进程间通信(2)-纯代码,非AIDL
- leetcode 513. Find Bottom Left Tree Value
- 若干题目2
- 搜索-H
- lucene完全匹配
- Centos7下各种配置集合
- 使用sftp下载文件
- Lagom参考指南(二)
- 使用饿了吗switch改变状态,改变图标的状态