前言
在Android跨进程通信的方式有很多比如广播,ContentProvider,AIDL等等,它们各自有各自的使用范围。而且AIDL更像是Java的ServerSocket通信机制, 需要一个常驻的服务端与调用它的客户端。AIDL现在的缺点可能也是需要一个服务配合使用。因为目前Android端Server的使用要求越来越多(前台化),使用场景也越来越少(WorkManager替代)。 AIDL更多的是在开发设备应用与系统开发中使用。切记不可随便选择AIDL技术。这样只会给你的项目带来混乱与大量强入侵性的代码。
简单实现Demo
服务端
创建AIDL
创建
完成后,在这个默认文件里会有一些默认方法,它告诉你了AIDL可以使用那些类型数据
编辑AIDL文件
编辑完成后,ReBuild 重新编译下整个项目,Android stuido会自动在debug里生成一份对应的aidl的java接口类
package com.zh.aidl; interface IDemoService { void setNum(int num); int getNum(); }
自动生成的java接口
创建服务,将服务绑定AIDL
注册清单
<!-- android:enabled="true" 与 android:exported="true" 是必要属性 --> <!-- android:enabled 定义服务能否被系统实例化的标签,true表示可以实例化,false不能实例化,默认为true。标签也有enabled标签,这个标签适用于application下所有组件。 只有当和下enabled标签的属性都为true的时候,才可以将广播接受者启动(enabled),否则广播接受者不能开启(disabled),不能被实例化。 --> <!-- android:exported 定义服务能否被外部应用的组件调用或者交互,true表示可以,false表示不能。 如果设置为false,服务只能接收本应用的组件或者是具有相同用户ID的应用所发出的所开启或绑定。 --> <service android:name=".DemoService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="DemoService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> </application>
服务
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; public class DemoService extends Service { private static final String CHANNEL_ID = "DemoService"; private int mNum = 0; @Nullable @Override public IBinder onBind(Intent intent) { //绑定AIDL return iBinder; } /** * 实例化AIDL */ private IBinder iBinder = new IDemoService.Stub() { @Override public void setNum(int num) throws RemoteException { mNum = num; Log.e("zh", "服务器端接收数据: Num = " + num); } @Override public int getNum() throws RemoteException { return mNum; } }; @Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { frontDeskService(); } } /** * 前台服务 */ @RequiresApi(api = Build.VERSION_CODES.O) private void frontDeskService() { NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "主服务", NotificationManager.IMPORTANCE_HIGH); channel.enableLights(true);//设置提示灯 channel.setLightColor(Color.RED);//设置提示灯颜色 channel.setShowBadge(true);//显示logo channel.setDescription("zh");//设置描述 channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); //设置锁屏可见 VISIBILITY_PUBLIC=可见 manager.createNotificationChannel(channel); Notification notification = new Notification.Builder(this) .setChannelId(CHANNEL_ID) .setContentTitle("主服务")//标题 .setContentText("运行中...")//内容 .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher)//小图标一定需要设置,否则会报错(如果不设置它启动服务前台化不会报错,但是你会发现这个通知不会启动),如果是普通通知,不设置必然报错 .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) .build(); startForeground(1, notification); } }
启动服务
private fun startService() { val intent = Intent(this, DemoService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent) } else{ startService(intent) } }
客户端
将服务端的AIDL文件复制到客户端里,注意包名路径要一致
绑定服务,接收数据,发送数据
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(mBinding.root) mBinding.connectService.setOnClickListener { //绑定服务 val intent = Intent().apply { setPackage("com.zh.aidl") setAction("DemoService") } bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE) } mBinding.sendValue.setOnClickListener { //发送数据 mIDemoService?.num = mBinding.editTextNumber.text.toString().toInt() } mBinding.getValue.setOnClickListener { //接收数据 Log.e("zh", "客户端接收: num = " + mIDemoService?.num) } }
自定义数据
服务端
目录结构
创建自定义Bean
UserBean数据需要添加序列化
在服务接口里引入UserBean,在参数前面需要添加 in 关键字。不添加会报错
其他绑定服务跟上面的demo是一样的
客户端
与上面的Demo一样需要把服务端的AIDL文件复制到客户端项目里,这里的UserBean一样有路径保持一致的要求,并且也是需要序列化的。
其他步骤与上面的Demo一致
End