之前在 Eclipse 上开发 Android 项目已经习惯了,突然切换到 Android Studio,总会遇到各种不适应。比如用 AIDL 实现远程服务(即 RPC 机制),在 Android Studio 中的开发方式与 Eclipse 中有很大区别。如果服务端和客户端位于同一个项目中,处理起来相对简单;但分属不同项目时,难度就会显著增加。特别是从 Android 5.0 开始,禁止隐式启动服务,这让很多开发者感到不习惯。因此,这里将简要介绍如何在 Android Studio 中通过 AIDL 创建远程服务的示例,涵盖 Android 4.4 和 Android 5.1 的开发场景。这有助于理解新环境下的实现方式以及适配不同版本的要求。
1、 创建一个新的aidl项目,并在其中添加一个名为IMyService.aidl的文件,创建步骤可参考链接:http://jingyan.baidu.com/article/6f2f55a15d53c9b5b93e6ca1.html。接着,在IMyService.aidl文件中定义方法int add(int value1, int value2);以下是具体代码内容:随后按照规范完成相关配置与实现,确保方法能够正常调用并返回两个整数相加的结果。此过程需仔细操作以避免语法错误。
2、 // IMyService.aidl
3、 package com.example.aidl;
4、 // 在此处通过 import 语句声明非默认类型
5、 interface IMyService {
6、 /
7、 * 展示了一些可以在 AIDL 中用作参数和返回值的基本数据类型。
8、 */
9、 // 定义 AIDL 接口方法,调用此 AIDL 服务的客户端需要使用该方法进行操作
10、 int add(int value1, int value2);
11、 }
12、 说明:上述代码定义了一个名为 IMyService 的 AIDL 接口。它包含一个名为 add 的方法,用于接收两个整型参数(value1 和 value2),并返回它们的和。在实际使用中,该接口允许跨进程通信(IPC),使其他应用程序或进程能够调用此方法以完成加法运算。如果需要使用非默认的数据类型,可以通过 import 语句引入相应的类或类型。此接口为开发者提供了一种简单的方式来实现 Android 系统中的远程过程调用(RPC)。
13、 编译后会自动生成一个对应的Java文件ImyService。这个aidl文件的位置在哪里?就像很多人在Android Studio中找不到R文件一样,可以通过以下方法查找:点击左上角的Packages,然后找到项目名称并展开,就能看到相关文件了。

14、 创建MyService类以提供服务功能。其中,onBind方法需返回一个实现IMyService接口的类,比如通过MyServiceImpl类实现aidl接口中的add方法。以下是具体代码示例:
15、 服务的全部代码如下:
16、 在 Android 开发中,为了实现跨进程通信(IPC),可以使用 AIDL(Android 接口定义语言)。下面是一个简单的服务类示例,用于展示如何通过 AIDL 实现远程方法调用。
17、 java
18、 package com.example.aidl;
19、 import android.app.Service;
20、 import android.content.Intent;
21、 import android.os.IBinder;
22、 import android.os.RemoteException;
23、 import android.support.annotation.Nullable;
24、 /
25、 * 该服务类用于处理通过 AIDL 定义的接口进行的远程调用。
26、 * 创建者:管理员,日期:2015年8月12日
27、 */
28、 public class MyService extends Service {
29、 // 内部类,继承自 AIDL 生成的 Stub 类,实现具体的接口方法
30、 private static class MyServiceImpl extends IMyService.Stub {
31、 @Override
32、 public int add(int value1, int value2) throws RemoteException {
33、 // 实现加法逻辑并返回结果
34、 return value1 + value2;
35、 }
36、 }
37、 // 当其他组件绑定到该服务时,返回一个 IBinder 对象
38、 @Override
39、 public IBinder onBind(Intent intent) {
40、 // 返回实现了 AIDL 接口的对象实例
41、 return new MyServiceImpl();
42、 }
43、 }
44、 功能说明
45、 1. AIDL 接口:通过 AIDL 文件定义了一个名为 `IMyService` 的接口,其中包含一个 `add` 方法,用于计算两个整数的和。
46、 2. 服务类:`MyService` 是一个继承自 `Service` 的类,专门用于处理远程调用请求。
47、 3. Stub 类:`IMyService.Stub` 是由 AIDL 自动生成的抽象类,开发者需要继承它并实现具体的方法逻辑。
48、 4. 绑定机制:当客户端组件调用 `bindService` 方法时,系统会调用 `onBind` 方法,并返回一个实现了 AIDL 接口的 `IBinder` 对象。这样,客户端就可以通过该对象调用远程方法。
49、 此代码片段展示了如何通过 AIDL 实现基本的跨进程通信功能,适合用于学习和理解 AIDL 的工作机制。
50、 在Activity中启动服务时,注意Android 5.0及以上版本不能隐式启动服务,必须显式启动,否则会出错。
51、 在Android开发中,实现跨进程通信(IPC)是一项重要的功能,而AIDL(Android Interface Definition Language)是完成这一任务的常见方式。下面通过一个示例来展示如何使用AIDL启动远程服务。
52、 首先,在`com.example.aidl`包下创建了一个名为`MainActivity`的活动类,继承自`AppCompatActivity`。该类主要用于初始化界面并启动一个远程服务。以下是代码的具体逻辑:
53、 1. 在`onCreate`方法中,首先调用父类构造函数,并加载布局文件`activity_main`作为主界面。
54、 2. 接着创建了一个`Intent`对象,用于描述要启动的服务。通过设置动作字符串`com.android.MYSERVICE`指定服务类型。
55、 3. 需要注意的是,从Android 5.0开始,系统不再支持隐式启动服务,因此必须通过`setPackage`方法显式指定服务所在的包名,这里设置为`com.example.aidl`。
56、 4. 然后调用`startService(intent)`方法启动服务。
57、 5. 使用`Log.e`记录日志信息,表明服务已启动。
58、 以下是完整代码:
59、 java
60、 package com.example.aidl;
61、 import android.content.Intent;
62、 import android.support.v7.app.AppCompatActivity;
63、 import android.os.Bundle;
64、 import android.util.Log;
65、 public class MainActivity extends AppCompatActivity {
66、 @Override
67、 protected void onCreate(Bundle savedInstanceState) {
68、 super.onCreate(savedInstanceState);
69、 // 设置布局文件
70、 setContentView(R.layout.activity_main);
71、 // 创建Intent对象
72、 Intent intent = new Intent();
73、 // 设置动作字符串
74、 intent.setAction(com.android.MYSERVICE);
75、 // Android 5.0以后需要显式指定包名
76、 intent.setPackage(com.example.aidl);
77、 // 启动服务
78、 startService(intent);
79、 // 记录日志
80、 Log.e(MainActivity, server start);
81、 }
82、 }
83、 上述代码展示了如何通过`Intent`启动一个远程服务,并结合AIDL实现跨进程通信。同时,代码还考虑了Android版本兼容性问题,确保在较高版本系统中也能正常运行。
84、 需在Manifest中声明该服务:
85、 运行此项目后,控制台会显示server start,至此服务端启动成功。
86、 创建名为aidlclient的新项目作为客户端,添加一个aidl文件,并将服务端aidl文件的内容复制过去(也可直接拷贝服务端aidl文件),确保包名相同。在布局文件中配置了一个textview和两个button。接下来,先完成服务的连接与断开功能的实现。
87、 在实现服务连接的过程中,我们需要定义一个 `IMyService` 接口类型的变量 `iMyService`,用于与远程服务进行交互。同时,为了管理服务的连接状态,还需要创建一个 `ServiceConnection` 对象 `mConn`,该对象会监听服务连接的变化。
88、 具体实现如下:首先声明一个 `IMyService` 类型的变量 `iMyService` 用于保存服务接口实例。接着定义一个私有的 `ServiceConnection` 对象 `mConn`,并重写其两个核心方法:`onServiceConnected` 和 `onServiceDisconnected`。
89、 当服务成功连接时,`onServiceConnected` 方法会被触发。在这个方法中,首先记录日志信息以标记服务连接开始,使用 `Log.e(MainActivity, connect service start)` 输出日志内容。随后,通过调用 `IMyService.Stub.asInterface(service)` 将传入的 `IBinder` 对象转换为具体的 `IMyService` 接口实例,并将其赋值给 `iMyService` 变量。最后再次记录日志信息,表明服务连接完成,即 `Log.e(MainActivity, connect service)`。
90、 而当服务断开连接时,`onServiceDisconnected` 方法会被触发。此时记录日志信息,输出 `Log.e(MainActivity, disconnect service)` 标记服务断开事件,同时将 `iMyService` 设置为 `null`,以确保后续不会出现误操作或空指针异常。这种设计能够有效管理服务连接状态,确保程序运行的稳定性。
91、 接着,点击 button1 以连接服务:
92、 创建一个 Intent 对象,并设置其动作为 com.android.MYSERVICE。由于 Android 5.0 及以上版本不再支持通过隐式 Intent 启动 Service,因此需要指定包名。这里设置的包名需与 AIDL 文件所属的包名相同,即 com.example.aidl。通过调用 intent.setPackage 方法完成包名设定后,使用 bindService 方法绑定服务,传入参数包括构建好的 Intent、连接对象 mConn 以及绑定标志 Context.BIND_AUTO_CREATE,从而实现与远程服务的绑定操作。
93、 最后调用服务方法即可完成操作。
94、 代码详情如下:
95、 顺便附上客户端的布局文件:
96、 附上服务端与客户端的结构图:

