AIDL 客户端与服务端的双向通信
来源:互联网 发布:怎么修改淘宝账号名称 编辑:程序博客网 时间:2024/05/21 10:01
时隔一年半了,终于写下了这个续篇,我发现我的很多博客有头无尾,都是有前面一点点,后面就没写去了,也正在想办法都补上
- 初涉IPC,了解AIDL的工作原理及使用方法
今天聊聊的是客户端和服务端的相互通信,何谓双向通信,事实上,我们在上一篇的博客中,只是讲解了客户端请求服务端的方法,然后服务端返回一个值给我们这样,其实是最简单的用法,但是常常在我们的开发过程中,如果调用了某些方法,比如网络请求,那么就需要等待请求有结果了之后再回调给我们,这个回调的过程就是服务端向客户端通信,作为ipc通信的一种,如果你不会双向通信,那么你可以比较low的用广播,但是我还是建议你直接用一整套的AIDL复用,好的,那么问题来了,我们怎么下手呢?
服务端
我们新建两个工程,一个叫ADILClient,一个叫AIDLService,分别代表的是客户端和服务端
我们现在开始编写我们的aidl,这里我需要编写两个AIDL文件,一个是我们对外的方法,一个是我们对外的回调方法,如图
这里我做一下讲解,首先我new了一个aidl的文件夹,在main下,和java同级,然后定义了一个公共的包名:com.android.openimpl,最后在里面实现了两个aidl文件,我们来看下具体的文件内容
IMyLifeStyleInterface
// IMyLifeStyleInterface.aidlpackage com.android.openimpl;import com.android.openimpl.IMyLifeStyleListener;interface IMyLifeStyleInterface { //计算 void sum(int a ,int b); //睡觉 void sleep(boolean isSleep); //注册 void registerCallback(IMyLifeStyleListener il); //解绑 void unregisterCallback(IMyLifeStyleListener il);}
IMyLifeStyleListener
// IMyLifeStyleListener.aidlpackage com.android.openimpl;//回调接口interface IMyLifeStyleListener { //回调方法 void OnCallBackSleep(String text); void OnCallBackSize(int size);}
这里我定义了IMyLifeStyleInterface ,里面有两个方法,假设我定义的事一个人,他有基本的两个本能,一个是计算,我传两个数字给他,他进行一系列的处理,那么,问题来, 我不想用返回值,我想通过回调知道,这是一点,另一个是睡觉,而在IMyLifeStyleListener,我也定义了两个对应的回调OnCallBackSleep和OnCallBackSize,好了,现在开始来实现我们的远程Service服务
public class OpenImplService extends Service { private IMyLifeStyleListener lifeStyleListener; private IBinder mBinder = new IMyLifeStyleInterface.Stub() { @Override public void sum(int a, int b) throws RemoteException { //经过一系列的计算后将值告知客户端 int c = a * 2 + b; if (lifeStyleListener != null) { lifeStyleListener.OnCallBackSize(c); } } @Override public void sleep(boolean isSleep) throws RemoteException { //告诉客户端我已经睡着 if(isSleep){ if (lifeStyleListener != null) { lifeStyleListener.OnCallBackSleep("帮我关下灯,谢谢!"); } } } @Override public void registerCallback(IMyLifeStyleListener il) throws RemoteException { if (il != null) { lifeStyleListener = il; } } @Override public void unregisterCallback(IMyLifeStyleListener il) throws RemoteException { if (il != null) { lifeStyleListener = null; } } }; @Override public IBinder onBind(Intent intent) { return mBinder; }}
这里,我定义了一个远程的服务OpenImplService,里面我只是new了IMyLifeStyleInterface.Stub并且把Binder对象给了onBind方法,而在Binder内部,我做的操作相信大家都看的明白吧,很简单,Ok,那我们的服务端就已经搞定了,我们来看下服务端的整体结构
当然,别忘了在清单文件中注册
<service android:name=".service.OpenImplService" android:enabled="true" android:exported="true" />
客户端
好的,现在就开始来实现我们的客户端,客户端也需要同样的AIDL文件,所以我可以直接复制过去,但是要注意的是包名一定要相同,如图
这里,我的客户端就是app包下的东西,那么我们来实现UI上的逻辑
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp"> <EditText android:id="@+id/et_numer_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入a" /> <EditText android:id="@+id/et_numer_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入b" /> <Button android:id="@+id/btn_sum" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="计算" android:textAllCaps="false" /> <Button android:id="@+id/btn_sleep" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="睡觉" android:textAllCaps="false" /></LinearLayout>
这里,我定义了两个输入框和有个按钮,对应的计算和睡觉,好的,我们run一下
我们来开始实现具体的逻辑了,这也是我们客户端经常要干的事情首先,我们initService来初始化了服务,在android5.0之后绑定远程服务都需要完整的包名了,如下
private void initService() { Intent i = new Intent(); //Android 5.0 之后需要直接定义包名 i.setComponent(new ComponentName("com.liuguilin.aidlservice", "com.liuguilin.aidlservice.service.OpenImplService")); bindService(i, mConnection, Context.BIND_AUTO_CREATE); }
这里需要传一个mConnection,这是一个对应的关系,如果现在bind,你销毁的时候需要unBind
@Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); }
好的,我们具体来看下mConnection的内容吧
private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "onServiceConnected"); //获取AIDL对象 iMyLifeStyleInterface = IMyLifeStyleInterface.Stub.asInterface(iBinder); //注册接口 try { iMyLifeStyleInterface.registerCallback(new OpenImpleListener()); } catch (RemoteException e) { e.printStackTrace(); } isBind = true; } @Override public void onServiceDisconnected(ComponentName componentName) { Log.i(TAG, "onServiceDisconnected"); try { iMyLifeStyleInterface.unregisterCallback(new OpenImpleListener()); } catch (RemoteException e) { e.printStackTrace(); } iMyLifeStyleInterface = null; isBind = false; } };
他一共会重写两个方法,服务绑定onServiceConnected和服务解绑onServiceDisconnected,所以这里我们用了一个标志位isBind来标记绑定状态,然后通过AIDL的asInterface方法来实例化对应的AIDL对象,然后就是注册这个接口回调了
class OpenImpleListener extends IMyLifeStyleListener.Stub { @Override public void OnCallBackSleep(String text) throws RemoteException { Toast.makeText(MainActivity.this, "text:" + text, Toast.LENGTH_SHORT).show(); } @Override public void OnCallBackSize(int size) throws RemoteException { Toast.makeText(MainActivity.this, "size:" + size, Toast.LENGTH_SHORT).show(); } }
这里要注意的事需要继承的是AIDL的Stub,最后就是我们的点击事件了
@Override public void onClick(View v) { if (isBind) { switch (v.getId()) { case R.id.btn_sum: String a = et_numer_1.getText().toString().trim(); String b = et_numer_2.getText().toString().trim(); try { iMyLifeStyleInterface.sum(Integer.parseInt(a),Integer.parseInt(b)); } catch (RemoteException e) { e.printStackTrace(); } break; case R.id.btn_sleep: try { iMyLifeStyleInterface.sleep(true); } catch (RemoteException e) { e.printStackTrace(); } break; } } else { Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show(); } }
这里算是比较简单的了,传值调用即可,好的,下面贴上全部的代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "AIDL"; private EditText et_numer_1; private EditText et_numer_2; private Button btn_sum; private Button btn_sleep; //绑定状态 private static boolean isBind = false; private IMyLifeStyleInterface iMyLifeStyleInterface; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "onServiceConnected"); //获取AIDL对象 iMyLifeStyleInterface = IMyLifeStyleInterface.Stub.asInterface(iBinder); //注册接口 try { iMyLifeStyleInterface.registerCallback(new OpenImpleListener()); } catch (RemoteException e) { e.printStackTrace(); } isBind = true; } @Override public void onServiceDisconnected(ComponentName componentName) { Log.i(TAG, "onServiceDisconnected"); try { iMyLifeStyleInterface.unregisterCallback(new OpenImpleListener()); } catch (RemoteException e) { e.printStackTrace(); } iMyLifeStyleInterface = null; isBind = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initService(); initView(); } private void initService() { Intent i = new Intent(); //Android 5.0 之后需要直接定义包名 i.setComponent(new ComponentName("com.liuguilin.aidlservice", "com.liuguilin.aidlservice.service.OpenImplService")); bindService(i, mConnection, Context.BIND_AUTO_CREATE); } private void initView() { et_numer_1 = (EditText) findViewById(R.id.et_numer_1); et_numer_2 = (EditText) findViewById(R.id.et_numer_2); btn_sum = (Button) findViewById(R.id.btn_sum); btn_sleep = (Button) findViewById(R.id.btn_sleep); btn_sum.setOnClickListener(this); btn_sleep.setOnClickListener(this); } @Override public void onClick(View v) { if (isBind) { switch (v.getId()) { case R.id.btn_sum: String a = et_numer_1.getText().toString().trim(); String b = et_numer_2.getText().toString().trim(); try { iMyLifeStyleInterface.sum(Integer.parseInt(a),Integer.parseInt(b)); } catch (RemoteException e) { e.printStackTrace(); } break; case R.id.btn_sleep: try { iMyLifeStyleInterface.sleep(true); } catch (RemoteException e) { e.printStackTrace(); } break; } } else { Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show(); } } class OpenImpleListener extends IMyLifeStyleListener.Stub { @Override public void OnCallBackSleep(String text) throws RemoteException { Toast.makeText(MainActivity.this, "text:" + text, Toast.LENGTH_SHORT).show(); } @Override public void OnCallBackSize(int size) throws RemoteException { Toast.makeText(MainActivity.this, "size:" + size, Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); }}
可以发现,代码很是简洁,希望大家能够学会,最后我们运行一遍
这里可以看到,点击睡觉,服务端会叫我们关下灯,而计算的话,我传的是2和3,服务端计算了一下 2 * 2 + 3 = 7 并且返回回来了。
Demo下载:点击下载
我的公众号,期待你的关注
- AIDL 客户端与服务端的双向通信
- AIDL 客户端与服务端的双向通信
- Java-Soket实现客户端与服务端双向通信
- Android aidl项目中服务端与客户端aidl文件不一致引起的问题
- Android aidl项目中服务端与客户端aidl文件不一致引起的问题
- AIDL使用入门, 客户端通过AIDL与服务端通信
- Java中利用socket实现简单的服务端与客户端的通信(中级)——实现任意双向通信
- android AIDL简单入门(客户端与服务端)
- 【网络编程】(五)NIO特点、实现客户端和服务端的单/双向通信
- AIDL使用详解(三) 客户端通过AIDL与服务端通信 实例项目
- 客户端与服务端的互动
- 【转】UDP Socket编程-客户端和服务端双向通信
- 【转】TCP Socket编程-客户端和服务端双向通信
- c语言socket双向通信+一服务端对多客户端通信
- Socket服务器与客户端双向通信实例
- UDP实现服务器与客户端双向通信
- Android 跨进程双向通信(Messenger与AIDL)详解
- 使用AIDL双向通信
- 4.2创建与合并分支
- CC2640的Flash操作
- java日志文件log4j.properties配置详解
- HDU 6230 Palindrome(主席树)
- 电子老鼠闯迷宫
- AIDL 客户端与服务端的双向通信
- Ubuntu 安装Android Studio3.0
- 刚入行的人员怎样去学习web前端呢?
- Bootstrap Table获取点击行的index
- JPanel的移除控件和刷新
- unlocked_ioctl和compat_ioctl
- html5 video无法播放视频
- [Java通信]Java通过HTTP请求发送HTTP服务器
- python-简单验证码识别-保监会网站