摘要:關于后稱的操作我們知道其實就是文件,所以這里的操作有獲取移動刪除。操作啟動停止重啟綁定解綁獲取系統服務以及多用戶操作。權限操作檢查本是否有某種權限檢查某是否有某種權限檢查權限授予權限等等。
先放一張圖吧 2.用處
1.Context的實現類有很多,但是ContextImpl(后稱CI)是唯一做具體工作的,其他實現都是對CI做代理。
2.CI中有一些成員對象,先來看看這些對象的用處
1.mSharedPrefsPaths(ArrayMap
2.mMainThread(ActivityThread(后稱AT)):這個對象是一個app進程的主線程,一個app的framework層就是從這里啟動的。
3.mPackageInfo(LoadedApk(后稱LA)):在AT初始化app的主線程的時候,會將APK加載到內存中,apk在內存中就是以這個對象的形式存在的,該對象可以加載apk的資源和dex文件。
4.mUser(UserHandle):多用戶相關
5.mContentResolver(ApplicationContentResolver):繼承于ContentResolver(后稱CR),主要功能是通過Uri來獲取文件、數據庫、asset、res等數據,還有就是通過ContentProvider來獲取其他應用和本機數據。
6.mResourcesManager(ResourcesManager):單例,因為一個apk不同機型的適配資源,所以用來加載Resource對象,以保證一個app中所有的CI使用的都是同一份資源。
7.mResources(Resources):獲取apk中res資源的對象。
8.mOuterContext(Context):用于指向代理本對象的Context,例如Activity、Service等
9.mTheme(Resources.Theme):主題
10.mPackageManager(PackageManager(后稱PM)):包管理類,不僅可以獲取我們apk包的信息,還能獲取本機apk包的信息。
3.CI中有很多api,我將這些api歸了一下類
1.獲取成員對象:即獲取上面我列出來的那些對象,這些對象獲取到了之后又有更多api暴露出來,在這里CI相當于做了一個聚合。最常用的就是getResource()了。
2.獲取成員對象的成員對象:即為了方便,CI封裝了一些常用的獲取成員對象中的信息的方法。例如getPackageName(),是通過PM來獲取的。
3.關于SharedPreferences(后稱SP)的操作:我們知道SP其實就是xml文件,所以這里的操作有:獲取、移動、刪除。
4.文件操作:增刪移文件、打開文件流、獲取app私有文件夾地址等等。
5.數據庫操作:我們知道sqlite其實是一種文件型數據庫,所以有:打開、創建、移動、刪除、獲取數據庫文件路徑,等操作。
6.壁紙相關操作:這個不是成員變量提供的,WallpaperManager是系統Service一種,所以是SystemService提供的。
7.啟動Activity:包括一般啟動Acitivyt、多用戶啟動Activity、啟動多個Activity。
8.廣播操作:發送普通廣播、發送需要權限的廣播、發送有序廣播、發送粘連廣播、發送有序粘連廣播、多用戶廣播、移除各種廣播、注冊各種廣播、取消注冊各種廣播。
9.Service操作:啟動、停止、重啟、綁定、解綁、獲取系統服務以及多用戶操作。
10.權限操作:檢查本app是否有某種權限、檢查某app是否有某種權限、檢查Uri權限、授予權限等等。
11.各種情況下創建CI:這個比較重要
1.createSystemContext(ActivityThread mainThread):在SystemService創建的時候為其創建一個CI
2.createAppContext(ActivityThread mainThread, LoadedApk packageInfo):在Application/Service創建的時候為其創建一個CI
3.createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration):在Activity創建的時候為其創建一個CI。
在了解Binder的時候有如下要注意的點
1.Activity初始化:
1.CI.startActivity():將調用交給Instrumentation(負責監控Activity和AMS的交互,所有Activity的本地進程到遠端進程的調用轉換都是其來執行),
2.Instrumentation.execStartActivity():傳入一個ApplicationThread(后稱APT)然后通過Binder機制將調用過程轉移到ActivityManagerService(后稱AMS)所在的系統服務進程,本地主線程則繼續運行,不過本地主線程后續也沒別的操作了,接下來就是本地的MessageQueue等待AMS服務運行完畢,發送消息將Activity的啟動重新交給本地主線程。
3.AMS.startActivity():從這里開始會調用會按順序在 ActivityStarter、ActivityStackSupervisor、ActivityStack 這三個類之間進行調用,主要會進行下面這些操作,不按順序:
1.對Intent的內容進行解析,獲取目標Activity的信息。
2.根據傳入的APT獲取被調用app的信息封裝成 ProcessRecord(后稱PR)。
3.將1、2和其他信息結合,將源Activity和目標Activity封裝成兩個ActivityRecord(后稱AR)
4.解析Activity的啟動模式 和當前的Activity棧狀態,判斷是否需要創建棧和Activity。(注意這里的AR有著app中的Activity的全部信息,可以將其看成系統服務里面的Activity的化身)
5.獲取到Activity和Activity棧之后,接下來要判斷是否要將當前Activity 執行onPause() 以及讓使用Binder執行目標Activity的 onCreate()和onResume(注意這里onStart()會在Binder遠程調用onCreate()的時候直接執行),這里AMS進程會使用APT調用app進程的Activity執行相應的生命周期。
6.在AMS中前置準備一切就緒之后,會通過APT使用Handler的形式調用到app進程的AT中。
7.最終到了ActivityStackSupervisor.realStartActivityLocked()中會使用APT將調用交給app進程-->AT.scheduleLaunchActivity()-->AT.handleLaunchActivity()
4.AT.handleLaunchActivity():將有以下操作
1.AT.performLaunchActivity:這個方法有以下操作
1.創建對象LoadedApk(后稱LA,一個app只加載一次)
2.創建對象Activity
3.創建對象Application(一個app,只創建一次)
4.創建對象CI:CI.createActivityContext()
5.Application/CI都attach到Activity對象:Activity.attach()
6.執行onCreate():Instrumentation.callActivityOnCreate()-->Activity.performCreate()-->Activity.onCreate()
7.執行onStart():AT.performLaunchActivity-->Activity.performStart()-->>Instrumentation.callActivityOnStart()—>Activity.onStart()
2.AT.handleResumeActivity()
1.AT.performResumeActivity()-->Activity.performResume()-->Instrumentation.callActivityOnResume()-->Activity.onResume()
2.Activity.makeVisible()-->WindowManager.addView():開始進行View的繪制流程。
3.從上面我們可以總結一下:在AMS將調用交給app進程之后,三個生命周期都是在app進程被回調的,并且在onResume()之后View才進行繪制
2.Service初始化:
1.CI.startService()-->CI.startServiceCommon():在這里傳入一個APT,類似Activity啟動時的第二步,將調用過程轉移到AMS中,本地主線程繼續運行,等待APT從AMS進程將調用轉移到本地主線程中。
2.AMS.startService():到了AMS進程之后,Service的啟動就會全權交給ActiveServices(后稱AS,這是AMS用來管理Service的成員變量)
3.AS.startServiceLocked():這里做了以下操作
1.根據傳入的APT獲取被調用app的信息封裝成 PR
2.解析Intent等參數獲取到Service的信息,封裝成ServicecRecord(后稱SR,這個類可以看做是Service在系統服務的化身,記錄了Service的一切信息)
3.再進過一系列調用:AS.startServiceInnerLocked()-->AS.bringUpServiceLocked()-->AS.realStartServiceLocked()到這里才是真正在app進程啟動Service的流程。
4.AS.realStartServiceLocked():這里會有以下操作:
1.SR.thread.scheduleCreateService():thread就是APT,這里會將調用轉到app進程,但是當前的進程還會繼續執行,這里就到了app線程的APT,這個方法里有以下操作
1.通過Handler轉到AT.handleCreateService()
2.創建對象LA(一個app只加載一次)
3.創建對象Service
4.創建對象CI
5.創建對象Application(一個app只創建一次)
6.Application/CI分別attach到Service對象
7.執行Service.onCreate()回調
8.此時Service已經啟動了
2.AS.sendServiceArgsLocked()-->SR.app.thread.scheduleServiceArgs():這里就轉到了app進程的APT中,這里會有以下操作:
1.APT.scheduleServiceArgs()
2.AT.handleServiceArgs()
3.Service.onStartCommand()
4.此時我們需要在Service中進行的操作將會執行。
3.ContentProvider初始化:
1.AT.main()-->AT.attach()-->AMS.attachApplication():傳入一個APT,調用轉到了AMS進程
2.AMS.attachApplicationLocked():獲取到ApplicationInfo 和 ProviderInfo列表之后通過APT將調用轉回app進程。
3.APT.bindApplication()-->AT.handleBindApplication()-->AT.installContentProviders():到這里之后將會循環初始化ContentProvider。
4.AT.installProvider():這個方法里面有以下操作
1.創建對象LA:CI.createPackageContext()中
2.創建對象CI:CI.createPackageContext()中
3.創建對象ContentProvider:ClassLoader創建
4.CI attach到ContentProvider對象:ContentProvider.attachInfo()中
5.執行onCreate回調:ContentProvider.attachInfo()中
4.BroadCastReceiver靜態初始化:因為動態廣播的注冊時進程已創建, 基本對象已創建完成,只需要回調BroadcastReceiver的onReceive()方法即可,所以這里不分析
1.當收到廣播時會調用AT.handleReceiver()
2.創建對象LA(一個app只加載一次)
3.創建對象BroadcastReceiver
4.創建對象Application
5.從創建的Application中獲取CI
6.執行onReceive()回調
5.Application初始化:由上面四個組件的初始化我們可以知道,當app還沒啟動的時候喚醒任意組件都會創建一個Application,而這里分析的是正常情況啟動一個app的時候創建Application的流程。
1.這里的流程其實就是包含了ContentProvider初始化的流程,所以前面都差不多
2.最后到了AT.handleBindApplication()中,這里有以下操作:
1.創建對象LA
2.創建對象CI
3.創建對象Instrumentation
4.創建對象Application;
5.安裝providers
6.執行Create回調
4.四大組件以及Application綁定Context的方法由上一節我們可以知道,四大組件以及Application在初始化的時候都會進行Context的綁定或者創建,這節就來講講各個組件是如何對context進程賦值的。
1.Activity:
1.AT.performLaunchActivity()
2.AT.createBaseContextForActivity(ActivityClientRecord , Activity)
3.ContextImpl.createActivityContext(ActivityThread , LoadedApk , IBinder , int displayId , Configuration)
4.ContextImpl():被賦值了 ActivityThread、LoadedApk、IBinder activityToken、Configuration
2.Service/Application:
1.AT.handleCreateService()
2.ContextImpl.createAppContext(ActivityThread , LoadedApk)
3.new ContextImpl():被賦值了 ActivityThread、LoadedApk
3.BroadCastReceiver:在AT.handleReceiver()中直接獲取Application的Context,其自身并不創建Context
4.ContentProvider:
1.AT.installProvider()
2.Context.createPackageContext()-->CI.createPackageContext()-->CI.createPackageContextAsUser():這里是通過一個Application的Context創建的Context,所以可以看做是Application的Context的一個復制。
5.總結 1.組件初始化會創建的對象:1.LoadedApk:所有組件在初始化的時候,如果LA沒被初始化都會初始化一遍
2.Context:
1.只有Activity的CI有上一個Activity的Token
2.Receiver的Context是繼承于ContextWrapper 的 ReceiverRestrictedContext,不可綁定Service。
3.Application:
1.Receiver使用的Context是ReceiverRestrictedContext包裝的Application的Context,所以其可以通過Context獲取到Application
2.ContentProvider一般是在app初始化的時候在初始化Application的過程中加載的,此時Application會被加載。但是如果是多個app共享進程,第二個app由ContentProvider調起,那么Application不會被初始化。
2.Context使用場景說明: (圖中第一列代表不同的Context, √代表允許在該Context執行相應的操作; ×代表不允許; -代表分情況討論)
1.當Context為Receiver的情況下:
1.不允許執行bindService()操作, 由于限制性上下文(ReceiverRestrictedContext)所決定的,會直接拋出異常.
2.registerReceiver是否允許取決于receiver;
3.當receiver == null用于獲取sticky廣播, 允許使用;否則不允許使用registerReceiver;
2.縱向來看startActivity操作
1.當為Activity Context則可直接使用;
2.當為其他Context, 要啟動的Activity不屬于任何Activity棧,所以必須帶上FLAG_ACTIVITY_NEW_TASK flags才能使用
3.getApplication()和getApplicationContext()絕大多數情況下, getApplication()和getApplicationContext()這兩個方法完全一致, 返回值也相同; 那么兩者到底有什么區別呢? 真正理解這個問題的人非常少. 接下來徹底地回答下這個問題:
1.getApplicationContext()這個的存在是Android歷史原因. 我們都知道getApplication()只存在于Activity和Service對象; 那么對于BroadcastReceiver和ContentProvider卻無法獲取Application, 這時就需要一個能在Context上下文直接使用的方法, 那便是getApplicationContext().
2.對于Activity/Service來說, getApplication()和getApplicationContext()的返回值完全相同; 除非廠商修改過接口;
3.BroadcastReceiver在onReceive的過程, 能使用getBaseContext().getApplicationContext獲取所在Application, 而無法使用getApplication;
4.ContentProvider能使用getContext().getApplicationContext()獲取所在Application. 絕大多數情況下沒有問題, 但是有可能會出現空指針的問題, 情況如下:當同一個進程有多個apk的情況下, 對于第二個apk是由provider方式拉起的, 前面介紹過provider創建過程并不會初始化所在application, 此時執getContext().getApplicationContext()返回的結果便是NULL. 所以對于這種情況要做好判空.
作者:何時夕
鏈接:https://www.jianshu.com/p/f49...
近3年BAT面試真題整理合集
?一招教你讀懂JVM和Dalvik之間的區別
金9銀10的面試黃金季節,分享幾個重要的面試題
kotlin學習筆記-異常好玩的list集合總結
相信自己,沒有做不到的,只有想不到的在這里獲得的不僅僅是技術!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/76580.html
摘要:作為的四大組件之二,其應用場景非常多。作用可以監聽或接收應用或系統發出的廣播消息,并做出響應。可以指定獨立的進程四大組件都可以通過此屬性指定自己的獨立進程。對于應用內廣播的動態注冊方式,回調中的返回值是。 前言 Hi,大家好,又雙見面啦,上一期我們講了如何使用Activity,肯定有不少小伙伴已經創建了屬于自己的FirstActivity,那么這一期我們主要為大家介紹第二個重要組件Br...
摘要:方法,是一個對象是從構造函數中賦值。上面我們分析到會執行構造函數,在構造函數會將的賦值給的。傳入的是返回對象也是繼承,其是。參考插件化技術原理篇中詳解你所不知道的更深層次的理解 Android插件化在國內已不再是幾個巨頭公司團隊在玩了,陸續有團隊開源其解決方案,例如 Small,VirtualAPK,RePlugin,Atlas,甚至Lody開發的VirtualApp。另外我司也在玩,...
摘要:但是,一定會被執行,從而保證了廣播在死亡前一定會被注銷,從而防止內存泄露。對于應用內廣播的動態注冊非方式,回調中的返回值是 前言 BroadcastReceiver(廣播接收器),屬于Android四大組件之一 在Android開發中,BroadcastReceiver的應用場景非常多 今天,我將詳細講解關于BroadcastReceiver的一切相關知識 目錄 showImg(...
閱讀 3120·2023-04-25 15:44
閱讀 1889·2019-08-30 13:11
閱讀 2850·2019-08-30 11:11
閱讀 3072·2019-08-29 17:21
閱讀 1318·2019-08-29 15:38
閱讀 965·2019-08-29 12:49
閱讀 1810·2019-08-28 18:19
閱讀 3236·2019-08-26 14:01