進階之路 | 奇妙的四大組件之旅

前言

本文已經收錄到個人Github我的博客,歡迎大佬們光臨寒舍:html

個人GIthub博客git

學習清單:

  • Activity的工做過程
  • Service的工做過程
  • Service的啓動過程
  • Service的綁定過程
  • BroadcastReceiver的工做過程
  • BroadcastReceiver的註冊過程
  • BroadcastReceiver的發送和接收過程
  • ContentProvider的工做過程

一.爲何要學習四大組件?

何爲「四大」:github

  • Activity
  • Service
  • BroadcastReceiver
  • ContentProvider

談到四大組件,相信在座各位都再熟悉不過了,光聞其名,未見其聲,「四大」二字一出,足見其在安卓系統中的地位,可謂是安卓界的F4面試

其地位之崇高,在某種程度上也能夠體現他的重要性,因此說,光會使用四大組件仍是不能體現咱們對他的重視(ai hu)的,咱們還要分析其工做過程,可以更好地理解系統內部的運行機制,從而加深對Android體系結構的認識;同時,四大組件仍是面試必問的知識點之一。數據庫

綜上,掌握好四大組件相關的知識,對於一個Android開發者來講是很是重要的!ide

如下內容緊張赤雞,請繫好保險帶,咱們要開車(hu you)了。— No picture,say a J8!post

老司機開車

二.核心知識點概括

2.1 概述

2.1.1 Activity

  • 類型:展現型組件學習

  • 做用:展現一個界面並和用戶交互測試

  • 使用:this

    A.須要在AndroidManifest中註冊

    B.須要藉助Intent啓動,兩種方式:

  • 顯示Intent:

    Intent intent=new Intent(xxx.this,xxx.class); startActivity(intent);

  • 隱式Intent:

    Intent intent=new Intent(); intent.setAction(xxx); intent.addCategory(xxx); startActivity(intent);

  • 四種啓動模式:
  • standard:標準模式
  • singleTop:棧頂複用模式
  • singleTask:棧內複用模式
  • singleInstance:單實例模式

想了解啓動模式的讀者,能夠看下筆者寫的一篇文章:進階之路 | 奇妙的Activity之旅中的2.2部分

  • 經過finish()結束一個Activity

2.1.2 Service

  • 類型:計算型組件

  • 做用:在後臺執行一系列計算任務,耗時的後臺計算建議在單獨的線程中執行

  • 使用:

    A.須要在AndroidManifest中註冊

    B.須要藉助Intent啓動:Intent intent = new Intent(xxx.this, xxx.class); startService(intent);

    C.兩種運行狀態:

  • 啓動狀態:經過startService()
  • 綁定狀態:經過bindService()

​ D.中止方式:unBindService();stopService();

2.1.3 BroadcastReceiver

  • 類型:消息型組件
  • 做用:在不一樣的組件乃至不一樣的應用之間傳遞消息
  • 使用:
  • 兩種註冊方式:

    A.動態註冊:經過Context.registerReceiver()& Context.unRegisterReceiver(),必需要啓動應用才能註冊並接收廣播。

    B.靜態註冊:在AndroidManifest文件中註冊,不須要啓動應用便可接收廣播。

  • 須要藉助Intent發送廣播:Intent intent = new Intent("xxx"); sendBroadcast(intent);

  • 四種廣播類型:

    A.普通廣播

    B.有序廣播

    C.本地廣播

    D.粘性廣播

  • 沒有中止概念

2.1.4 ContentProvider

  • 類型:共享型組件
  • 做用:向其餘組件乃至其餘應用共享數據(安卓IPC的一種方式)
  • 使用:
  • 須要在AndroidManifest中註冊

  • 無需藉助Intent啓動

  • 四種操做:注意須要處理好線程同步(由於這些操做運行在Binder線程)

    A.insert():添加數據

    B.update():更新數據

    C.delete():刪除數據

    D.query():查詢數據

  • 無需手動中止

想詳細瞭解IPC機制的讀者,能夠看下筆者寫的一篇文章:進階之路 | 奇妙的 IPC 之旅

2.2 工做過程

差很少該進入今天的主題了,爲了逼格,爲了高薪,大夥往前衝!

2.2.1 Activity

Activity啓動過程流程圖:

一眼看上去有點暈暈的,牆裂建議配合源碼一塊兒服用,效果極佳,筆者推薦一篇文章:圖解Activity啓動流程,進階高級

`Activity`啓動過程

Q1:結論:

  • ActivityManagerServiceApplicationThread都是Binder
  • Application的建立也是經過Instrumentation來完成的,這個過程和Activity對象同樣,都是經過類加載器來實現的
  • Activity的啓動過程最終回到ApplicationThread中,經過ApplicationThread.scheduleLaunchActivity() 將啓動Activity的消息發送並交由Handler H處理。
  • Handler H對消息的處理會調用handleLaunchActivity()->performLaunchActivity()得以最終完成Activity的建立和啓動。

Q2:重點類

  • Instrumentation

instrumentationAndroid系統裏面的一套控制方法或者」鉤子「。 這些鉤子能夠在正常的生命週期(正常是由操做系統控制的)以外控制Android控件的運行;它們同時能夠控制Android如何加載應用程序。

  • ActivityManagerService「AMS」

AMS是系統的引導服務,應用進程的啓動、切換和調度、四大組件的啓動和管理都須要AMS的支持。

  • ActivityStackSupervisor:
  • ActivityStackSupervisorAMS中的構造方法中被建立。

  • AMS 經過操做ActivityStackSupervisor來管理Activity

  • ActivityStack:
  • ActivityStack從名稱來看是跟棧相關的類,其實它是一個管理類,用來管理系統全部Activity的各類狀態
  • 它由ActivityStackSupervisor來進行管理的
  • ApplicationThread:
  • ActivityThread的私有內部類,也是一個Binder對象
  • 在此處它是做爲IApplicationThread對象的Server端,等待Client端的請求而後進行處理,最大的Client就是AMS

2.2.2 Service

源碼流程分析:Service的工做過程

1.啓動過程:

Service啓動過程

2.綁定過程:

Service綁定過程

結論:

  • ContextImplContext的具體實現,經過Activity.attach()Activity創建關聯。Activity.attach()中還會完成Window的建立並和Activity&Window的關聯,由此事件可傳遞給Window
  • ActivityServices是一個輔助ActivityManagerService(AMS)進行Service管理的類,包括Service的啓動、綁定和中止。
  • Activity相似的,Service的啓動/綁定過程最終回到ApplicationThread中,經過ActivityThread.handleCreateService()/ActivityThread.handleBindService完成Service的啓動/綁定,注意綁定Service的後續還必須告知客戶端已經成功鏈接Service的這一流程,由ActivityManagerService.publishService()去完成。

2.2.3 BroadcastReceiver

源碼流程分析:BroadcastReceiver 的工做過程分析

1.註冊

四大組件的靜態註冊都是在應用安裝時由PackageManagerService(PMS)解析註冊,當動態註冊BroadcastReceiver時流程爲:

BroadcastReceiver動態註冊

2.發送和接收

發送和接收流程

結論:

  • 動態註冊廣播最終會跨進程交給AMS,並把遠程Receiver( 實際上傳的是IIntentReceiver,是個Binder 對象)和遠程IntentFilter保存起來,完成註冊任務
  • 發送廣播時,系統爲intent添加了兩個標記位:
  • FLAG_EXCLUDE_STOPPED_PACKAGES :廣播不會發送給已經中止的APP(系統爲全部廣播默認添加該標記)
  • FLAG_INCLUDE_STOPPED_PACKAGES :廣播也會發送到已經中止的APP(兩個標記共存時,以該標記爲準
  • 最終在ReceiverDispatcher .performReceive ()裏回調了ReceiveronReceive(),使得廣播得以接收並處理

Q2:實現原理:

從實現原理看上,廣播使用了觀察者模式,基於消息的發佈/訂閱事件模型

具體實現流程要點粗略歸納以下:

  • 廣播接收者BroadcastReceiver經過Binder機制向AMS進行註冊
  • 廣播發送者經過Binder機制向AMS發送廣播
  • AMS查找符合相應條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發送到BroadcastReceiver(通常狀況下是Activity)相應的消息循環隊列中
  • 消息循環執行拿到此廣播,回調BroadcastReceiver中的onReceive()方法

2.2.4 ContentProvider

1.啓動流程總概

ContentProvider啓動流程總概

  • 啓動的入口爲ActivityThread.main():建立ActivityThread實例並建立主線程消息隊列
  • ActivityThread.attach():遠程調用AMS.attachApplication()並提供ApplicationThread用於和AMS的通訊
  • AMS.attachApplication():經過ActivityThread.bindApplication()方法和Handler H來調回ActivityThread.handleBindApplication()
  • ActivityThread.handleBindApplication():先建立Application、再加載ContentProvider、最後回調Application.onCreate()
2.Query過程流程

insert()delete()update()的實現原理和query()相似,限於篇幅,這裏不展開,感興趣的讀者能夠主動去探究

源碼流程分析:ContentProvider的工做過程

3gYU1K.jpg

結論:

  • ContentProvidermultiprocess屬性:ContentProvider是不是單例,通常用單例

  • 訪問ContentProvider須要ContentResolver,其真正實現類是ApplicationContentResolver。當ContentProvider所在進程未啓動時,第一次訪問它會觸發ContentProvider的建立以及進程啓動

  • ContentProvider所在的進程啓動時,會同時被啓動並被髮布到AMS

注意:ContentProvider.onCreate()Application.onCreate()執行

  • 一樣的,最終經過ActivityThread.handleBindApplication()完成ContentProvider的建立。

三.課堂小測試

恭喜你!已經看完了前面的文章,相信你對四大組件已經有必定深度的瞭解,下面,進行一下課堂小測試,驗證一下本身的學習成果吧!

Q1:爲何要使用ContentProvider?它和SQL在實現上有什麼區別?

  • ContentProvider 屏蔽了數據存儲的細節,內部實現透明化,用戶只需關心URI便可(是否匹配)
  • ContentProvider能實現不一樣APP的數據共享,SQL只能是本身程序才能訪問
  • ContentProvider還能增刪本地的文件,XML等信息

Q2:Android引入四大組件的用意

這個問題在筆者剛開始學習Android的時候就一直困惑,直到看了一篇Google Android 團隊:Dianne Hackborn發表在Google+上的一篇post譯文

看法:Google Android Framework團隊決定,不要讓一個明確的Main方法做爲APP的入口,由於須要讓系統對APP怎樣運行有更多的控制權,在該系統中,用戶永遠不須要考慮開啓和中止一個APP,而把這些事交給系統去管理。因此他們設計了四大組件以做爲APP功能的載體和入口

  • Activity

一個APP與用戶交互的入口

  • BroadcastReceiver
  • 一種讓系統在正常的用戶流(user flow)以外,傳遞事件給APP的機制。
  • 最重要的是,由於這是另外一個被精心定義的APP的入口,即便APP當前並不在運行,系統也能夠將Broadcasts傳遞給APP
  • Service

APP因爲各類各樣的緣由須要在後臺運行時,Service就是一個這樣的入口

  • ContentProvider
  • 人們一般會將它看成對數據庫的抽象,由於有許多的API和支持庫就是這樣使用ContentProvider
  • 可是從系統設計的角度,這並非ContentProvider的初衷。對於系統來講,ContentProvider其實是一個入口,用於獲取一個APP內部的公開的被命名的數據項(data items),每一個數據項都被一個URI scheme所標識。

若是文章對您有一點幫助的話,但願您能點一下贊,您的點贊,是我前進的動力

本文參考連接:

相關文章
相關標籤/搜索