Android
远程服务的制作与测试运行,AIDL服务。Android API = 29
即 Android 10
,开发IDE是 Android Studio
网上搜了N多文章,要么年代久远,要么开发IDE不同操作不懂(小白搞不懂。。),本文以最详细的步骤实现最简的 AIDL 远程服务的制作和调用。
概述
在 Android Studio
中创建了空的工程(其实后来没用到,不过为了配合源码还是要说下),创建模块 rsserver
- 由于 Android Studio
和 IDEA
一个德行的,这里只能叫它模块了 - 英文名是 module
吗。本模块用来制作一个服务可以在本模块的 activity
中调用,可以提供给其他 app
或者模块使用,再创建一个客户端模块 rsclient
- 这里的 rs
表示 remote service
。那么最终形成的结构如下图:
后面的步骤为先制作服务端模块中的服务并且测试通过后再制作客户端模块,让我们开始吧。
制作 AIDL
接口文件,在服务端模块的根节点上通过右键菜单创建一个AIDL
文件
将其命名为 IProcessInfo
,其中只要定义一个方法不用实现,全部代码如下(创建完毕后会有一个默认的方法,将其删除掉,然后追加一个我们自己的方法)
// IProcessInfo.aidl
package com.ccsoft.rsserver;
// Declare any non-default types here with import statements
interface IProcessInfo {
int getProcessId();
}
实现 AIDL
文件中定义的方法
在项目包 com.ccsoft.rsserver
下创建包 service
再在其下创建服务 IProcessInfoImpl
继承自 IProcessInfo.Stub
,其全部代码如下
package com.ccsoft.rsserver.service;
import android.os.RemoteException;
import com.ccsoft.rsserver.IProcessInfo;
public class IProcessInfoImpl extends IProcessInfo.Stub {
@Override
public int getProcessId() throws RemoteException {
return android.os.Process.myPid();
}
}
创建服务,用来返回实现接口的类的实例,其全部代码如下:
package com.ccsoft.rsserver.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyRemoteService extends Service {
private static final String TAG = "chanchaw";
IProcessInfoImpl mProcessInfo = new IProcessInfoImpl();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "MyRemoteService thread id = " + Thread.currentThread().getId());
return mProcessInfo;
}
}
接下来为服务端创建一个 Activity
用来测试服务是否可用,先创建布局文件 activity_main
,其全部代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定本地服务"
android:onClick="bindLocalService" />
LinearLayout>
创建一个 Activity
显示该布局并且测试服务,命名为 MainActivity
,其全部代码如下:
package com.ccsoft.rsserver;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import com.ccsoft.rsserver.service.MyRemoteService;
public class MainActivity extends Activity {
// 打印日志时用来过滤,快速找到调试信息
private static final String TAG = "chanchaw";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 关联到 res/layout/activity_main.xml,会显示其中定义的控件
setContentView(R.layout.activity_main);
}
// 创建 ServiceConnection 类型的对象实例,在后面绑定服务时会用到
ServiceConnection myServiceConnection = new ServiceConnection() {
/**
* 服务绑定成功后会调用本方法
* @param name
* @param service
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "MyRemoteService onServiceConnected");
// 通过aidl取出数据
IProcessInfo processInfo = IProcessInfo.Stub.asInterface(service);
try {
Log.i(TAG, "MyRemoteService process id = " + processInfo.getProcessId());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MyRemoteService onServiceDisconnected");
}
};
public void bindLocalService(View v){
Intent intent = new Intent(this, MyRemoteService.class);
bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(myServiceConnection);
}
}
在模块清单文件 AndroidManifest.xml
中注册Activity
和服务,其全部代码如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ccsoft.rsserver">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" android:label="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<service android:name=".service.MyRemoteService" android:process=":remote">
<intent-filter>
<action android:name="com.jxx.server.service.bind" />
<category android:name="android.intent.category.DEFAULT" />
intent-filter>
service>
application>
manifest>
客户端模块中创建 activity
的布局文件,其全部代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/rsclient_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="rsclient_textview" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定远程服务"
android:onClick="bindRemoteService" />
LinearLayout>
创建 Activity
,全部代码如下
package com.ccsoft.rsclient;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.ccsoft.rsserver.IProcessInfo;
public class MainActivity extends Activity {
private static final String TAG = "chanchaw";
TextView text = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.rsclient_textview);
}
// 绑定远程服务
public void bindRemoteService(View v){
Intent intent = new Intent();
intent.setAction("com.jxx.server.service.bind");//Service的action
intent.setPackage("com.ccsoft.rsserver");//App A的包名
bindService(intent, mServerServiceConnection, BIND_AUTO_CREATE);
}
ServiceConnection mServerServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "MyRemoteService onServiceConnected");
// 通过aidl取出数据
IProcessInfo processInfo = IProcessInfo.Stub.asInterface(service);
try {
Log.i(TAG, "MyRemoteService process id = " + processInfo.getProcessId());
text.setText("绑定成功!");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MyRemoteService onServiceDisconnected");
}
};
}
清单文件中注册 Activity
,全部代码如下
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ccsoft.rsclient">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" android:label="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
application>
manifest>
这里不用注册远程的服务,因为是远程调用的
源码地址:https://gitee.com/chanchaw/rsdemo