android 系统中,每个应用程序之间的内存是无法共享内存的。我们要实现在不同的应用程序之间交互数据,这种可以跨进程通信的服务叫AIDL。
AIDL作用很大,但并不是所有情况下都是最好的跨进程通信方案,那么什么场景下才适合使用呢?对此,官方给出的解释是:“只有当你允许来自不同应用程序的客户端远程访问你的服务并且在你的服务中处理多线程的情况下才使用AIDL;如果不需要跨应用程序实现并发进程间通信的话,那么你应该使用Binder接口;如果只是进程间通信,但不许处理多线程,那么使用Messenger
1、首先我们新建立一个项目,然后创建一个aidl文件,如下图
下面是创建好的aidl
我们打开aidl添加一个接口,如图下所显示,这个aidl文件每次修改或首次创建,都要进行Rebuild project ,在JAVA代码中才可以使用
2、我们来创建一个服务,代码如下
package com.nyw.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service{
public final String TAG = "log_info";
//client 可以通过Binder获取Service实例
public class MyBinder extends IMyAidlInterface.Stub{
public MyService getService() {
return MyService.this;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getInfo(String msg) throws RemoteException {
//aidl文件中自定义的接口,在这里可以收到其他APP发过来的信息,下面我们打印出来,往下看我们在创建一个新项目APP来发数据到这个APP里来,在这里可以接收到数据并打印日志出来
Log.i(TAG,"getInfo");
Log.i(TAG,msg);
return "我是服务端AIDL"+msg;
}
}
//通过binder实现调用者client与Service之间的通信
public MyBinder binder = new MyBinder();
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
//服务第一次启动执行,可以在这里做初始化业务代码操作。在次启动服务只会执行onStartCommand
Log.i(TAG,"onCreate");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//抽象方法,仅启动服务是bindService的时候生效,activity中我们调用了bindService()后,会回调onBind()方法
Log.i(TAG,"onBind");
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//每次服务启动都执行,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等
Log.i(TAG,"onStartCommand");
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
//服务停止会执行
Log.i(TAG,"onDestroy");
}
//getMsg是Service暴露出去供client调用的公共方法,这里的client是指其他页面的activityt等
public String getMsg() {
String msg="Service暴露出去供client调用的公共方法";
return msg;
}
}
需要在AndroidManifest里添加服务注册
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.nyw.aidldemo"/>
</intent-filter>
</service>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nyw.aidldemo">
<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/Theme.AIDLDemo">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.nyw.aidldemo"/>
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
接下来我们看activity代码如下
package com.nyw.aidldemo;
import androidx.appcompat.app.AppCompatActivity;
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 android.widget.Toast;
/**
* 测试服务打开关闭及跨进程通信
*/
public class MainActivity extends AppCompatActivity {
private boolean isBind = false;
private TextView tv_data;
private String fromMsg=null;
private MyService myService=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_openServer).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//打开服务
//方法一
// Intent startIntent = new Intent(MainActivity.this, MyService.class);
// startService(startIntent);
//方法二
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startIntent.putExtra("from", "Activity");
bindService(startIntent, conn, BIND_AUTO_CREATE);
}
});
findViewById(R.id.btn_closeServer).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//关闭服务
//方法一
// Intent stopIntent = new Intent(MainActivity.this,MyService.class);
// stopService(stopIntent);
//方法二
if(isBind==true) {
unbindService(conn);
}
}
});
myService=new MyService();
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//开始连接绑定
isBind = true;
IMyAidlInterface myBinder = IMyAidlInterface.Stub.asInterface(binder) ;
try {
myBinder.getInfo("服务端程序");
} catch (RemoteException e) {
e.printStackTrace();
}
Log.i("log_info", "Activity - onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
//绑定失败
isBind = false;
Log.i("log_info", "Activity - onServiceDisconnected");
}
};
}
3、我们建立新项目,安装另一个APP到手机上,如下操作。
创建 aidl folder
然后创建一个包,这个包名要和要访问的APP那里aidl包名一致,否则无法通信,无法绑定其他APP服务或无法发数据给其他APP。这里指aidl包名,不是项目代码包名。每次修改AIDL文件,都要做Rebuild Project才能使用。
同样这个APP项目也需要一个服务,创建一个服务,代码如下
package com.nyw.aidlclientdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.nyw.aidldemo.IMyAidlInterface;
public class MyService extends Service{
public final String TAG = "log_info";
private IBinder binder = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getInfo(String msg) throws RemoteException {
//aidl文件中自定义的接口
Log.i(TAG,"getInfo");
msg="223666";
Log.i(TAG,msg);
return "我是客户端的AIDL"+msg;
}
};
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
//服务第一次启动执行,可以在这里做初始化业务代码操作。在次启动服务只会执行onStartCommand
Log.i(TAG,"onCreate");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//抽象方法,仅启动服务是bindService的时候生效,activity中我们调用了bindService()后,会回调onBind()方法
Log.i(TAG,"onBind");
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//每次服务启动都执行,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等
Log.i(TAG,"onStartCommand");
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
//服务停止会执行
Log.i(TAG,"onDestroy");
}
//getMsg是Service暴露出去供client调用的公共方法
public String getMsg() {
String msg="Service暴露出去供client调用的公共方法";
return msg;
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nyw.aidlclientdemo">
<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/Theme.AidlClientDemo">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.nyw.aidldemo"/>
</intent-filter>
</service>
</application>
</manifest>
我们在看下activity里的代码,点击这个项目中的按钮,可以发数据给另一个APP
package com.nyw.aidlclientdemo;
import androidx.appcompat.app.AppCompatActivity;
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 android.widget.Toast;
import com.nyw.aidldemo.IMyAidlInterface;
public class MainActivity extends AppCompatActivity {
private MyService myService=null;
IMyAidlInterface iMyAidlInterface=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startAndBindService();
findViewById(R.id.btn_get_msg).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Toast.makeText(MainActivity.this,iMyAidlInterface.getInfo("77777777777777"),Toast.LENGTH_LONG).show();
// Log.i("log_info",iMyAidlInterface.getInfo(""));
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
IMyAidlInterface myBinder = (IMyAidlInterface) binder;
iMyAidlInterface=IMyAidlInterface.Stub.asInterface(binder);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("log_info","链接Service失败");
}
};
private void startAndBindService(){
Intent service = new Intent(MainActivity.this, MyService.class);
bindService(service,serviceConnection, Context.BIND_AUTO_CREATE);
}
}
最后我们运行安装APP到手机里,点击按钮,发送数据给另一个APP,另一个APP日志打印消息出来,如下效果
代码下载链接
android_service_and_aidl_server_client.zip-Android文档类资源-CSDN下载