AndroidStudio通过AIDL开启、绑定远程Service
2016-04-17 15:25
567 查看
前言
关于服务的启动方式(startService()、stopService()、bindService()、unbindService()),我这里就不多说了,可以参考这篇博文。示例原理图
本文以一个简单的案例,记录一下怎么使用AIDL结合服务实现进程间的通信:首先,创建两个项目,一个项目(RemoteService)作为远程服务提供端,另一个(RemoteServiceTest)作为调用远程服务的客户端.然后,当客户端绑定远程服务后,可以通过AIDL接口调用远程服务中的方法,原理过程如图:
远程服务RemoteService 项目
1.创建AIDL文件,选中要提供的服务类所在的包名,右键 -> New -> AIDL -> AIDL File文件,如图这里将AIDL文件命名为RemoteInterface,创建完成后,会在main下生成一个aidl文件夹,一个包名与刚刚选中的包名相同的包,包下生成了一个RemoteInterface.aidl,如图
2.打开RemoteInterface.aidl文件,定义一个接口方法 remotePrintInterface(); 重新编译一下项目,如果成功编译那么会在如下目录中生成一个RemoteInterface接口文件
注意不要修改这个接口文件,接口中有一个重要的 Stub类,是之后要用的,Stub类继承了Binder,并实现了RemoteInterface接口。
3.创建一个服务类如RemoteService让其继承自Service, 服务中定义一个方法remotePrint(),并定义一个内部类 MyBinder 继承自 Stub, 实现Stub或者说RemoteInterface接口中的remotePrintInterface()的方法,让这个方法去调用服务的remotePrint()方法,代码如下:
package com.yu.remoteservice; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log; import android.widget.Toast; /** * Created by yu on 2016/4/15. */ public class RemoteService extends Service { private static final String TAG = "RemoteService"; @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG,"RemoteService 绑定 ------------------------------------------"); Toast.makeText(this,"远程服务绑定",Toast.LENGTH_SHORT).show(); return new MyBinder();//一定要记得返回 MyBinder 对象 } //内部类继承自Stub class MyBinder extends RemoteInterface.Stub{ //实现RemoteInterface中的方法 @Override public void remotePrintInterface() { //调用服务的方法 remotePrint(); } } public void remotePrint() { Log.d(TAG,"通过接口调用 RemoteService 的 remotePrint 方法"); } @Override public void onCreate() { super.onCreate(); Log.d(TAG,"RemoteService 创建 ------------------------------------------"); Toast.makeText(this,"远程服务创建",Toast.LENGTH_SHORT).show(); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG,"RemoteService 销毁 ------------------------------------------"); Toast.makeText(this,"远程服务销毁",Toast.LENGTH_SHORT).show(); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG,"RemoteService 解绑 ------------------------------------------"); Toast.makeText(this,"远程服务绑定",Toast.LENGTH_SHORT).show(); return super.onUnbind(intent); } }
4.在清单文件中注册服务
<service android:name=".RemoteService"> <intent-filter> <action android:name="com.yu.remote"/> </intent-filter> </service>
通过上面的步骤,服务端就算码完了,客户端绑定服务后,可以通过onBind方法返回的MyBinder对象中的方法来间接调用服务中的方法。
客户端RemoteServiceTest 项目:
1.目的是要在main下生成一个跟RemoteService中的aidl一毛一样的文件,做法是:1)在main下创建一个aidl文件夹
2)在aidl文件夹下创建一个包,包名跟服务端aidl文件所在的包名一样,此处即为com.yu.remoteservice
3)拷贝服务端的RemoteInterface.aidl文件到包下。
4)rebuild project,结束后,应该会生成和服务端一毛一样的接口
结果如图
2.绑定服务,得到服务返回的Ibinder对象,强转为接口的类型,并调用接口的方法,去间接调用服务中的方法
客户端代码如下:
package com.yu.remoteservicetest; import android.content.ComponentName; 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.util.Log; import android.view.View; import android.widget.Toast; import com.yu.remoteservice.RemoteInterface; public class MainActivity extends AppCompatActivity { private final String TAG = "RemoteServiceTest"; //远程服务的包名 private final String RemoteServicePackage = "com.yu.remoteservice"; //绑定服务时的连接对象 private ServiceConnection conn = null; //通过aidl创建的接口类的对象 private RemoteInterface ri = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void start(View view) { Intent intent = new Intent(); //设置意图对象要匹配的action intent.setAction("com.yu.remote"); //android 5.0之后 //设置包名,这里测试了一下,必须是服务所在的包名才可以 intent.setPackage(RemoteServicePackage); startService(intent); } public void stop(View view) { Intent intent = new Intent(); intent.setAction("com.yu.remote"); intent.setPackage(RemoteServicePackage); stopService(intent); } //绑定服务 public void bind(View view) { Intent intent = new Intent(); intent.setAction("com.yu.remote"); intent.setPackage(RemoteServicePackage); if (conn == null) { //创建连接服务的对象 conn = new RemoteServiceConnection(); } bindService(intent,conn,BIND_AUTO_CREATE); } public void unbind(View view) { if (conn != null) { unbindService(conn); conn = null; } } //调用服务的方法 public void callRemotePrint(View view) { Log.d(TAG,"callRemotePrint........................"); if (ri != null) { try { //通过调用接口对象的remotePrintInterface方法,简介调用服务的remotePrint方法 ri.remotePrintInterface(); } catch (RemoteException e) { e.printStackTrace(); } } else { Toast.makeText(this,"remote interface is null",Toast.LENGTH_SHORT).show(); } } //实现ServiceConnection类,用于创建连接服务的对象 class RemoteServiceConnection implements ServiceConnection { //当使用bindService方法绑定服务,并且服务返回IBinder对象的时候会调用 @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG,"onServiceConnected........................"); //强转为接口对象 ri = RemoteInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } } @Override protected void onDestroy() { super.onDestroy(); if (conn != null) { unbindService(conn); conn = null; } } }
客户端界面
文件目录结构
客户端文件目录结构远程服务文件目录结构
遇到的问题:
1.在创建aidl文件后,没有去自动生成相应的接口,reBuild后报以下错误:Error:Execution failed for task ‘:app:compileDebugAidl’.
java.lang.RuntimeException:
com.android.ide.common.process.ProcessException:
org.gradle.process.internal.ExecException: Process ‘command
‘F:\Study\Android\soft\adt-bundle-windows-x86_64-20140321\sdk\build-tools\24.0.0-preview\aidl.exe”
finished with non-zero exit value 1
搜了一下,大概是说 项目的编译版本和编译工具的版本不一致。。。蛋碎。。。
最后解决的办法是:
右键项目 open Moudle Setting -> app -> 修改Compile Sdk Version 和Build Tools Version 版本一致。
2.无论是startService还是bindService都没有能够启动远程服务:
原因是android5.0以后表面上是不能隐式启动Service的,参考这篇文章
而且,intent.setPackage(RemoteServicePackage);必须设置为服务所在的包名,否则是不能开启服务的,而且没有任何错误或警告给出。。。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析