Android 通用中间件

中间件的核心思想

中间件的核心思想是提供一种通用的接口和服务,将底层系统的复杂性进行抽象,使应用程序更容易调用和使用系统资源。它充当了应用程序和操作系统之间的桥梁,使得应用程序不必直接处理底层细节,而是通过中间件提供的接口来访问系统功能。

中间件的优势

  • 简化开发

    • 从复杂的应用程序中抽象出通用的公共部分,从而降低应用开发的复杂度。

  • 易于扩展

    • 中间件可以通过添加新的模块或更新现有模块来实现系统功能的扩展和升级,而不影响应用程序的正常运行。

  • 提高可维护性

    • 中间件模块的独立性使得对特定功能的修改、升级和维护更加容易。应用程序可以保持不变,只需更新中间件模块即可。

  • 抽象底层复杂性

    • 中间件提供了一个抽象层,隐藏了底层系统和硬件的复杂性。应用程序能够更专注于业务逻辑而不用过多关心底层实现。

  • 跨平台适用性:

    • 中间件提供了统一的接口,应用程序可以跨不同硬件和系统版本使用相同的调用方式,根据业务需求在对应的Android设备上运行,而无需修改代码。 提高应用程序的可移植性。

Android 12 开发项目结构图

中间件应用架构的组成

  1. Manager/src/main/aidl目录中,在对应目录下对AIDL接口进行定义接口。而IService.aidl文件则是定义了获取各个中间件模块实例的方法,包括音频、网络、图片、信源、系统和事件模块。

  2. Manager/src/main/java目录中,在对应目录下对各个目录中AIDL接口进行初始化,资源分配等操作。而Manager是一个单例类,通过getInstance()方法获取各个目录的唯一实例。

  3. app/src/main/java目录中,Service 类是一个 Android 服务(Service),用于提供中间件模块的绑定和管理。而在对应目录下的Binder则是对服务进行实现

中间件应用架构实现示例

  1. Manager/aidl目录下的IAudio文件中接口实现

    package com.middleware.manager.audio;
    
    interface IAudio {
        //-Setting the ARC switch
        void setARC(boolean onoff);
        //-Get the volume of the specified type
        int getVolumeType(int audioHelper);
        //-Determine whether ARC is started or not
        boolean isARCEnable();
    
    }
    
  2. Manager/java目录下的AudioManager文件中对接口进行初始化

    public class AudioManager {
        private static final String TAG = "Manager-Audio";
    
        private static IAudio getService() {
            LogHelper.service(TAG);
            if (Manager.getInstance() == null) {
                Log.d(TAG, "getService: getInstance is null ");
                return null;
            }
            return Manager.getInstance().getAudio();
        }
    
        public static void setARC(boolean onoff){
            IAudio service = getService();
            try {
                if(service != null ){
                    service.setARC(onoff);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        public static int getVolumeType(int audioHelper){
            try {
                IAudio service = getService();
                return service == null ? -1 : service.getVolumeType(audioHelper);
            } catch (RemoteException e) {
                e.printStackTrace();
                return -1;
            }
        }
        public static boolean isARCEnable(){
            try {
                IAudio service = getService();
                return service == null ? false : service.isARCEnable();
            } catch (RemoteException e) {
                e.printStackTrace();
                return false;
            }
        }
    }
    ​
        
    

  3. app/src/main/java目录下的AudioBinder文件初始化的接口进行实现

    public class AudioBinder extends IAudio.Stub {
        private static final String TAG = "Audio";
        private Context mContext;
        public AudioBinder(Context context){
            mContext = context;
        }
    
        @Override
        public void setARC(boolean onoff) throws RemoteException {
            HitvManager hitvManager = HitvManager.getInstance();
            if (hitvManager != null) {
                Audio audio = hitvManager.getAudio();
                if (audio != null) {
                    audio.enableARC(onoff);
                    Log.d(TAG, "ARC switched " + (onoff ? "on" : "off"));
                } else {
                    Log.e(TAG, "setARC: Audio is null.");
                }
            } else {
                Log.e(TAG, "setARC: HitvManager is null.");
            }
        }
    
        @Override
        public int getVolumeType(int audioHelper) throws RemoteException {
            HitvManager hitvManager = HitvManager.getInstance();
            if (hitvManager != null) {
                Audio audio = hitvManager.getAudio();
                if (audio != null) {
                  return  audio.getVolume(audioHelper);
                }
            }
            return -1;
        }
    
        @Override
        public boolean isARCEnable() throws RemoteException {
            HitvManager hitvManager = HitvManager.getInstance();
            if (hitvManager != null) {
                Audio audio = hitvManager.getAudio();
                if (audio != null) {
                    return  audio.isARCEnable();
                }
            }
            return false;
        }
    }
    

  4. Manager/aidl目录下的IService文件获取各个中间件模块实例的方法

    interface IService {
        IAudio getAudio();
        INetWork getNetWork();
        IPicture getPicture();
        ISource getSource();
        ISystem getSystem();
        IEvent getEvent();
    }
    

  5. Manager/java目录下的Manager文件获取各个目录的唯一实例

    public class Manager {
        private static final String TAG = "Manager";
    
        private static volatile Manager sInstance = null;
    
        private static IAudio sAudio = null;
    
        private static INetWork sNetWork = null;
    
        private static IPicture sPicture = null;
    
        private static ISource sSource = null;
    
        private static ISystem sSystem = null;
    
        private static IEvent sEvent = null;
    
    
        private static final DeathRecipient sDeathRecipient = () -> {
            sInstance = null;
            sAudio = null;
            sNetWork = null;
            sPicture = null;
            sSource = null;
            sSystem = null;
            sEvent = null;
        };
    
        private final IService mService;
    
        private Manager(IService service) {
            mService = service;
        }
    
        public static Manager getInstance() {
            // Double-checked locking
            if (sInstance == null) {
                synchronized (Manager.class) {
                    if (sInstance == null) {
                        IBinder binder = ServiceManager.getService("kitkingservice");
                        int count = 0;
                        while (binder == null && count < 60) {
                            try {
                                Thread.currentThread().sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            binder = ServiceManager.getService("kitkingservice");
                            count++;
                        }
                        try {
                            if (binder != null) {
                                binder.linkToDeath(sDeathRecipient, 0);
                                sInstance = new Manager(IService.Stub.asInterface(binder));
                            }
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return sInstance;
        }
    
        public IAudio getAudio() {
            if (sAudio == null) {
                try {
                    sAudio = mService.getAudio();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sAudio;
        }
    
        public INetWork getNetWork() {
            if (sNetWork == null) {
                try {
                    sNetWork = mService.getNetWork();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sNetWork;
        }
    
        public IPicture getPicture() {
            if (sPicture == null) {
                try {
                    sPicture = mService.getPicture();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sPicture;
        }
    
        public ISource getSource() {
            if (sSource == null) {
                try {
                    sSource = mService.getSource();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sSource;
        }
    
        public ISystem getSystem() {
            if (sSystem == null) {
                try {
                    sSystem = mService.getSystem();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sSystem;
        }
    
        public IEvent getEvent() {
            if (sEvent == null) {
                try {
                    sEvent = mService.getEvent();
                } catch (RemoteException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return sEvent;
        }
    }
    
  6. app/src/main/java目录下的Service文件对中间件模块的绑定和管理

    public class Service extends Service {
        private static final String TAG = "Service";
    
        public Context context;
    
        private AudioBinder mAudioBinder = null;
    
        private PictureBinder mPictureBinder = null;
    
    
        private NetBinder mNetWorkBinder = null;
    
        private SourceBinder mSourceBinder = null;
    
        private SystemBinder mSystemBinder = null;
    
        private EventBinder mEventBinder = null;
    
        private final IService.Stub mBinder = new IService.Stub() {
    
            @Override
            public synchronized IAudio getAudio() {
                if (mAudioBinder == null) {
                    mAudioBinder = new AudioBinder(getApplicationContext());
                }
                return mAudioBinder;
            }
    
            @Override
            public synchronized INetWork getNetWork() {
                if (mNetWorkBinder == null) {
                    mNetWorkBinder = new NetBinder(getApplicationContext());
                }
                return mNetWorkBinder;
            }
    
            @Override
            public synchronized IPicture getPicture() {
                if (mPictureBinder == null) {
                    mPictureBinder = new PictureBinder(getApplicationContext());
                }
                return mPictureBinder;
            }
    
            @Override
            public synchronized ISource getSource() {
                if (mSourceBinder == null) {
                    mSourceBinder = new SourceBinder(getApplicationContext());
                }
                return mSourceBinder;
            }
    
            @Override
            public synchronized ISystem getSystem() {
                if (mSystemBinder == null) {
                    mSystemBinder = new SystemBinder(getApplicationContext());
                }
                return mSystemBinder;
            }
    
            @Override
            public synchronized IEvent getEvent() {
                if (mEventBinder == null) {
                    mEventBinder = new EventBinder(getApplicationContext());
                }
                return mEventBinder;
            }
        };
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            context = getApplicationContext();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            ServiceManager.addService("kitkingservice", mBinder);
            return START_STICKY;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            return super.onUnbind(intent);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    }
    

UML 流程图

数据流程

  1. App 向中间件请求数据:

    • App通过 Manager 获取中间件的实例。

    • 通过中间件实例调用相应的接口方法,例如 getAudio()getNetWork() 等。

  2. 中间件处理请求:

    • 中间件收到请求后,根据请求的类型,创建相应的中间件模块实例(例如,AudioBinderNetBinder)。

    • 调用中间件模块的相应方法,处理具体的功能逻辑,例如获取音频信息、网络状态等。

  3. 中间件向系统请求数据:

    • 中间件可能需要向系统请求底层数据,例如通过 HitvManager 获取 TV 的音频信息。

  4. 系统返回数据给中间件:

    • 系统接收到中间件的请求,执行相应的系统功能,例如获取 TV 的音频信息。

    • 系统将获取的数据返回给中间件。

  5. 中间件处理系统返回的数据:

    • 中间件收到系统返回的数据,进行相应的处理和加工,确保符合中间件的接口规范。

  6. 中间件返回数据给 App:

    • 中间件将处理后的数据返回给AppApp 进一步处理或显示这些数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我中意你呀丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值