• Android 跨进程通信之AIDL


    前言

      在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

  • 相关阅读:
    ZOJ 2587 Unique Attack (最小割唯一性)
    POJ 2987 Firing (最大权闭合图)
    POJ 2987 Firing (最大权闭合图)
    POJ 3469 Dual Core CPU (最小割建模)
    POJ 3469 Dual Core CPU (最小割建模)
    UVA 11426 GCD-Extreme(II) ★ (欧拉函数)
    UVA 11426 GCD-Extreme(II) ★ (欧拉函数)
    HDU 4612 Warm up (边双连通分量+DP最长链)
    HDU 4612 Warm up (边双连通分量+DP最长链)
    hdu5531 Rebuild
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/16310607.html
Copyright © 2020-2023  润新知