使用AIDL实现IPC通信之——简单调用远程服务的方法
来源:互联网 发布:linux 只显示文件大小 编辑:程序博客网 时间:2024/05/16 15:28
为什么使用AIDL
AIDL和Messenger都可以实现跨进程通信,Messenger底层也是基于AIDL的。使用AIDL而不使用Messenger的情况是:允许从不同应用的客户端访问你的Service且你的Service需要处理多线程的情况,因为Messenger中的消息默认是串行执行的。还有一点就是:使用Messenger主要是为了传递消息,很多时候需要跨进程调用服务端的方法,这种情况Messenger就无法做到了,可以使用AIDL实现跨进程的方法的调用。
AIDL主要分为客户端和服务端实现:
1、服务端实现:
1、创建aidl文件:在Android Studio当中创建一个文件夹aidl,然后再找个文件夹中创建一个包,在这个包里面创建一个aidl文件,如下所示。在接口中定义了三个方法。当重新Make Project,会在Android Studio的工程目录:build/generated/source/aidl/debug/aidl包名 目录下面生成对应的.java文件。这个.java文件就是对Binder的封装,使得我们不需要直接对Binder进行操作。
// IRemoteService.aidlpackage com.easyliu.demo.aidlremotedemo;// Declare any non-default types here with import statementsinterface IRemoteService { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ int getPid(); int add(int a,int b); void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);}
2、创建一个Service,在Service当中使用上面的aidl接口创建一个IBinder对象,然后在Service的onBind()方法中返回这个IBinder对象即可。如下所示:
package com.easyliu.demo.aidlremotedemo;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.Process;import android.os.RemoteException;import android.util.Log;public class RemoteService extends Service { private static final String TAG = RemoteService.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return mBinder; } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); } private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { @Override public int getPid() throws RemoteException { return Process.myPid(); } @Override public int add(int a, int b) throws RemoteException { return a + b; } @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } };}
3、然后记得在Manifest文件里面进行注册,不过Android Studio会自动生成,这一点很方便。在这里指定了一个action,这样别的进程就可以通过Intent来查找此Service。注意,当给Service加上Intent-filter之后,其android:exported默认就为true了,这样别的APP就可以访问了。同时,设置了android:process属性,让Service运行在不同的进程。这跟运行在两个APP当中效果是一样的,所以可以直接放在一个APP当中进行测试。
<service android:name=".RemoteService" android:process=":remote" android:enabled="true"> <intent-filter> <action android:name="com.easyliu.demo.aidlremotedemo.RemoteService" /> </intent-filter> </service>
2、客户端实现:
客户端的代码比较简单,在布局文件当中创建两个文本输入框、一个按钮和一个文本显示控件。点击按钮调用远程服务端的方法执行加法操作,然后在文本控件中显示。
布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.easyliu.demo.aidlremotedemo.MainActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/et_mainActivity_inputA" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="input a number a" android:inputType="number" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/et_mainActivity_inputB" android:layout_below="@+id/et_mainActivity_inputA" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="input a number b" android:inputType="number" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add" android:id="@+id/btn_mainActivity_add" android:layout_below="@+id/et_mainActivity_inputB" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1" android:textSize="20sp" android:layout_marginTop="20dp" android:id="@+id/tv_sum" android:layout_below="@+id/btn_mainActivity_add" android:layout_centerHorizontal="true" /></RelativeLayout>
主Activity:
package com.easyliu.demo.aidlremotedemo;import android.content.ComponentName;import android.content.Context;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.EditText;import android.widget.TextView;public class MainActivity extends AppCompatActivity { private AdditionServiceConnection mServiceConnection; private EditText et_mainActivity_inputA; private EditText et_mainActivity_inputB; private Button btn_mainActivity_add; private TextView tv_sum; private boolean mIsBound; private IRemoteService mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); } @Override protected void onStart() { super.onStart(); doBindService(); } /** * init Views */ private void initViews() { et_mainActivity_inputA = (EditText) findViewById(R.id.et_mainActivity_inputA); et_mainActivity_inputB = (EditText) findViewById(R.id.et_mainActivity_inputB); tv_sum = (TextView) findViewById(R.id.tv_sum); btn_mainActivity_add = (Button) findViewById(R.id.btn_mainActivity_add); btn_mainActivity_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { if (mService != null) { int sum = mService.add(Integer.parseInt(et_mainActivity_inputA.getText().toString()), Integer.parseInt(et_mainActivity_inputB.getText().toString())); tv_sum.setText(String.valueOf(sum)); } else { tv_sum.setText("请先绑定服务!"); } } catch (RemoteException e) { e.printStackTrace(); } } }); } /** * bind service */ private void doBindService() { mServiceConnection = new AdditionServiceConnection(); Intent intent = new Intent(RemoteService.class.getName()); intent.setPackage("com.easyliu.demo.aidlremotedemo"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } /** * unbind service */ private void doUnbindService() { if (mIsBound) { unbindService(mServiceConnection); mServiceConnection = null; mIsBound = false; } } /** * ServiceConection */ class AdditionServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = IRemoteService.Stub.asInterface((IBinder) service); mIsBound = true; try { //设置死亡代理 service.linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } tv_sum.setText("Servie Conected!"); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; mIsBound = false; tv_sum.setText("Servie DisConected!"); } } /** * 监听Binder是否死亡 */ private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mService == null) { return; } mService.asBinder().unlinkToDeath(mDeathRecipient, 0); mService = null; //重新绑定 doBindService(); } }; @Override protected void onStop() { super.onStop(); doUnbindService(); } @Override protected void onDestroy() { super.onDestroy(); }}
在主Activity当中,在onStart方法当中bindService,然后在onStop方法当中unBindService。当然你可以在onCreate方法当中bindService,然后在onDestory方法unBindService,看具体需求。也可以手动进行绑定和解绑。
同时给返回的IBinder对象设置了一个死亡代理,当远端Service由于某种原因死亡的时候,就会调用此回调方法,我们就可以在此方法当中进行一些操作,比如,重新bindService等。
当然,也可以在onServiceDisconnected里面重新连接Service,只是这个方法运行在主线程,可以访问主UI,而DeathRecipient接口的binderDied回调方法中不能访问主UI。
3、验证AIDL功能
当执行打开主界面->回到home->再进入主界面,打印的log如下所示,说明远程绑定成功。当回到桌面的时候,会调用Activity的onStop方法,在里面会解除绑定。由于这里只有一个客户端绑定到Service,所以当绑定解除的时候就销毁了。关于绑定服务的详细简介,请参考:Bound Service
<span style="font-size:12px;">06-18 21:59:11.313 2471-2471/com.easyliu.demo.aidlremotedemo:remote I/RemoteService: onBind06-18 21:59:36.842 2471-2471/com.easyliu.demo.aidlremotedemo:remote I/RemoteService: onUnbind06-18 21:59:36.842 2471-2471/com.easyliu.demo.aidlremotedemo:remote I/RemoteService: onDestroy06-18 21:59:51.743 2471-2471/com.easyliu.demo.aidlremotedemo:remote I/RemoteService: onBind</span><strong style="font-size: 24px;"></strong>
下面来看一下执行效果
启动Activity,输入两个数字1和7,点击ADD按钮,得到数字8,说明成功调用远程服务端的方法。
然后当按home键退回桌面再打开,界面如下所示,说明当返回Activity的时候调用了onStart方法,重新bindService。
- 使用AIDL实现IPC通信之——简单调用远程服务的方法
- Android开发之AIDL实现远程服务进程通信(IPC)
- android 使用AIDL和服务通信实现IPC通信
- 使用AIDL实现IPC通信之——实现服务端主动发送数据给客户端
- android,aidl,绑定远程服务,调用远程服务的方法
- Android-->IPC(跨进程)通信Aidl的实现方法
- IPC—AIDL最简单的实现步骤
- android中的跨进程通信的实现(一)——远程调用过程和aidl
- android中的跨进程通信的实现——远程调用过程和aidl(转)
- android中的跨进程通信的实现(一)——远程调用过程和aidl
- android中的跨进程通信的实现(一)——远程调用过程和aidl
- Android中的跨进程通信的实现——远程调用过程和aidl
- Android中的跨进程通信的实现(一)——远程调用过程和aidl
- 使用AIDL和远程服务实现进程通信
- Android使用AIDL和远程服务实现进程通信
- 使用AIDL和远程服务实现进程通信
- Android--使用AIDL和远程服务实现线程通信
- 使用AIDL和远程服务实现进程通信
- 手动产生crashdump的方法
- 用代码控制unityeditor的暂停/播放状态
- 循环显示上级目录
- Openstack组件实现原理 — Keystone认证功能
- [Java语言] Clob转String
- 使用AIDL实现IPC通信之——简单调用远程服务的方法
- [Java语言] 实线与虚线
- 关于Java异常处理
- 词组缩写 英语句子所有单词首字母大写输出 C语言/C++编程题
- mac下使用latex的各种问题
- 拥抱高效、拥抱 Bugtags 之来自用户的声音(三)
- 自动更新技术解决方案
- sorting a python list by two criteria
- 愿时光温柔相待