日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android插件化原理解析——广播的管理

發(fā)布時(shí)間:2025/3/15 Android 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android插件化原理解析——广播的管理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在Activity生命周期管理?以及?插件加載機(jī)制?中我們詳細(xì)講述了插件化過程中對于Activity組件的處理方式,為了實(shí)現(xiàn)Activity的插件化我們付出了相當(dāng)多的努力;那么Android系統(tǒng)的其他組件,比如BroadcastReceiver,Service還有ContentProvider,它們又該如何處理呢?

相比Activity,BroadcastReceiver要簡單很多——廣播的生命周期相當(dāng)簡單;如果希望插件能夠支持廣播,這意味著什么?

回想一下我們?nèi)粘i_發(fā)的時(shí)候是如何使用BroadcastReceiver的:注冊,?發(fā)送接收;因此,要實(shí)現(xiàn)BroadcastReceiver的插件化就這三種操作提供支持;接下來我們將一步步完成這個(gè)過程。

閱讀本文之前,可以先clone一份?understand-plugin-framework,參考此項(xiàng)目的receiver-management?模塊。另外,插件框架原理解析系列文章見索引。

如果連BroadcastReceiver的工作原理都不清楚,又怎么能讓插件支持它?老規(guī)矩,知己知彼。

源碼分析

我們可以注冊一個(gè)BroadcastReceiver然后接收我們感興趣的廣播,也可以給某有緣人發(fā)出某個(gè)廣播;因此,我們對源碼的分析按照兩條路線展開:

注冊過程

不論是靜態(tài)廣播還是動(dòng)態(tài)廣播,在使用之前都是需要注冊的;動(dòng)態(tài)廣播的注冊需要借助Context類的registerReceiver方法,而靜態(tài)廣播的注冊直接在AndroidManifest.xml中聲明即可;我們首先分析一下動(dòng)態(tài)廣播的注冊過程。

Context類的registerReceiver的真正實(shí)現(xiàn)在ContextImpl里面,而這個(gè)方法間接調(diào)用了registerReceiverInternal,源碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; // Important !!!!! if (receiver != null) { if (mPackageInfo != null && context != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { if (scheduler == null) { scheduler = mMainThread.getHandler(); } rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver(); } } try { return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; } }

可以看到,BroadcastReceiver的注冊也是通過AMS完成的;在進(jìn)入AMS跟蹤它的registerReceiver方法之前,我們先弄清楚這個(gè)IIntentReceiver類型的變量rd是什么。首先查閱API文檔,很遺憾SDK里面沒有導(dǎo)出這個(gè)類,我們直接去?grepcode?上看,文檔如下:

System private API for dispatching intent broadcasts. This is given to the activity manager as part of registering for an intent broadcasts, and is called when it receives intents.

這個(gè)類是通過AIDL工具生成的,它是一個(gè)Binder對象,因此可以用來跨進(jìn)程傳輸;文檔說的很清楚,它是用來進(jìn)行廣播分發(fā)的。什么意思呢?

由于廣播的分發(fā)過程是在AMS中進(jìn)行的,而AMS所在的進(jìn)程和BroadcastReceiver所在的進(jìn)程不一樣,因此要把廣播分發(fā)到BroadcastReceiver具體的進(jìn)程需要進(jìn)行跨進(jìn)程通信,這個(gè)通信的載體就是IIntentReceiver類。其實(shí)這個(gè)類的作用跟?Activity生命周期管理?中提到的?IApplicationThread相同,都是App進(jìn)程給AMS進(jìn)程用來進(jìn)行通信的對象。另外,IIntentReceiver是一個(gè)接口,從上述代碼中可以看出,它的實(shí)現(xiàn)類為LoadedApk.ReceiverDispatcher。

OK,我們繼續(xù)跟蹤源碼,AMS類的registerReceiver方法代碼有點(diǎn)多,這里不一一解釋了,感興趣的話可以自行查閱;這個(gè)方法主要做了以下兩件事:

  • 對發(fā)送者的身份和權(quán)限做出一定的校檢
  • 把這個(gè)BroadcastReceiver以BroadcastFilter的形式存儲(chǔ)在AMS的mReceiverResolver變量中,供后續(xù)使用。
  • 就這樣,被傳遞過來的BroadcastReceiver已經(jīng)成功地注冊在系統(tǒng)之中,能夠接收特定類型的廣播了;那么注冊在AndroidManifest.xml中的靜態(tài)廣播是如何被系統(tǒng)感知的呢?

    在?插件加載機(jī)制?中我們知道系統(tǒng)會(huì)通過PackageParser解析Apk中的AndroidManifest.xml文件,因此我們有理由認(rèn)為,系統(tǒng)會(huì)在解析AndroidMafest.xml的<receiver>標(biāo)簽(也即靜態(tài)注冊的廣播)的時(shí)候保存相應(yīng)的信息;而Apk的解析過程是在PMS中進(jìn)行的,因此靜態(tài)注冊廣播的信息存儲(chǔ)在PMS中。接下來的分析會(huì)證實(shí)這一結(jié)論。

    發(fā)送和接收過程

    發(fā)送過程

    發(fā)送廣播很簡單,就是一句context.sendBroadcast(),我們順藤摸瓜,跟蹤這個(gè)方法。前文也提到過,Context中方法的調(diào)用都會(huì)委托到ContextImpl這個(gè)類,我們直接看ContextImpl對這個(gè)方法的實(shí)現(xiàn):

    1 2 3 4 5 6 7 8 9 10 11 12 13 public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } }

    嗯,發(fā)送廣播也是通過AMS進(jìn)行的,我們直接查看ActivityManagerService類的broadcastIntent方法,這個(gè)方法僅僅是調(diào)用了broadcastIntentLocked方法,我們繼續(xù)跟蹤;broadcastIntentLocked這個(gè)方法相當(dāng)長,處理了諸如粘性廣播,順序廣播,各種Flag以及動(dòng)態(tài)廣播靜態(tài)廣播的接收過程,這些我們暫時(shí)不關(guān)心;值得注意的是,在這個(gè)方法中我們發(fā)現(xiàn),其實(shí)廣播的發(fā)送和接收是融為一體的。某個(gè)廣播被發(fā)送之后,AMS會(huì)找出所有注冊過的BroadcastReceiver中與這個(gè)廣播匹配的接收者,然后將這個(gè)廣播分發(fā)給相應(yīng)的接收者處理。

    匹配過程

    某一條廣播被發(fā)出之后,并不是阿貓阿狗都能接收它并處理的;BroadcastReceiver可能只對某些類型的廣播感興趣,因此它也只能接收和處理這種特定類型的廣播;在broadcastIntentLocked方法內(nèi)部有如下代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Figure out who all will receive this broadcast. List receivers = null; List<BroadcastFilter> registeredReceivers = null; // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { // Query one target user at a time, excluding shell-restricted users // 略 } else { registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } }

    這里有兩個(gè)列表receivers和registeredReceivers,看名字好像是廣播接收者的列表;下面是它們的賦值過程:

    1 2 receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId);

    讀者可以自行跟蹤這兩個(gè)方法的代碼,過程比較簡單,我這里直接給出結(jié)論:

  • receivers是對這個(gè)廣播感興趣的靜態(tài)BroadcastReceiver列表;collectReceiverComponents 通過PackageManager獲取了與這個(gè)廣播匹配的靜態(tài)BroadcastReceiver信息;這里也證實(shí)了我們在分析BroadcasrReceiver注冊過程中的推論——靜態(tài)BroadcastReceiver的注冊過程的確實(shí)在PMS中進(jìn)行的。
  • mReceiverResolver存儲(chǔ)了動(dòng)態(tài)注冊的BroadcastReceiver的信息;還記得這個(gè)mReceiverResolver嗎?我們在分析動(dòng)態(tài)廣播的注冊過程中發(fā)現(xiàn),動(dòng)態(tài)注冊的BroadcastReceiver的相關(guān)信息最終存儲(chǔ)在此對象之中;在這里,通過mReceiverResolver對象匹配出了對應(yīng)的BroadcastReceiver供進(jìn)一步使用。
  • 現(xiàn)在系統(tǒng)通過PMS拿到了所有符合要求的靜態(tài)BroadcastReceiver,然后從AMS中獲取了符合要求的動(dòng)態(tài)BroadcastReceiver;因此接下來的工作非常簡單:喚醒這些廣播接受者。簡單來說就是回調(diào)它們的onReceive方法。

    接收過程

    通過上文的分析過程我們知道,在AMS的broadcastIntentLocked方法中找出了符合要求的所有BroadcastReceiver;接下來就需要把這個(gè)廣播分發(fā)到這些接收者之中。在broadcastIntentLocked方法的后半部分有如下代碼:

    1 2 3 4 5 6 7 8 9 10 11 BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); }

    首先創(chuàng)建了一個(gè)BroadcastRecord代表此次發(fā)送的這條廣播,然后把它丟進(jìn)一個(gè)隊(duì)列,最后通過scheduleBroadcastsLocked通知隊(duì)列對廣播進(jìn)行處理。

    在BroadcastQueue中通過Handle調(diào)度了對于廣播處理的消息,調(diào)度過程由processNextBroadcast方法完成,而這個(gè)方法通過performReceiveLocked最終調(diào)用了IIntentReceiver的performReceive方法。

    這個(gè)IIntentReceiver正是在廣播注冊過程中由App進(jìn)程提供給AMS進(jìn)程的Binder對象,現(xiàn)在AMS通過這個(gè)Binder對象進(jìn)行IPC調(diào)用通知廣播接受者所在進(jìn)程完成余下操作。在上文我們分析廣播的注冊過程中提到過,這個(gè)IItentReceiver的實(shí)現(xiàn)是LoadedApk.ReceiverDispatcher;我們查看這個(gè)對象的performReceive方法,源碼如下:

    1 2 3 4 5 6 7 8 9 10 11 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); if (!mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); args.sendFinished(mgr); } } }

    這個(gè)方法創(chuàng)建了一個(gè)Args對象,然后把它post到了mActivityThread這個(gè)Handler中;我們查看Args類的run方法:(堅(jiān)持一下,馬上就分析完了 ^ ^)

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public void run() { final BroadcastReceiver receiver = mReceiver; final boolean ordered = mOrdered; final IActivityManager mgr = ActivityManagerNative.getDefault(); final Intent intent = mCurIntent; mCurIntent = null; if (receiver == null || mForgotten) { if (mRegistered && ordered) { sendFinished(mgr); } return; } try { ClassLoader cl = mReceiver.getClass().getClassLoader(); // Important!! load class intent.setExtrasClassLoader(cl); setExtrasClassLoader(cl); receiver.setPendingResult(this); receiver.onReceive(mContext, intent); // callback } catch (Exception e) { if (mRegistered && ordered) { sendFinished(mgr); } if (mInstrumentation == null || !mInstrumentation.onException(mReceiver, e)) { throw new RuntimeException( "Error receiving broadcast " + intent + " in " + mReceiver, e); } } if (receiver.getPendingResult() != null) { finish(); } }

    這里,我們看到了相應(yīng)BroadcastReceiver的onReceive回調(diào);因此,廣播的工作原理到這里就水落石出了;我們接下來將探討如何實(shí)現(xiàn)對于廣播的插件化。

    思路分析

    上文中我們分析了BroadcastReceiver的工作原理,那么怎么才能實(shí)現(xiàn)對BroadcastReceiver的插件化呢?

    從分析過程中我們發(fā)現(xiàn),Framework對于靜態(tài)廣播和動(dòng)態(tài)廣播的處理是不同的;不過,這個(gè)不同之處僅僅體現(xiàn)在注冊過程——靜態(tài)廣播需要在AndroidManifest.xml中注冊,并且注冊的信息存儲(chǔ)在PMS中;動(dòng)態(tài)廣播不需要預(yù)注冊,注冊的信息存儲(chǔ)在AMS中。

    從實(shí)現(xiàn)Activity的插件化過程中我們知道,需要在AndroidManifest.xml中預(yù)先注冊是一個(gè)相當(dāng)麻煩的事情——我們需要使用『替身』并在合適的時(shí)候進(jìn)行『偷梁換柱』;因此看起來動(dòng)態(tài)廣播的處理要容易那么一點(diǎn),我們先討論一下如何實(shí)現(xiàn)動(dòng)態(tài)注冊BroadcastReceiver的插件化。

    首先,廣播并沒有復(fù)雜的生命周期,它的整個(gè)存活過程其實(shí)就是一個(gè)onReceive回調(diào);而動(dòng)態(tài)廣播又不需要在AndroidManifest.xml中預(yù)先注冊,所以動(dòng)態(tài)注冊的BroadcastReceiver其實(shí)可以當(dāng)作一個(gè)普通的Java對象;我們完全可以用純ClassLoader技術(shù)實(shí)現(xiàn)它——不就是把插件中的Receiver加載進(jìn)來,然后想辦法讓它能接受onReceive回調(diào)嘛。

    靜態(tài)BroadcastReceiver看起來要復(fù)雜一些,但是我們連Activity都搞定了,還有什么難得到我們呢?對于實(shí)現(xiàn)靜態(tài)BroadcastReceiver插件化的問題,有的童鞋或許會(huì)想,我們可以借鑒Activity的工作方式——用替身和Hook解決。但是很遺憾,這樣是行不通的。為什么呢?

    BroadcastReceiver有一個(gè)IntentFilter的概念,也就是說,每一個(gè)BroadcastReceiver只對特定的Broadcast感興趣;而且,AMS在進(jìn)行廣播分發(fā)的時(shí)候,也會(huì)對這些BroadcastReceiver與發(fā)出的廣播進(jìn)行匹配,只有Intent匹配的Receiver才能收到廣播;在分析源碼的時(shí)候也提到了這個(gè)匹配過程。如果我們嘗試用替身Receiver解決靜態(tài)注冊的問題,那么它的IntentFilter該寫什么?我們無法預(yù)料插件中靜態(tài)注冊的Receiver會(huì)使用什么類型的IntentFilter,就算我們在AndroidManifest.xml中聲明替身也沒有用——我們壓根兒收不到與我們的IntentFilter不匹配的廣播。其實(shí),我們對于Activity的處理方式也有這個(gè)問題;如果你嘗試用IntentFilter的方式啟動(dòng)Activity,這并不能成功;這算得上是DroidPlugin的缺陷之一。

    那么,我們就真的對靜態(tài)BroadcastReceiver無能為力嗎?想一想這里的難點(diǎn)是什么?

    沒錯(cuò),主要是在靜態(tài)BroadcastReceiver里面這個(gè)IntentFilter我們事先無法確定,它是動(dòng)態(tài)變化的;但是,動(dòng)態(tài)BroadcastReceiver不是可以動(dòng)態(tài)添加IntentFilter嗎!!!

    可以把靜態(tài)廣播當(dāng)作動(dòng)態(tài)廣播處理

    既然都是廣播,它們的功能都是訂閱一個(gè)特定的消息然后執(zhí)行某個(gè)特定的操作,我們完全可以把插件中的靜態(tài)廣播全部注冊為動(dòng)態(tài)廣播,這樣就解決了靜態(tài)廣播的問題。當(dāng)然,這樣也是有缺陷的,靜態(tài)BroadcastReceiver與動(dòng)態(tài)BroadcastReceiver一個(gè)非常大的不同之處在于:動(dòng)態(tài)BroadcastReceiver在進(jìn)程死亡之后是無法接收廣播的,而靜態(tài)BroadcastReceiver則可以——系統(tǒng)會(huì)喚醒Receiver所在進(jìn)程;這算得上缺陷之二,當(dāng)然,瑕不掩瑜。

    靜態(tài)廣播非靜態(tài)的實(shí)現(xiàn)

    上文我們提到,可以把靜態(tài)BroadcastReceiver當(dāng)作動(dòng)態(tài)BroadcastReceiver處理;我們接下來實(shí)現(xiàn)這個(gè)過程。

    解析

    要把插件中的靜態(tài)BroadcastReceiver當(dāng)作動(dòng)態(tài)BroadcastReceiver處理,我們首先得知道插件中到底注冊了哪些廣播;這個(gè)過程歸根結(jié)底就是獲取AndroidManifest.xml中的<receiver>標(biāo)簽下面的內(nèi)容,我們可以選擇手動(dòng)解析xml文件;這里我們選擇使用系統(tǒng)的 PackageParser 幫助解析,這種方式在之前的 [插件加載過程][] 中也用到過,如果忘記了可以溫習(xí)一下。

    PackageParser中有一系列方法用來提取Apk中的信息,可是翻遍了這個(gè)類也沒有找到與「Receiver」名字相關(guān)的方法;最終我們發(fā)現(xiàn)BroadcastReceiver信息是用與Activity相同的類存儲(chǔ)的!這一點(diǎn)可以在PackageParser的內(nèi)部類Package中發(fā)現(xiàn)端倪——成員變量receivers和activities的范型類型相同。所以,我們要解析apk的<receiver>的信息,可以使用PackageParser的generateActivityInfo方法。

    知道這一點(diǎn)之后,代碼就比較簡單了;使用反射調(diào)用相應(yīng)的隱藏接口,并且在必要的時(shí)候構(gòu)造相應(yīng)參數(shù)的方式我們在插件化系列文章中已經(jīng)講述過很多,相信讀者已經(jīng)熟練,這里就不贅述,直接貼代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 private static void parserReceivers(File apkFile) throws Exception { Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser"); Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class); Object packageParser = packageParserClass.newInstance(); // 首先調(diào)用parsePackage獲取到apk對象對應(yīng)的Package對象 Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_RECEIVERS); // 讀取Package對象里面的receivers字段,注意這是一個(gè) List<Activity> (沒錯(cuò),底層把<receiver>當(dāng)作<activity>處理) // 接下來要做的就是根據(jù)這個(gè)List<Activity> 獲取到Receiver對應(yīng)的 ActivityInfo (依然是把receiver信息用activity處理了) Field receiversField = packageObj.getClass().getDeclaredField("receivers"); List receivers = (List) receiversField.get(packageObj); // 調(diào)用generateActivityInfo 方法, 把PackageParser.Activity 轉(zhuǎn)換成 Class<?> packageParser$ActivityClass = Class.forName("android.content.pm.PackageParser$Activity"); Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState"); Class<?> userHandler = Class.forName("android.os.UserHandle"); Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId"); int userId = (Integer) getCallingUserIdMethod.invoke(null); Object defaultUserState = packageUserStateClass.newInstance(); Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component"); Field intentsField = componentClass.getDeclaredField("intents"); // 需要調(diào)用 android.content.pm.PackageParser#generateActivityInfo(android.content.pm.ActivityInfo, int, android.content.pm.PackageUserState, int) Method generateReceiverInfo = packageParserClass.getDeclaredMethod("generateActivityInfo", packageParser$ActivityClass, int.class, packageUserStateClass, int.class); // 解析出 receiver以及對應(yīng)的 intentFilter for (Object receiver : receivers) { ActivityInfo info = (ActivityInfo) generateReceiverInfo.invoke(packageParser, receiver, 0, defaultUserState, userId); List<? extends IntentFilter> filters = (List<? extends IntentFilter>) intentsField.get(receiver); sCache.put(info, filters); } }

    注冊

    我們已經(jīng)解析得到了插件中靜態(tài)注冊的BroadcastReceiver的信息,現(xiàn)在我們只需要把這些靜態(tài)廣播動(dòng)態(tài)注冊一遍就可以了;但是,由于BroadcastReceiver的實(shí)現(xiàn)類存在于插件之后,我們需要手動(dòng)用ClassLoader來加載它;這一點(diǎn)在?插件加載機(jī)制?已有講述,不啰嗦了。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 ClassLoader cl = null; for (ActivityInfo activityInfo : ReceiverHelper.sCache.keySet()) { Log.i(TAG, "preload receiver:" + activityInfo.name); List<? extends IntentFilter> intentFilters = ReceiverHelper.sCache.get(activityInfo); if (cl == null) { cl = CustomClassLoader.getPluginClassLoader(apk, activityInfo.packageName); } // 把解析出來的每一個(gè)靜態(tài)Receiver都注冊為動(dòng)態(tài)的 for (IntentFilter intentFilter : intentFilters) { BroadcastReceiver receiver = (BroadcastReceiver) cl.loadClass(activityInfo.name).newInstance(); context.registerReceiver(receiver, intentFilter); } }

    就這樣,我們對插件靜態(tài)BroadcastReceiver的支持已經(jīng)完成了,是不是相當(dāng)簡單?至于插件中的動(dòng)態(tài)廣播如何實(shí)現(xiàn)插件化,這一點(diǎn)交給讀者自行完成,希望你在解決這個(gè)問題的過程中能夠加深對于插件方案的理解 ^ ^

    小節(jié)

    本文我們介紹了BroadcastReceiver組件的插件化方式,可以看到,插件方案對于BroadcastReceiver的處理相對簡單;同時(shí)「靜態(tài)廣播非靜態(tài)」的特性以及BroadcastReceiver先天的一些特點(diǎn)導(dǎo)致插件方案沒有辦法做到盡善盡美,不過這都是大醇小疵——在絕大多數(shù)情況下,這樣的處理方式是可以滿足需求的。

    雖然對于BroadcastReceiver的處理方式相對簡單,但是文章的內(nèi)容卻并不短——我們花了大量的篇幅講述BroadcastReceiver的原理,這也是我的初衷:借助DroidPlugin更深入地了解Android Framework。

    原文出處:http://weishu.me/2016/04/12/understand-plugin-framework-receiver/

    總結(jié)

    以上是生活随笔為你收集整理的Android插件化原理解析——广播的管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。