2019Android面試總結(jié)

Java

equals和==、hashCode的區(qū)別

  • == 比較棧中存儲(chǔ)的值是否相同
  • equals 如果不重寫equals方法時(shí),其和==作用相同,Object類默認(rèn)實(shí)現(xiàn)就是通過==來實(shí)現(xiàn)equals的,重寫后按照會(huì)根據(jù)equals返回結(jié)果比較.
  1. 重寫equals方法時(shí)需要重寫hashCode方法,主要是針對Map、Set等集合類型的使用;
    a: Map、Set等集合類型存放的對象必須是唯一的;
    b: 集合類判斷兩個(gè)對象是否相等,是先判斷equals是否相等,如果equals返回TRUE,還要再判斷HashCode返回值是否ture,只有兩者都返回ture,才認(rèn)為該兩個(gè)對象是相等的。
  2. 由于Object的hashCode返回的是對象的hash值,所以即使equals返回TRUE,集合也可能判定兩個(gè)對象不等,所以必須重寫hashCode方法,以保證當(dāng)equals返回TRUE時(shí),hashCode也返回Ture,這樣才能使得集合中存放的對象唯一。

JVM內(nèi)存模型

image.png

JVM 的內(nèi)存區(qū)域可以分為兩類:線程私有和區(qū)域和線程共有的區(qū)域。 線程私有的區(qū)域:程序計(jì)數(shù)器、JVM 虛擬機(jī)棧、本地方法棧;線程共有的區(qū)域:堆、方法區(qū)

  • 程序計(jì)數(shù)器(Program Counter Register)也叫做PC寄存器,是一塊較小的內(nèi)存空間。在虛擬機(jī)概念模型中,字節(jié)碼解釋器工作時(shí)就是通過改變程序計(jì)數(shù)器來選取下一條需要執(zhí)行的字節(jié)碼指令,Java虛擬機(jī)的多線程是通過輪流切換并分配處理器執(zhí)行時(shí)間的方式來實(shí)現(xiàn)的,在一個(gè)確定的時(shí)刻只有一個(gè)處理器執(zhí)行一條線程中的指令,為了在線程切換后能恢復(fù)到正確的執(zhí)行位置,每個(gè)線程都會(huì)有一個(gè)獨(dú)立的程序計(jì)數(shù)器,因此,程序計(jì)數(shù)器是線程私有的。如果線程執(zhí)行的方法不是Native方法,則程序計(jì)數(shù)器保存正在執(zhí)行的字節(jié)碼指令地址,如果是Native方法則程序計(jì)數(shù)器的值則為空(Undefined)。程序計(jì)數(shù)器是Java虛擬機(jī)規(guī)范中唯一沒有規(guī)定任何OutOfMemoryError情況的數(shù)據(jù)區(qū)域。
  • Java虛擬機(jī)棧(Java Virtual Machine Stacks)
    它的生命周期與線程相同,與線程是同時(shí)創(chuàng)建的。Java虛擬機(jī)棧存儲(chǔ)線程中Java方法調(diào)用的狀態(tài),包括局部變量、參數(shù)、返回值以及運(yùn)算的中間結(jié)果等。一個(gè)Java虛擬機(jī)棧包含了多個(gè)棧幀,一個(gè)棧幀用來存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。當(dāng)線程調(diào)用一個(gè)Java方法時(shí),虛擬機(jī)壓入一個(gè)新的棧幀到該線程的Java棧中,當(dāng)該方法執(zhí)行完成,這個(gè)棧幀就從Java棧中彈出。我們平常所說的棧內(nèi)存(Stack)指的就是Java虛擬機(jī)棧。
    1.如果線程請求分配的棧容量超過Java虛擬機(jī)所允許的的最大容量,Java虛擬機(jī)會(huì)拋出StackOverflowError
    2.Java虛擬機(jī)棧動(dòng)態(tài)擴(kuò)展內(nèi)存時(shí),無法申請到足夠內(nèi)存,則會(huì)報(bào)OutOfMemoryError
  • 本地方法棧(Native Method Stack)
    與Java虛擬機(jī)棧類似,只不過其執(zhí)行的是native方法,該區(qū)域Java規(guī)范沒有強(qiáng)制要求支持,HotSpot VM將本地方法棧和Java虛擬機(jī)棧合二為一.本地方法棧也會(huì)拋出StackOverflowError或OutOfMemoryError
  • Java堆(Java Heap) 是被所有線程共享的運(yùn)行時(shí)內(nèi)存區(qū)域。Java堆用來存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存。Java堆存儲(chǔ)的對象被垃圾收集器管理,這些受管理的對象無需也無法顯示的銷毀。從內(nèi)存回收的角度,Java堆可以粗略的分為新生代和老年代。Java堆的容量可以是固定的,也可以動(dòng)態(tài)的擴(kuò)展。Java堆的所使用的內(nèi)存在物理上不需要連續(xù),邏輯上連續(xù)即可。堆中沒有足夠的內(nèi)存來完成實(shí)例分配,并且堆也無法進(jìn)行擴(kuò)展時(shí),則會(huì)拋出OutOfMemoryError異常。
  • 方法區(qū)(Method Area),其是被所有線程共享的運(yùn)行時(shí)內(nèi)存區(qū)域。用來存儲(chǔ)已經(jīng)被Java虛擬機(jī)加載的類的結(jié)構(gòu)信息
    image.png

    每一個(gè)Class文件中,都維護(hù)著一個(gè)常量池(這個(gè)保存在類文件里面,不要與方法區(qū)的運(yùn)行時(shí)常量池搞混),里面存放著編譯時(shí)期生成的各種字面值和符號引用;這個(gè)常量池的內(nèi)容,在類加載的時(shí)候,被復(fù)制到方法區(qū)的運(yùn)行時(shí)常量池 ;
    如果方法區(qū)的內(nèi)存空間不滿足內(nèi)存分配需求時(shí),Java虛擬機(jī)會(huì)拋出OutOfMemoryError異常

類的加載過程

類的生命周期


image.png

其中前五步為加載階段,而驗(yàn)證、準(zhǔn)備、解析又可概括為鏈接,所以類加載大致的一個(gè)流程為加載、鏈接、初始化,下面我將對這三部分逐個(gè)進(jìn)行詳細(xì)講解

  1. 加載
    將類class文件內(nèi)容加載到內(nèi)存中,然后把靜態(tài)數(shù)據(jù)轉(zhuǎn)換為方法區(qū)需要的數(shù)據(jù)結(jié)構(gòu) (是轉(zhuǎn)換,并不是將靜態(tài)數(shù)據(jù)加載到方法區(qū)) ,最后在堆中生成一個(gè)類的Class對象用來訪問方法區(qū)數(shù)據(jù)。其中class文件的表現(xiàn)形式就是字節(jié)數(shù)組,所以class文件的來源可以是本地文件、網(wǎng)絡(luò)、jar包等等。另外加載過程中需要有類加載器參與,在java中類ClassLoader就是類加載器。
  2. 鏈接
    1.驗(yàn)證: 驗(yàn)證加載進(jìn)來的class文件各種格式是否符合JVM的要求
    2.準(zhǔn)備:為靜態(tài)變量分配內(nèi)存,并賦予初始值。這個(gè)階段開發(fā)者定義的值不會(huì)賦予靜態(tài)變量并且也不會(huì)執(zhí)行靜態(tài)代碼塊。但如果為final修飾的變量會(huì)直接賦予開發(fā)者定義的值。
    3.解析:將常量池中的符號引用轉(zhuǎn)換為直接引用

符號引用:符號引用是以一組符號來描述所引用的目標(biāo),符號可以是任何的字面形式的字面量。
直接引用:是指向目標(biāo)的指針,偏移量或者能夠直接定位的句柄。該引用是和內(nèi)存中的而布局有關(guān)的,并且一定加載進(jìn)來的。

  1. 初始化
    初始化為類加載過程的最后一個(gè)階段,這個(gè)階段會(huì)為靜態(tài)變量進(jìn)行賦值,并且順序執(zhí)行靜態(tài)代碼塊

Java類執(zhí)行過程

Java類執(zhí)行過程

類初始化的4種情況

  1. 遇到new,getstatic,putstatic,invokestatic這失調(diào)字節(jié)碼指令時(shí),如果類沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。生成這4條指令的最常見的Java代碼場景是:使用new關(guān)鍵字實(shí)例化對象的時(shí)候、讀取或設(shè)置一個(gè)類的靜態(tài)字段(被final修飾、已在編譯器把結(jié)果放入常量池的靜態(tài)字段除外)的時(shí)候,以及調(diào)用一個(gè)類的靜態(tài)方法的時(shí)候。
  2. 使用java.lang.reflect包的方法對類進(jìn)行反射調(diào)用的時(shí)候,如果類沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。
  3. 當(dāng)初始化一個(gè)類的時(shí)候,如果發(fā)現(xiàn)其父類還沒有進(jìn)行過初始化,則需要先觸發(fā)其父類的初始化。
  4. 當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)主類。

Java引用及GC垃圾回收機(jī)制

Java引用及GC垃圾回收機(jī)制

Java Exception和Error 異常

JAVA基礎(chǔ)——異常詳解

Java I/O

Java IO面試題

Java泛型

Java泛型

Java反射

Java反射

Jni介紹

Java多線程

Android

Android 系統(tǒng)架構(gòu)

android_platform_architecture.png

Android系統(tǒng)架構(gòu)分為五層

  1. 應(yīng)用層
  2. 應(yīng)用框架層(Java API Framework),向應(yīng)用層提供api,例如:ActivityManager,LocationManager,PackageManager,ContentProvider等
  3. 系統(tǒng)運(yùn)行庫層(Native)
    1.C++程序庫 SQLite輕型關(guān)系型數(shù)據(jù)庫引擎
    2.Android運(yùn)行時(shí)庫 包括核心庫和ART虛擬機(jī)(Android5.0后,Dalvik虛擬機(jī)被ART取代)。核心庫提供了Java語言核心庫大多數(shù)功能,這樣開發(fā)者才可以使用Java語言編寫Android應(yīng)用。Dalvik虛擬機(jī)(DVM)中應(yīng)用每次運(yùn)行,字節(jié)碼都需要通過即時(shí)編譯器(Just In Time,JIT)轉(zhuǎn)化為機(jī)器碼,這會(huì)使應(yīng)用運(yùn)行效率降低。而ART,系統(tǒng)在安裝應(yīng)用時(shí)會(huì)進(jìn)行一次預(yù)編譯(Ahead Of Time,AOT),將字節(jié)碼預(yù)先編譯為機(jī)器碼并存儲(chǔ)在本地,這樣應(yīng)用每次運(yùn)行時(shí)就無需編譯了,運(yùn)行效率大大提高。
  4. 硬件抽象層(HAL) 隱藏了特定平臺(tái)的硬件接口細(xì)節(jié),為操作系統(tǒng)提供虛擬硬件平臺(tái)。
  5. Linux 內(nèi)核層(Linux Kernel) 系統(tǒng)的內(nèi)存管理,驅(qū)動(dòng)模型都依賴于該內(nèi)核。

JVM&DVM&ART區(qū)別

Android系統(tǒng)啟動(dòng)過程

Android系統(tǒng)啟動(dòng)流程
  1. 啟動(dòng)電源以及系統(tǒng)啟動(dòng)
    當(dāng)電源按下時(shí)引導(dǎo)芯片代碼開始從預(yù)定義的地方(固化在ROM)開始執(zhí)行。加載引導(dǎo)程序Bootloader到RAM,然后執(zhí)行。
  2. 引導(dǎo)程序Bootloader
    引導(dǎo)程序是在Android操作系統(tǒng)開始運(yùn)行前的一個(gè)小程序,它的主要作用是把系統(tǒng)OS拉起來并運(yùn)行。
  3. linux內(nèi)核啟動(dòng) (Linux 內(nèi)核層)
    內(nèi)核啟動(dòng)時(shí),設(shè)置緩存、被保護(hù)存儲(chǔ)器、計(jì)劃列表,加載驅(qū)動(dòng)。當(dāng)內(nèi)核完成系統(tǒng)設(shè)置,它首先在系統(tǒng)文件中尋找”init”文件,然后啟動(dòng)root進(jìn)程或者系統(tǒng)的第一個(gè)進(jìn)程。
  4. init進(jìn)程啟動(dòng)(Native層)
    init進(jìn)程解析init.rc文件孵化出Zygote進(jìn)程,Zygote進(jìn)程是Android系統(tǒng)第一個(gè)Java進(jìn)程(虛擬機(jī)進(jìn)程),zygote進(jìn)程是所有Java進(jìn)程的父進(jìn)程。
  5. Zygote進(jìn)程啟動(dòng)(Framework層)
    創(chuàng)建Java虛擬機(jī)并為Java虛擬機(jī)注冊JNI方法,創(chuàng)建服務(wù)端Socket,啟動(dòng)SystemServer進(jìn)程
  6. SystemServer進(jìn)程啟動(dòng)
    啟動(dòng)各種系統(tǒng)服務(wù),如ActivityManagerService,PackageManagerService,WindowManagerService等。
  7. Launcher啟動(dòng)
    AMS會(huì)啟動(dòng)Launcher。

Apk打包流程

myapp.apk
|------assets/   // 原封不動(dòng)打包
    ---lib/      // 原封不動(dòng)打包
        --armeabi-v7a
            - libconversation.so
    ---META-INF/    
        --CERT.RSA  // 這個(gè)文件保存了簽名和公鑰證書。
        --CERT.SF
        --MANIFEST.MF
    ---res/   // 所有XML文件都是二進(jìn)制
        --anim/
        --color/
        --drawable/
        --layout/
        --menu/
        --raw/
        --xml/
        ...
    ---AndroidManifest.xml  // 二進(jìn)制
    ---classes.dex  //  *.java(通過javac)--->*.class(通過dx工具)--->classes.dex
    ---resources.arsc // 記錄了所有的應(yīng)用程序資源目錄的信息,將其想象成是一個(gè)資源索引表,這個(gè)資源索引表在給定資源ID和設(shè)備配置信息(例如設(shè)備分辨率)的情況下,能夠在應(yīng)用程序的資源目錄中快速地找到最匹配的資源
  1. 通過aapt工具編譯所有資源文件(res目錄但不包括res/raw)生成R.java(但res/raw資源也會(huì)在R.java)供代碼引用資源。
    assets和res/raw不參與編譯,會(huì)原封不動(dòng)打包到apk,res目錄下的其他xml資源和AndroidManifest.xml都會(huì)編譯為二進(jìn)制。
    打包工具aapt負(fù)責(zé)編譯和打包資源,編譯完成之后,會(huì)生成一個(gè)resources.arsc文件和一個(gè)R.java,前者保存的是一個(gè)資源索引表,后者定義了各個(gè)資源ID常量。res/values會(huì)被直接保存在resource.arsc中。
    那為什么要將文本格式的xml轉(zhuǎn)為二進(jìn)制格式的xml呢?
    (1) 二進(jìn)制格式的XML文件占用空間更小。
    (2) 二進(jìn)制格式的XML文件解析速度更快。
  2. 通過aidl工具將aidl代碼轉(zhuǎn)化為java代碼
  3. 所有的java文件通過javac編譯為class字節(jié)碼文件(包括R.java和aidl生成的java類)
  4. 將生成的class文件和第三方j(luò)ar包通過dx工具生成classes.dex
  5. 通過apkbuilder(最新的sdk沒有該腳本,是通過sdklib.jar完成)將so文件,classes.dex、resources.arsc、res文件夾(res/raw資源被原裝不動(dòng)地打包進(jìn)APK之外,其它的資源都會(huì)被編譯或者處理)、Other Resources(assets文件夾)、AndroidManifest.xml打包成apk文件
    1.res/raw和assets的相同點(diǎn):
    兩者目錄下的文件在打包后會(huì)原封不動(dòng)的保存在apk包中,不會(huì)被編譯成二進(jìn)制。
    2.res/raw和assets的不同點(diǎn):
    res/raw中的文件會(huì)被映射到R.java文件中,訪問的時(shí)候直接使用資源ID即R.id.filename;assets文件夾下的文件不會(huì)被映射到R.java中,訪問的時(shí)候需要AssetManager類。
    res/raw不可以有目錄結(jié)構(gòu),而assets則可以有目錄結(jié)構(gòu),也就是assets目錄下可以再建立文件夾
  6. jarsigner對apk進(jìn)行簽名,可以進(jìn)行Debug和Release 簽名。
  7. 通過zipalign工具對apk中的未壓縮資源(圖片、視頻)進(jìn)行“對齊操作”,讓資源按4字節(jié)的邊界進(jìn)行對齊,使得資源訪問速度更快。(優(yōu)化思想類似結(jié)構(gòu)體變量分配時(shí)采用內(nèi)存對齊)

Activity相關(guān)

1. 談?wù)刼nSaveInstanceState(Bundle outState)

onSaveInstanceState一般在onStop之間調(diào)用,與onpause沒有調(diào)用時(shí)序關(guān)系

  1. 用戶行為要Activity關(guān)閉,不會(huì)執(zhí)行onSaveInstanceState方法.當(dāng)用戶按下HOME鍵時(shí)或啟動(dòng)其他程序時(shí)都會(huì)調(diào)用onSaveInstanceState
  2. onSaveInstanceStateonRestoreInstanceState不是成對執(zhí)行,onRestoreInstanceState轉(zhuǎn)屏?xí)r會(huì)執(zhí)行

2. onRestoreInstanceState(Bundle savedInstanceState)

onRestoreInstanceState在onResume之前調(diào)用,onCreate(Bundle)可能沒有數(shù)據(jù),但onRestoreInstanceState調(diào)用時(shí)一定會(huì)有.

  1. 其并不是和onSaveInstanceState成對回調(diào),如果Activity并沒有銷毀也不需要恢復(fù),這種情況下不會(huì)調(diào)用。
  2. 回調(diào)onRestoreInstanceState方法也會(huì)將保存的bundle傳給onCreate()方法中的bundle

3. onPause和onSaveInstanceState區(qū)別

作用不同,onPause適用做數(shù)據(jù)持久化存儲(chǔ),onSaveInstanceState適用于臨時(shí)狀態(tài)數(shù)據(jù)

4. 4種啟動(dòng)模式介紹

  • standard:標(biāo)準(zhǔn)模式 每次啟動(dòng)一個(gè)Activity,都會(huì)創(chuàng)建一個(gè)實(shí)例,放入啟動(dòng)他的Activity(除了啟動(dòng)它的Activity是SingleInstance情況)棧頂,即使已經(jīng)存在
  • singleTop:棧頂復(fù)用模式 如果新Activity已經(jīng)位于棧頂,那么activity不會(huì)重新創(chuàng)建,同時(shí)onNewIntent方法會(huì)被回調(diào).
  • singleTask:棧內(nèi)復(fù)用模式 只要該Activity在一個(gè)任務(wù)棧中存在,都不會(huì)重新創(chuàng)建,并回調(diào)onNewIntent方法.比如啟動(dòng)Activity A,先判斷是否存在其想要的任務(wù)棧,如果不存在,系統(tǒng)會(huì)先重新創(chuàng)建一個(gè)任務(wù)棧將A放入該任務(wù)棧;如果存在,這時(shí)會(huì)判斷該棧是否有實(shí)例存在,如果實(shí)例存在則將A調(diào)到棧頂并調(diào)用onNewIntent方法,如果實(shí)例不存在,就創(chuàng)建A實(shí)例并將其壓棧.
  • singleInstance:單實(shí)例模式 具有此模式的Activity只能單獨(dú)位于一個(gè)任務(wù)棧中,且此任務(wù)棧中只有唯一一個(gè)實(shí)例.
    TaskAffinity可以指定任務(wù)棧名稱,默認(rèn)為包名,其用來和SingleTask配對適用,其他模式?jīng)]有意義.
    各自適用場景
    SingleTop 棧頂復(fù)用,可能有多個(gè)Activity,但SingleTask棧中只有一個(gè).
    FLAG
    FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_SINGLE_TOP,作用和singleTask,singleTop作用相同,但指定FLAG的優(yōu)先級高.

IntentFilter匹配規(guī)則

  • 一個(gè)Intent只有同時(shí)匹配某個(gè)Activity的intent-filter中的action,category,data才算完全匹配.
  • 一個(gè)Activity可以有多個(gè)intent-filter,一個(gè)intent只要成功匹配任意一組就可以啟動(dòng)Activity.
    1.action匹配規(guī)則: intent-filter可以有多個(gè)action,但I(xiàn)ntent只能指定一個(gè)action,只要與intent-filter中一條action匹配,則action匹配
    2.category匹配規(guī)則:intent可以不指定category,則系統(tǒng)會(huì)為其添加default的category,intent可以指定多條category,但多條category必須在intent-filter包含,如果包含則category匹配
    3.data匹配規(guī)則:intent-filter中有data,則intent中必須指明data,并且該data需要和intent-filter中一個(gè)data圈圈匹配即可.

Fragment相關(guān)

1. Fragment生命周期

onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

  • onAttach():當(dāng)Fragment和Activity建立關(guān)聯(lián)是調(diào)用
  • onCreateView(): 當(dāng)Fragment創(chuàng)建視圖時(shí)調(diào)用
  • onActivityCreated():當(dāng)與Fragment關(guān)聯(lián)的Activity執(zhí)行完onCreate方法后調(diào)用
  • onDestroyView(): Fragment中布局被移除的時(shí)候
  • onDetach():與Activity解除關(guān)聯(lián)時(shí)調(diào)用

2. Fragment和Activity異同

  • 相同點(diǎn):他們都可包含布局,有自己的生命周期
  • 不同點(diǎn):Fragment依附在Activity上,聲明周期有宿主Activity而不是操作系統(tǒng)調(diào)用

3. 合適采用Fragment

  • Fragment性能高,可以解決Activity切換卡頓
  • Fragment對于大小屏適配非常合適

4. DialogFragment與AlertDialog的優(yōu)點(diǎn)

  • 轉(zhuǎn)屏DialogFragment可保持顯示,并可數(shù)據(jù)恢復(fù)
  • 有著和Activity幾乎一致的生命周期,更容易管理
  • 大小屏幕可以定制顯示狀態(tài),例如大屏幕將內(nèi)容直接顯示在Activity中,小屏幕顯示對話框

5. 同一個(gè)Activity不同F(xiàn)ragment的傳值

  1. Activity向Fragment傳值
    通過Activity中在添加Fragment之前調(diào)用setArgument傳入Bundle值,F(xiàn)ragment通過getArgument即可得到Bundle
  2. Fragment向Activity傳值
    采用接口回調(diào),F(xiàn)ragment中定義接口,Activity實(shí)現(xiàn)該接口,需要傳值時(shí)Fragment調(diào)用接口方法即可。Fragment中該接口的具體實(shí)現(xiàn)可以通過getActivity直接獲得,也可通過set方法傳入實(shí)現(xiàn)了該接口的對象。
  3. Fragment向Fragment傳值
    1. 先由Fragment傳值到Activity,再Activity傳至Fragment
    2. 得到另一個(gè)Fragment的對象,調(diào)用其方法即可,eg:左右兩個(gè)Fragment,左Fragment向右Fragment傳值
      LeftFragment
    // 或者調(diào)用findFramgentByTag方法
    RightFragment rightFragment =(RightFragment) getFragmentManager().findFragmentById(R.id.right_fragment);
    
    1. 同屬一個(gè)Activity,可以直接得到目標(biāo)Fragment的控件進(jìn)行操作

Service相關(guān)

1. Service生命周期

Service兩種啟動(dòng)方式生命周期

2. startService和bindService

  1. 啟動(dòng)Service

    context.startService()->onCreate()->onStartCommand()->Service運(yùn)行->(如果調(diào)用context.stopService)->onDestroy
    
    • 多次調(diào)用startService()只會(huì)走一次onCreate(),每次都會(huì)執(zhí)行onStartCommand()方法
    • 多次調(diào)用stopService之后的stopService不會(huì)有任何反應(yīng)
  2. 綁定Service

    context.bindService()->onCreate()->onBind()->Service綁定->(如果調(diào)用context.unbindService())->onUnbind()->onDestory();
    
    • 多次調(diào)用bindService(),只有第一次會(huì)走onCreate()和onBind(),之后的不會(huì)走任何方法
    • 多次調(diào)用unbindService(),之后的unbind會(huì)報(bào)錯(cuò)Caused by: java.lang.IllegalArgumentException: Service not registered: com.breeze.b.MainActivity$1@bdbf7e8
    • onBind返回null,onServiceConnected不會(huì)被回調(diào)
    • Service已經(jīng)被啟動(dòng),這時(shí)綁定Service解綁后又重新綁定,在onRebind方法返回值為true的情況,這時(shí)會(huì)執(zhí)行onRebind方法而不是調(diào)用bind
  3. Service可以同時(shí)處于綁定狀態(tài)和運(yùn)行狀態(tài),只要Service存在則再start或bind就不會(huì)回調(diào)onCreate方法,當(dāng)Service被start并且bind,需要同時(shí)stop和unbind才會(huì)回調(diào)onDestory()

  4. 啟動(dòng)方式和綁定方式區(qū)別

    1. 啟動(dòng)方式一旦啟動(dòng)Service,Service就一直運(yùn)行在后臺(tái),除非調(diào)用自身stopSelf()方法,或者context.stopService();綁定方式綁定Service后,如果客戶端調(diào)用unbindservice或者客戶端退出后Service都會(huì)銷毀,其與客戶端聲明周期有關(guān)
    2. 啟動(dòng)方式,調(diào)用方式無法與Service進(jìn)行交互,只能啟動(dòng)或關(guān)閉Service;綁定方式可以通過返回的IBinder接口調(diào)用服務(wù)端的代碼,從而實(shí)現(xiàn)交互。

3. Service如何和Activity進(jìn)行通信

通過bindService可以實(shí)現(xiàn)Activity調(diào)用Service的方法.通過廣播實(shí)現(xiàn)Service向Activity發(fā)送消息

4. IntentService

用于后臺(tái)執(zhí)行耗時(shí)任務(wù),執(zhí)行完成并可自動(dòng)停止.比線程優(yōu)先級高. 實(shí)現(xiàn)原理是通過HandlerThread消息機(jī)制.

5. Android8.0不允許啟動(dòng)后臺(tái)Service

切換為前臺(tái)Service,但必須有通知.或者通過JobIntentService實(shí)現(xiàn).

6. 如何保證Service不被殺死

  • Service的onStartCommand()中設(shè)置flag為START_STICKY,在運(yùn)行onStartCommand后service進(jìn)程被kill后,那將保留在開始狀態(tài),但是不保留那些傳入的intent。不久后service就會(huì)再次嘗試重新創(chuàng)建,因?yàn)楸A粼陂_始狀態(tài),在創(chuàng)建 service后將保證調(diào)用onstartCommand。
  • 提升Service優(yōu)先級為前臺(tái)Service
  • Service執(zhí)行onDestory()方法時(shí)發(fā)送廣播,接收到廣播時(shí)重啟Service
  • 系統(tǒng)級應(yīng)用

Broadcast相關(guān)

廣播的類型主要分為5類:

  • 普通廣播(Normal Broadcast)
  • 系統(tǒng)廣播(System Broadcast)
  • 有序廣播(Ordered Broadcast)
  • 粘性廣播(Sticky Broadcast)
  • App應(yīng)用內(nèi)廣播(Local Broadcast)

1. 普通廣播(Normal Broadcast)

普通廣播接收沒有先后順序.最常用,分為動(dòng)態(tài)注冊和靜態(tài)注冊。但靜態(tài)注冊在Android8.0上做了限制,只能接收部分系統(tǒng)廣播.

2. 系統(tǒng)廣播(System Broadcast)

  • Android中內(nèi)置了多個(gè)系統(tǒng)廣播:只要涉及到手機(jī)的基本操作(如開機(jī)、網(wǎng)絡(luò)狀態(tài)變化、拍照等等),都會(huì)發(fā)出相應(yīng)的廣播
  • 每個(gè)廣播都有特定的Intent - Filter(包括具體的action),Android常用系統(tǒng)廣播action如下:
系統(tǒng)操作 action
監(jiān)聽網(wǎng)絡(luò)變化 android.net.conn.CONNECTIVITY_CHANGE
關(guān)閉或打開飛行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充電時(shí)或電量發(fā)生變化 Intent.ACTION_BATTERY_CHANGED
系統(tǒng)啟動(dòng)完成后(僅廣播一次) Intent.ACTION_BOOT_COMPLETED
屏幕被關(guān)閉 Intent.ACTION_SCREEN_OFF
屏幕被打開 Intent.ACTION_SCREEN_ON

3. 有序廣播(Ordered Broadcast)

  • 發(fā)送出去的廣播被廣播接收者按照先后順序接收,
    廣播接受者接收廣播的順序規(guī)則(同時(shí)面向靜態(tài)和動(dòng)態(tài)注冊的廣播接受者)
    按照Priority屬性值從大-小排序;Priority 取值范圍-1000~+1000,默認(rèn)為0
    Priority屬性相同者,動(dòng)態(tài)注冊的廣播優(yōu)先;
  • 先接收的廣播接收者可以對廣播進(jìn)行截?cái)嗤ㄟ^調(diào)用 abortBroadcast();,即后接收的廣播接收者不再接收到此廣播;
    先接收的廣播接收者可以對廣播進(jìn)行修改通過setResultxxx(),getResultxxx(),那么后接收的廣播接收者將接收到被修改后的廣播
  • 有序廣播的使用過程與普通廣播非常類似,差異僅在于廣播的發(fā)送方式:sendOrderedBroadcast(intent);

4. 粘性廣播(Sticky Broadcast)

粘性消息在發(fā)送后就一直存在于系統(tǒng)的消息容器里面,等待對應(yīng)的處理器去處理,如果暫時(shí)沒有處理器處理這個(gè)消息則一直在消息容器里面處于等待狀態(tài),粘性廣播的Receiver如果被銷毀,那么下次重建時(shí)會(huì)自動(dòng)接收到消息數(shù)據(jù)。(在 android 5.0/api 21中deprecated,不再推薦使用)

耳機(jī)插拔廣播Intent.ACTION_HEADSET_PLUG就是粘性廣播

5. App應(yīng)用內(nèi)廣播(Local Broadcast)

Android中的廣播可以跨App直接通信(exported對于有intent-filter情況下默認(rèn)值為true).

存在的問題

  • 其他App針對性發(fā)出與當(dāng)前App intent-filter相匹配的廣播,由此導(dǎo)致當(dāng)前App不斷接收廣播并處理;
  • 其他App注冊與當(dāng)前App一致的intent-filter用于接收廣播,獲取廣播具體信息;
    即會(huì)出現(xiàn)安全性 & 效率性的問題。

App應(yīng)用內(nèi)廣播可理解為一種局部廣播,廣播的發(fā)送者和接收者都同屬于一個(gè)App。相比于全局廣播(普通廣播),App應(yīng)用內(nèi)廣播優(yōu)勢體現(xiàn)在:安全性高 & 效率高。通常采用如下兩種方式實(shí)現(xiàn)本地廣播

  1. 增設(shè)相應(yīng)權(quán)限permission或者通過intent.setPackage(packageName)指定包名接收
  2. v4包下LocalBroadcastManager實(shí)現(xiàn)localBroadcastManager = LocalBroadcastManager.getInstance(this);獲取其實(shí)例,通過其發(fā)送廣播和接收廣播。

ContentProvider相關(guān)

ContentProvider四大組件之一,嚴(yán)格意義不屬于數(shù)據(jù)存儲(chǔ),它實(shí)現(xiàn)存儲(chǔ)方式是通過其他存儲(chǔ)方式實(shí)現(xiàn)(文件存儲(chǔ),SharedPrefernces,SQLite數(shù)據(jù)).ContentProvider主要是用于不同應(yīng)用之間數(shù)據(jù)共享.

數(shù)據(jù)存儲(chǔ)方式有哪些?

  1. File文件存儲(chǔ): 寫入和讀取文件的方法和Java中實(shí)現(xiàn)I/O的程序一樣
  2. SharedPreferences: 輕型數(shù)據(jù)存儲(chǔ)方式,常用與存儲(chǔ)一些簡單配置信息,本質(zhì)是通過XML文件存儲(chǔ)鍵值對數(shù)據(jù)
  3. SQLite數(shù)據(jù)存儲(chǔ):輕型關(guān)系型數(shù)據(jù)庫,速度快,占用資源少,適合存儲(chǔ)大量復(fù)雜關(guān)系型數(shù)據(jù)
  4. ContentProvider: 實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)與共享
  5. 網(wǎng)絡(luò)存儲(chǔ) 使用較少,暫不記錄
    Android數(shù)據(jù)存儲(chǔ)的5種方式

1. SharedPreferences適用情形?適用中需要注意什么?

適用情形上面已說明.SharedPreferences底層通過讀/寫XML文件來實(shí)現(xiàn),并發(fā)容易出問題.從而可靠性下降

Android進(jìn)程和線程區(qū)別

  • 進(jìn)程就是一個(gè)應(yīng)用程序的執(zhí)行過程,它是一個(gè)動(dòng)態(tài)的概念
  • 線程是進(jìn)程中的一部分,起始CPU調(diào)度的最小單元
    進(jìn)程至少包含一個(gè)線程,及主線程,Android中稱為UI線程。線程之間可以共享進(jìn)程資源,但進(jìn)程與進(jìn)程彼此獨(dú)立。
  • 一般一個(gè)應(yīng)用對應(yīng)一個(gè)進(jìn)程,但也可以通過process屬性開啟多進(jìn)程模式
  • 線程是有限個(gè):不可無限制的產(chǎn)生,且線程的產(chǎn)生和銷毀都是要一定開銷。

IPC

1. 為什么要進(jìn)行IPC,多進(jìn)程可能出現(xiàn)什么問題

由于每個(gè)應(yīng)用都運(yùn)行在獨(dú)立的虛擬機(jī),不同虛擬機(jī)內(nèi)存地址空間不同,從而不同虛擬機(jī)訪問同一個(gè)對象會(huì)產(chǎn)生多個(gè)副本,故涉及到內(nèi)存共享數(shù)據(jù),都會(huì)共享失敗,一般會(huì)造成如下幾個(gè)問題。

  1. 靜態(tài)成員和單例模式完全失效
  2. 線程同步完全失效
    不同進(jìn)程的鎖永遠(yuǎn)不會(huì)是同一個(gè)對象
  3. SharedPreference可靠性下降
    SharedPreference不支持兩個(gè)進(jìn)程同時(shí)執(zhí)行寫操作,否則會(huì)引起一定概率的數(shù)據(jù)丟失
  4. Application多次創(chuàng)建

2. Serializable接口和Parcelable接口的區(qū)別

  • Parcelable和Serializable都是實(shí)現(xiàn)序列化并且都可以用于Intent間傳遞數(shù)據(jù)
  • Serializable是Java的實(shí)現(xiàn)方式,會(huì)頻繁的IO操作,所以消耗比較大,但是實(shí)現(xiàn)方式簡單。適用本地存儲(chǔ)和網(wǎng)絡(luò)傳輸。
  • Parcelable是Android提供的方式,其是將一個(gè)對象進(jìn)行效率比較高,但是實(shí)現(xiàn)起來復(fù)雜一些 。
    二者的選取規(guī)則是:內(nèi)存序列化上選擇Parcelable, 存儲(chǔ)到設(shè)備或者網(wǎng)絡(luò)傳輸上選擇Serializable(當(dāng)然Parcelable也可以但是稍顯復(fù)雜)

3. Android中為何新增Binder來作為主要的IPC方式?

  1. 傳輸效率高、可操作性強(qiáng):傳輸效率主要影響因素是內(nèi)存拷貝的次數(shù),拷貝次數(shù)越少,傳輸速率越高。從Android進(jìn)程架構(gòu)角度分析:對于消息隊(duì)列、Socket和管道來說,數(shù)據(jù)先從發(fā)送方的緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,再從內(nèi)核緩存區(qū)拷貝到接收方的緩存區(qū),一共兩次拷貝,共享內(nèi)存雖然無需拷貝,但控制復(fù)雜,難以使用.
  2. 安全性 傳統(tǒng)Linux IPC的接收方無法獲得對方進(jìn)程可靠的UID/PID,從而無法鑒別對方身份;而Binder機(jī)制為每個(gè)進(jìn)程分配了UID/PID且在Binder通信時(shí)會(huì)根據(jù)UID/PID進(jìn)行有效性檢測。

4. Binder機(jī)制?

以AIDL運(yùn)行機(jī)制介紹


  1. 服務(wù)端中的Service給與其綁定的客戶端提供Binder對象
  2. 客戶端通過AIDL接口中的asInterface()將這個(gè)Binder對象轉(zhuǎn)換為代理Proxy,通過它發(fā)起RPC請求。客戶端發(fā)起請求時(shí)會(huì)掛起當(dāng)前線程,并將參數(shù)寫入data然后調(diào)用transact()方法,RPC請求會(huì)通過系統(tǒng)底層封裝后由服務(wù)端的onTransact()處理,并將結(jié)果寫入reply,這個(gè)過程運(yùn)行在服務(wù)端中的Binder線程池,最后返回調(diào)用結(jié)果并喚醒客戶端線程。


    image.png

5. 是否了解AIDL?原理是什么?如何優(yōu)化多模塊都使用AIDL的情況

當(dāng)有多個(gè)業(yè)務(wù)模塊都需要AIDL來進(jìn)行IPC,此時(shí)需要為每個(gè)模塊創(chuàng)建特定的aidl文件,那么相應(yīng)的Service就會(huì)很多。必然會(huì)出現(xiàn)系統(tǒng)資源耗費(fèi)嚴(yán)重、應(yīng)用過度重量級的問題。解決辦法是建立Binder連接池,即將每個(gè)業(yè)務(wù)模塊的Binder請求統(tǒng)一轉(zhuǎn)發(fā)到一個(gè)遠(yuǎn)程Service中去執(zhí)行,從而避免重復(fù)創(chuàng)建Service

每個(gè)業(yè)務(wù)模塊創(chuàng)建自己的AIDL接口并實(shí)現(xiàn)此接口,然后向服務(wù)端提供自己的唯一標(biāo)識(shí)和其對應(yīng)的Binder對象。服務(wù)端只需要一個(gè)Service,服務(wù)器提供一個(gè)queryBinder接口,它會(huì)根據(jù)業(yè)務(wù)模塊的特征來返回相應(yīng)的Binder對像,不同的業(yè)務(wù)模塊拿到所需的Binder對象后就可進(jìn)行遠(yuǎn)程方法的調(diào)用了

6. IPC有哪些,各自優(yōu)缺點(diǎn)適用場景

  1. Intent數(shù)據(jù)傳遞
    使用Bundle進(jìn)行傳遞數(shù)據(jù)在Activity,Service,BroadcastReceiver中,數(shù)據(jù)支持類型有
    1.8種基本類型及數(shù)組
    2.String(實(shí)現(xiàn)了Serializable),CharSequence及對應(yīng)數(shù)組
  2. 是實(shí)現(xiàn)了Serializable或者Parcelable的對象或數(shù)組
    Bundle支持傳輸?shù)淖畲髷?shù)據(jù)為1M,甚至更小,因?yàn)锽inder會(huì)話緩沖區(qū)大小限制為1M,它是被所有處于Binder會(huì)話的進(jìn)程鎖共享的。
  3. 文件共享 (適合對并發(fā)要求不高的進(jìn)程之間使用)
    • ObjectOutputStream/ObjectInputStrem實(shí)現(xiàn)讀寫對象到文件 文件可以是各種格式,只要雙方約定好即可
    • 并發(fā)讀寫容易引起問題
  4. SharedPreference (不建議使用)
    • 本質(zhì)上也是文件共享的一種
    • 系統(tǒng)對其有緩存策略,即內(nèi)存中存在其緩存,多進(jìn)程對其讀寫不可靠
    • 高并發(fā)容易引起數(shù)據(jù)丟失
  5. 基于Binder的Messager和AIDL
  6. Socket
  7. LocalSocket
    LocalSocket解決的是同一臺(tái)主機(jī)上不同進(jìn)程間互相通信的問題。其相對于網(wǎng)絡(luò)通信使用的socket不需要經(jīng)過網(wǎng)絡(luò)協(xié)議棧,不需要打包拆包、計(jì)算校驗(yàn),自然的執(zhí)行效率也高。與大名鼎鼎的binder機(jī)制作用一樣,都在Android系統(tǒng)中作為IPC通信手段被廣泛使用

android下使用localsocket可以實(shí)現(xiàn)C與C,C與JAVA,JAVA與JAVA進(jìn)程間通信

IPC優(yōu)缺點(diǎn)對比

1. MotionEvent是什么?包含幾種事件?什么條件下會(huì)產(chǎn)生?

MotionEvent是手指觸摸屏幕鎖產(chǎn)生的一系列事件。包含的事件有:
ACTION_DOWN:手指剛接觸屏幕
ACTION_MOVE:手指在屏幕上滑動(dòng)
ACTION_UP:手指在屏幕上松開的一瞬間
ACTION_CANCEL:手指保持按下操作,并從當(dāng)前控件轉(zhuǎn)移到外層控件時(shí)會(huì)觸發(fā)

2. View的事件分發(fā)機(jī)制?

觸摸事件傳遞順序是Activity,ViewGroup,View
而在事件分發(fā)過程中,涉及到三個(gè)最重要的方法:

  • dispatchTouchEvent()
    事件能夠傳遞到當(dāng)前View,則該方法一定調(diào)用,返回結(jié)果受當(dāng)前View的onTouchEvent和子View的dispatchTouchEvent方法影響,表示是否消耗事件.
  • onInterceptTouchEvent()
    判斷是否攔截某個(gè)事件,如果當(dāng)前View攔截了某個(gè)事件,那么在同一個(gè)事件序列當(dāng)中,此方法不會(huì)被再次調(diào)用,返回值表示是否攔截當(dāng)前事件序列.
  • onTouchEvent
    在dispatchTouchEvent方法中調(diào)用,用來處理點(diǎn)擊事件,返回結(jié)果表示是否消耗當(dāng)前事件,如果不消耗則統(tǒng)一事件序列中,當(dāng)前View無法再次接收到事件.
    整體分發(fā)過程如下
public boolean dispatchTouchEvent(MotionEvent ev) {
    //consume 表示事件是否在該View中消耗
    boolean consume = false;
    //是否當(dāng)前View攔截事件,如果攔截,則調(diào)用本View的onTouchEvent方法,不會(huì)再下發(fā)事件序列中的其他事件
    if (onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);  
    } else {
        //如果沒有攔截事件,則會(huì)遍歷手指按下時(shí)接觸的所有子View(不是容器的所有子View,而是該容器中down事件所接觸的子View)進(jìn)行遍歷派發(fā)事件,事件如果有消耗則退出循環(huán),如果所有字View均沒有消耗,則此時(shí)consume為false
        for(int i=0; i<childs.length && !consume;i++) {
            consume = childs[i].dispatchTouchEvent(ev);
        }
        
    }
    如果派發(fā)給所有字view事件依然沒有消耗,則有本View的onTouchEvent來進(jìn)行處理,如果依然返回false,則當(dāng)前View沒有消耗事件,進(jìn)一步上發(fā)事件給父View,如果頂層View依然沒有處理,則Activity的onTouchEvent會(huì)被調(diào)用.
    if(!consume) {
        consume = onTouchEvent(ev);       
    }
    return consume;
}
  • ViewGroup在ACTION_DOWN事件時(shí),onInterceptTouchEvent方法返回true,則所有子View都無法接收到事件,只在ACTION_MOVE或ACTION_UP時(shí),onInterceptTouchEvent方法返回true,上次接收到事件的子View會(huì)接收了ACTION_CANCEL事件
  • ACTION_DOWN時(shí),所有View都不消耗事件時(shí),則Activity不會(huì)再繼續(xù)下事件給View.
  • View的onTouchListener的onTouch方法>onTouchEvent>onClickListener的onClick方法
  • 子View可通過requestDisallowInterceptTouchEvent干預(yù)父View的事件攔截,除了ACTION_DOWN事件.
    具體意思就是如果父View在ACTION_DOWN時(shí)已經(jīng)攔截了事件,那么子View無論如何都不會(huì)得到任何事件. 還有一種情況是,子View雖然禁止攔截事件,但自己不消耗事件,那么事件序列依然不會(huì)給其下發(fā).

Android 子線程訪問主線線程更新UI && Handler原理

1. 為什么Android無法在子線程更新UI

實(shí)質(zhì)上是為了避免多線程并發(fā)問題,容易引起界面更新錯(cuò)亂。如果通過加鎖的機(jī)制實(shí)現(xiàn)同步,則非常消耗性能。

2. 其他線程訪問UI線程的5種方式:

  1. Activity.runOnUiThread(Runnable);
  2. View.post(Runnable);
  3. View.postDelayed(Runnable,long);
  4. Handler;
  5. AsyncTask。
    上述5種方式包括AsyncTask本質(zhì)都是通過Handler來實(shí)現(xiàn)的

3. Handler原理

Handler原理如下:

一個(gè)線程通過Looper.prepare會(huì)創(chuàng)建唯一的Looper對象,創(chuàng)建Looper中就會(huì)創(chuàng)建一個(gè)消息隊(duì)列MessageQueue(數(shù)據(jù)結(jié)構(gòu)是單鏈表隊(duì)列)。創(chuàng)建Handler時(shí)會(huì)與當(dāng)前線程的Looper及MessageQueue綁定,調(diào)用sendMessage方法發(fā)送消息Message,該消息Message會(huì)入隊(duì)到MessageQueue。線程調(diào)用Looper.loop方法就會(huì)循環(huán)從MessageQueue中取消息并將該消息通過Handler的dispatchMessage方法將Message交由Handler處理。Looper負(fù)責(zé)一直從消息隊(duì)列拿消息交由Handler來處理消息。

一個(gè)線程只能有一個(gè)Looper對象,并且有一個(gè)消息隊(duì)列,但可以有多個(gè)Handler對象。

4. 主線程中的Looper.loop()一直無限循環(huán)為什么不會(huì)造成ANR?

造成ANR的原因一般有兩種:

  1. 當(dāng)前的事件沒有機(jī)會(huì)得到處理(即主線程正在處理前一個(gè)事件,沒有及時(shí)的完成或者looper被某種原因阻塞住了)
  2. 當(dāng)前的事件正在處理,但沒有及時(shí)完成

當(dāng)只在UI線程延時(shí)很長時(shí)間,是不會(huì)引起ANR,如果按鈕點(diǎn)擊后延時(shí),按鈕則彈起后無法恢復(fù),直到延時(shí)結(jié)束,如果按鈕彈起,這時(shí)還要處理其他事件則會(huì)引起ANR

因?yàn)锳ndroid 的是由事件驅(qū)動(dòng)的,looper.loop() 不斷地接收事件、處理事件,每一個(gè)點(diǎn)擊觸摸或者說Activity的生命周期都是運(yùn)行在 Looper.loop() 的控制之下,如果它停止了,應(yīng)用也就停止了。只能是某一個(gè)消息或者說對消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就說我們的代碼其實(shí)就是在這個(gè)循環(huán)里面去執(zhí)行的,當(dāng)然不會(huì)阻塞了。

5. HandlerThread

HandlerThread繼承自Thread,它就是一個(gè)線程,不過做了對looper的封裝。

HandlerThread的run方法中開始執(zhí)行了Looper.prepare方法,在run方法結(jié)尾調(diào)用了Looper.loop方法,Looper.loop之前回調(diào)onLooperPrepared方法供子類可以進(jìn)行一些設(shè)置。當(dāng)在其他線程創(chuàng)建Handler時(shí),需要傳入HandlerThread的getLooper方法,這樣該Handler才與該線程的Looper綁定了,從而Handler發(fā)送的消息才會(huì)進(jìn)入該線程的MessageQueue中,Looper.loop取得消息才可以交由該Handler處理。

當(dāng)線程無需處理消息時(shí),可通過HandlerThread的quit或者quitSafely方法退出消息循環(huán),從而run方法執(zhí)行完成,該線程也就終止了。quit和quitSafely區(qū)別在于quit消息隊(duì)列中的全部消息,而quitSafely只清除消息隊(duì)列中的延遲消息。

6. AsyncTask相比Handler有什么優(yōu)點(diǎn)?不足呢?

  • Handler
    使用的優(yōu)點(diǎn):結(jié)構(gòu)清晰,功能定義明確
    對于多個(gè)后臺(tái)任務(wù)時(shí),簡單,清晰
    使用的缺點(diǎn):在單個(gè)后臺(tái)異步處理時(shí),顯得代碼過多,結(jié)構(gòu)過于復(fù)雜(相對性)
  • AsyncTask
    使用的優(yōu)點(diǎn):簡單,快捷,過程可控
    使用的缺點(diǎn):在使用多個(gè)異步操作和并需要進(jìn)行Ui變更時(shí),就變得復(fù)雜起來.

7. 使用AsyncTask需要注意什么?

一個(gè)異步對象只能調(diào)用一次execute()方法

線程池和阻塞隊(duì)列

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這是我近段時(shí)間收集的面試題,獻(xiàn)給打算年后找工作的同學(xué)們。文中涉及的知識(shí)比較廣也可能比較零散,并且一些較為基礎(chǔ)的知識(shí)...
    01_小小魚_01閱讀 955評論 0 35
  • Java部分 1.GC是什么? 為什么要有GC? GC是垃圾收集的意思(Gabage Collection),內(nèi)存...
    01_小小魚_01閱讀 231評論 0 3
  • Java部分 1.GC是什么? 為什么要有GC? GC是垃圾收集的意思(Gabage Collection),內(nèi)存...
    Near尼爾閱讀 1,534評論 0 21
  • Java SE 基礎(chǔ): 封裝、繼承、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個(gè)獨(dú)立的整體,并盡...
    Jayden_Cao閱讀 2,234評論 0 8
  • 安裝完成后運(yùn)行桌面快捷方式,彈出注冊窗口選擇Activate>License Server>輸入http://xi...
    1_ming閱讀 2,209評論 0 0

友情鏈接更多精彩內(nèi)容