Android AIDL:跨进程调用Service (AIDL Service)
来源:互联网 发布:高清矩阵 编辑:程序博客网 时间:2024/04/29 14:15
一、概述
开发环境:Android Studio 1.4.1
Android Developer Guides : Bound Services 和 AIDL .
1. 相关知识点
Android系统中的进程之间不能共享内存,需要提供一些机制在不同进程之间进行数据通信,这个机制就是AIDL。
1. AIDL: Android Interface definition language
Android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。
2. IPC:interprocess communication (内部进程通信)
3. 如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
2. 选择AIDL的使用场合
官方文档特别提醒我们何时使用AIDL是必要的:
- 只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。
- 如果不需要进行不同应用程序间的并发通信(IPC),you should create your interface by implementing a Binder;或者你想进行IPC,但不需要处理多线程的,则implement your interface using a Messenger。
- 无论如何,在使用AIDL前,必须要理解如何绑定service——bindService。
二、跨应用启动Service
从 Android 5.0 以后只能通信显式 Intent 来启动服务。
在这里我们新建一个Project:StartServiceFromAnotherAPP
- 再创建一个Service:APPService
- 重写 onCreate(),onDestroy()方法如下
@Override public void onCreate() { super.onCreate(); Log.i("TAG","AppService onCreate"); } @Override public void onDestroy() { super.onDestroy(); Log.i("TAG", "AppService onDestroy"); }
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService(new Intent(this, AppService.class)); } @Override protected void onDestroy() { super.onDestroy(); stopService(new Intent(this, AppService.class)); }}
启动应用和退出后可以看到日志信息:
至此可以发现在同一个应用中启动和停止Service是非常简单的。
那么如何在另一个应用中启动Service呢?
- 下面我们在该Project中新建一个Module:AnotherApp
- 在布局文件中加入两个Button:“启动服务”和“停止服务”
修改 MainActivity.java 代码 :
public class MainActivity extends AppCompatActivity implements OnClickListener { private Intent mServiceIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_start_Service).setOnClickListener(this); findViewById(R.id.btn_stop_Service).setOnClickListener(this); mServiceIntent = new Intent(); mServiceIntent.setComponent( new ComponentName("com.zhuanghongji.startservicefromanotherapp", "com.zhuanghongji.startservicefromanotherapp.AppService")); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_Service: startService(mServiceIntent); break; case R.id.btn_stop_Service: stopService(mServiceIntent); break; } }}
分别点击两个按钮同样可以看到输出的日志:
我们也可以在Service中重写 onStartCommand() 来接收其他应用传递过来的数据。
@Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); // 做你想做的事 }
三、跨应用绑定Service
1. 创建AIDL文件
右键app包名新建.aidl文件:
- 自动生成的代码如图中右边所示(IAppServiceRemoteBinder.aidl)。
- 同时也自动新建了个aidl文件夹,.aidl文件就是在这个文件夹下(图中左边)。
Build->Make Project 发现在…debug目录下自动生成了对应的java接口文件
该文件代码如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: F:\\AndroidG\\StartServiceFromAnotherApp\\app\\src\\main\\aidl\\com\\zhuanghongji\\startservicefromanotherapp\\IAppServiceRemoteBinder.aidl */package com.zhuanghongji.startservicefromanotherapp;// Declare any non-default types here with import statementspublic interface IAppServiceRemoteBinder extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder { private static final java.lang.String DESCRIPTOR = "com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder interface, * generating a proxy if needed. */ public static com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder))) { return ((com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder) iin); } return new com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0 != data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.zhuanghongji.startservicefromanotherapp.IAppServiceRemoteBinder { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean) ? (1) : (0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;}/*Stub对象是在被调用端进程,也就是服务端进程 */
在Service中重写onBind()方法:
@Override public IBinder onBind(Intent intent) { return new IAppServiceRemoteBinder.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { // .... } }; }
这时重写AnotherApp中的MainActivity:
public class MainActivity extends AppCompatActivity implements OnClickListener, ServiceConnection { private Intent mServiceIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_start_Service).setOnClickListener(this); findViewById(R.id.btn_stop_Service).setOnClickListener(this); findViewById(R.id.btn_bind_Service).setOnClickListener(this); findViewById(R.id.btn_unbind_Service).setOnClickListener(this); mServiceIntent = new Intent(); mServiceIntent.setComponent(new ComponentName("com.zhuanghongji.startservicefromanotherapp", "com.zhuanghongji.startservicefromanotherapp.AppService")); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_Service: startService(mServiceIntent); break; case R.id.btn_stop_Service: stopService(mServiceIntent); break; case R.id.btn_bind_Service: bindService(mServiceIntent, this, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbind_Service: unbindService(this); break; } } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("TAG", "Bind Service : " + service); } @Override public void onServiceDisconnected(ComponentName name) { }}
重新安装后,点击“绑定外部服务”
会看到如下日志:
四、跨应用绑定Service并通信
- 在app 中的IAppServiceRemoteBinder增加接口方法:
void setData(String data);
- 复制该文件的包名
com.zhuanghongji.startservicefromanotherapp
- 在AnotherApp中新建一个
AIDL Folder
,再在里面新建一个包(包名是刚才复制的包名,否则会编译错误)。 - 将
IAppServiceRemoteBinder.aidl
文件整个复制到刚才新建的包下。
// IAppServiceRemoteBinder.aidlpackage com.zhuanghongji.startservicefromanotherapp;// Declare any non-default types here with import statementsinterface IAppServiceRemoteBinder { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); void setData(String data);}
Build -> ReBuild Project 后在AppService中的onBind(Intent intent)中实现void setData(String data);
package com.zhuanghongji.startservicefromanotherapp;public class AppService extends Service { private String mData = "默认数据"; private boolean isRunning = false; public AppService() { } @Override public void onCreate() { super.onCreate(); Log.i("TAG", "AppService onCreate"); new Thread(new Runnable() { @Override public void run() { isRunning = true; while (isRunning) { Log.i("TAG", mData); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } @Override public void onDestroy() { super.onDestroy(); Log.i("TAG", "AppService onDestroy"); isRunning = false; } @Override public IBinder onBind(Intent intent) { return new IAppServiceRemoteBinder.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { // .... } @Override public void setData(String data) throws RemoteException { mData = data; } }; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); // 做你想做的事 }}
此时务必要在App的MainActivity中注释掉 startService
和 stopService
。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);// startService(new Intent(this, AppService.class)); } @Override protected void onDestroy() { super.onDestroy();// stopService(new Intent(this, AppService.class)); }}
分别运行app和anotherApp后点击“绑定外部服务”后会发现日志每隔一秒打印出“默认数据”。
点击“同步按钮”后变成打印“这是另一个应用中的数据”。
至此就实现了跨进程间的通信。
下面给出anotherApp的主布局及其xml代码:
<?xml version="1.0" encoding="utf-8"?><LinearLayout 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:orientation="vertical" 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=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!"/> <Button android:id="@+id/btn_start_Service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="启动服务"/> <Button android:id="@+id/btn_stop_Service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止服务"/> <Button android:id="@+id/btn_bind_Service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="绑定外部服务"/> <Button android:id="@+id/btn_unbind_Service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="解除绑定外部服务"/> <EditText android:id="@+id/edit_text" android:text="这是另一个应用中的数据" android:layout_width="match_parent" android:layout_height="wrap_content"/> <Button android:id="@+id/btn_sync_data" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="同步按钮"/></LinearLayout>
- Android AIDL:跨进程调用Service (AIDL Service)
- android跨进程调用Service(AIDL服务)
- Android AIDL跨进程调用Service
- Android:跨进程调用Services(AIDL Service)
- 跨进程调用service(AIDL)
- 跨进程调用Service(AIDL Service)
- 跨进程调用 Service(AIDL Service)
- 跨进程调用Service(AIDL Service)
- Android---44---使用AIDL Service 实现跨进程调用Service
- 跨进程调用Service(AIDL服务)
- 跨进程调用Service(AIDL服务)
- 跨进程调用Service(AIDL 服务)
- AIDL Service,跨进程调用Services
- AIDL跨进程通信和Service调用
- android api分析23 跨进程调用Service AIDL
- Android学习笔记----跨进程调用Service(AIDL)
- Android基本功:跨进程调用Services(AIDL Service)
- android 跨进程访问service方法(AIDL)
- 关于Android 中 Bitmap 内存回收的一点心得
- 第十二周项目三~~图的遍历
- VC 6.0调试方法
- 关于c++编程的一些小小易错点
- 【NOIP2015】D2-T1跳石头,二分答案
- Android AIDL:跨进程调用Service (AIDL Service)
- 雨天+图书馆+一个人——忍不住记录一下最近
- Oracle函数
- maven学习2——pom.xml详解
- ls ,tree,用法简单命令;alias别名用法(临时设置和永久设置)
- Java读取文件MD5的两种方案
- NYOJ-20 吝啬的国度
- P问题、NP问题、NPC问题以及NP-hard问题理解与区分
- 单片机学习之硬件基础知识学习