中间件的核心思想
中间件的核心思想是提供一种通用的接口和服务,将底层系统的复杂性进行抽象,使应用程序更容易调用和使用系统资源。它充当了应用程序和操作系统之间的桥梁,使得应用程序不必直接处理底层细节,而是通过中间件提供的接口来访问系统功能。
中间件的优势
-
简化开发
-
从复杂的应用程序中抽象出通用的公共部分,从而降低应用开发的复杂度。
-
-
易于扩展
-
中间件可以通过添加新的模块或更新现有模块来实现系统功能的扩展和升级,而不影响应用程序的正常运行。
-
-
提高可维护性
-
中间件模块的独立性使得对特定功能的修改、升级和维护更加容易。应用程序可以保持不变,只需更新中间件模块即可。
-
-
抽象底层复杂性
-
中间件提供了一个抽象层,隐藏了底层系统和硬件的复杂性。应用程序能够更专注于业务逻辑而不用过多关心底层实现。
-
-
跨平台适用性:
-
中间件提供了统一的接口,应用程序可以跨不同硬件和系统版本使用相同的调用方式,根据业务需求在对应的Android设备上运行,而无需修改代码。 提高应用程序的可移植性。
-
Android 12 开发项目结构图
中间件应用架构的组成
-
在
Manager/src/main/aidl
目录中,在对应目录下对AIDL
接口进行定义接口。而IService.aidl
文件则是定义了获取各个中间件模块实例的方法,包括音频、网络、图片、信源、系统和事件模块。 -
在
Manager/src/main/java
目录中,在对应目录下对各个目录中AIDL
接口进行初始化,资源分配等操作。而Manager
类是一个单例类,通过getInstance()
方法获取各个目录的唯一实例。 -
在
app/src/main/java
目录中,Service
类是一个 Android 服务(Service),用于提供中间件模块的绑定和管理。而在对应目录下的Binder则是对服务进行实现
中间件应用架构实现示例
-
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(); }
-
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; } } }
-
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; } }
-
Manager/aidl
目录下的IService
文件获取各个中间件模块实例的方法interface IService { IAudio getAudio(); INetWork getNetWork(); IPicture getPicture(); ISource getSource(); ISystem getSystem(); IEvent getEvent(); }
-
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; } }
-
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 流程图
数据流程
-
App 向中间件请求数据:
-
App
通过Manager
获取中间件的实例。 -
通过中间件实例调用相应的接口方法,例如
getAudio()
、getNetWork()
等。
-
-
中间件处理请求:
-
中间件收到请求后,根据请求的类型,创建相应的中间件模块实例(例如,
AudioBinder
、NetBinder
)。 -
调用中间件模块的相应方法,处理具体的功能逻辑,例如获取音频信息、网络状态等。
-
-
中间件向系统请求数据:
-
中间件可能需要向系统请求底层数据,例如通过
HitvManager
获取 TV 的音频信息。
-
-
系统返回数据给中间件:
-
系统接收到中间件的请求,执行相应的系统功能,例如获取 TV 的音频信息。
-
系统将获取的数据返回给中间件。
-
-
中间件处理系统返回的数据:
-
中间件收到系统返回的数据,进行相应的处理和加工,确保符合中间件的接口规范。
-
-
中间件返回数据给 App:
-
中间件将处理后的数据返回给
App
,App
进一步处理或显示这些数据。
-