、主要分為以下幾部分:
(1)java面試題
(2)Android面試題
(3)高級(jí)開(kāi)發(fā)技術(shù)面試題
(4)跨平臺(tái)Hybrid 開(kāi)發(fā)
一、java面試題
熟練掌握java是很關(guān)鍵的,大公司不僅僅要求你會(huì)使用幾個(gè)api,更多的是要你熟悉源碼實(shí)現(xiàn)原理,甚至要你知道有哪些不足,怎么改進(jìn),還有一些java有關(guān)的一些算法,設(shè)計(jì)模式等等。
(一) java基礎(chǔ)面試知識(shí)點(diǎn)
java中==和equals和hashCode的區(qū)別
equals是Object的方法可以重寫(xiě) ,僅僅用來(lái)判斷兩個(gè)對(duì)象的值
==是操作符,主要用來(lái)判斷兩個(gè)對(duì)象的地址
hashCode用來(lái)獲取對(duì)象的哈希碼,用于確定對(duì)象在哈希表中的位置。
int、char、long各占多少字節(jié)數(shù)
一個(gè)字節(jié)占8位:
char:1個(gè)字節(jié),8位
short:2字節(jié),16位
int:4個(gè)字節(jié),32位
long:8個(gè)字節(jié), 64位
int與integer的區(qū)別
int是值類(lèi)型,Integer是引用類(lèi)型
Integer必須實(shí)例化后才能使用,而int不需要
int默認(rèn)是0,Integer默認(rèn)是null
探探對(duì)java多態(tài)的理解
多態(tài)的定義:同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式
多態(tài)的好處:消除類(lèi)型之間的耦合關(guān)系
多態(tài)的條件:要有繼承,要有重寫(xiě),父類(lèi)引用指向子類(lèi)對(duì)象
String、StringBuffer、StringBuilder區(qū)別
1:是否從可變的角度
String是final類(lèi)既不允許繼承也不允許改變對(duì)象
StringBuffer、StringBuilder 都繼承AbstractStringBuilder,沒(méi)有final修飾,對(duì)象可變
2、從線程安全角度來(lái)看
String因?yàn)楸籪inal修飾因此不可變,自然也就是線程安全的
StringBuffer 內(nèi)部append方法添加了同步鎖synchronized ,因此它也是線程安全的
StringBuilder內(nèi)部append方法沒(méi)有同步鎖,因此它不是線程安全的
什么是內(nèi)部類(lèi)??jī)?nèi)部類(lèi)的作用
定義:可以把一個(gè)類(lèi)定義到另一個(gè)類(lèi)的內(nèi)部,當(dāng)作外部類(lèi)的成員,這個(gè)類(lèi)就叫做內(nèi)部類(lèi)
作用:根據(jù)內(nèi)部類(lèi)的分類(lèi)說(shuō)一下各個(gè)內(nèi)部類(lèi)的作用
? ? ? ? 成員內(nèi)部類(lèi):可以訪問(wèn)外部類(lèi)的所有方法、屬性、甚至包括私有方法屬性。
? ? ? ? 局部?jī)?nèi)部類(lèi):定義在某個(gè)方法或者一個(gè)作用域里面的類(lèi),只能訪問(wèn)該方法或者作用域里面的對(duì)象
? ? ? ? 靜態(tài)內(nèi)部類(lèi):不依賴于外部類(lèi)而存在,只能訪問(wèn)外部類(lèi)的靜態(tài)成員
? ? ? ? 匿名內(nèi)部類(lèi):無(wú)名內(nèi)部類(lèi),常見(jiàn)于定義控件事件中
抽象類(lèi)和接口區(qū)別
默認(rèn)方法實(shí)現(xiàn):抽象類(lèi)可以有默認(rèn)方法實(shí)現(xiàn),接口沒(méi)有
訪問(wèn)修飾符:抽象類(lèi)public、protected;接口只能public
構(gòu)造器:抽象類(lèi)可以有構(gòu)造器,接口沒(méi)有
抽象類(lèi)的意義
1、為子類(lèi)提供一個(gè)公共的類(lèi)型
2、封裝子類(lèi)中重復(fù)的方法和屬性
3、定義有抽象方法,子類(lèi)雖然有不同的實(shí)現(xiàn),但該方法的定義是一致的
抽象類(lèi)與接口的應(yīng)用場(chǎng)景
如果你擁有一些方法并且想讓它們中的一些有默認(rèn)實(shí)現(xiàn),那么使用抽象類(lèi)吧。
如果你想實(shí)現(xiàn)多重繼承,那么你必須使用接口。由于Java不支持多繼承,子類(lèi)不能夠繼承多個(gè)類(lèi),但可以實(shí)現(xiàn)多個(gè)接口。因此你就可以使用接口來(lái)解決它。
如果基本功能在不斷改變,那么就需要使用抽象類(lèi)。如果不斷改變基本功能并且使用接口,那么就需要改變所有實(shí)現(xiàn)了該接口的類(lèi)
抽象類(lèi)是否可以沒(méi)有方法和屬性?
可以
接口的意義
使用接口可以達(dá)到一定的解耦和作用,比如:我們?cè)诮涌谥卸x一個(gè)變量,所有繼承它的子類(lèi),都用到這個(gè)變量,那么當(dāng)需求改變時(shí)只需要修改著一個(gè)變量即可;
解決java中不能多繼承的缺點(diǎn)
泛型中extends和super的區(qū)別
<? extends T>限定參數(shù)類(lèi)型的上界:參數(shù)類(lèi)型必須是T或T的子類(lèi)型
<? super T> 限定參數(shù)類(lèi)型的下界:參數(shù)類(lèi)型必須是T或T的超類(lèi)型
父類(lèi)的靜態(tài)方法能否被子類(lèi)重寫(xiě)
父類(lèi)的靜態(tài)方法可以被子類(lèi)繼承,但是不能被重寫(xiě)
進(jìn)程和線程的區(qū)別
進(jìn)程是指一個(gè)執(zhí)行單元,一般指一個(gè)程序或者應(yīng)用
線程是cpu調(diào)度的最小單元,主要用于執(zhí)行耗時(shí)操作,一個(gè)進(jìn)程可以有多個(gè)線程
final,finally,finalize的區(qū)別
final:修飾符,使用final修飾的類(lèi)、方法、屬性不能被繼承、重寫(xiě)和改變變量的值
finally:作為異常處理的一部分,通常配合try catch一起使用,標(biāo)識(shí)最終被執(zhí)行的意思
finalize:Object的一個(gè)方法,意為假定該對(duì)象被回收,什么意思呢?我們先了解一下java中垃圾回收器(GC)的工作原理,我們都知道java中的GC只回收J(rèn)VM分配的內(nèi)存,如果對(duì)象使用jni底層c、c++來(lái)進(jìn)行分配的內(nèi)存那么finalize就是負(fù)責(zé)回收這部分內(nèi)存的,在GC工作時(shí)先調(diào)用finalize()方法,并在下一次垃圾回收發(fā)生,才真正回收該對(duì)象占用的內(nèi)存。
Serializable 和Parcelable 的區(qū)別
????????????????????????????????????Serializable? ? ? ? ?????????????????????????Parcelable? ? ? ? ? ? ? ? ? ?
? ? ? ? ? 平臺(tái):? ? ? ? ? ? ? ?java自帶? ? ? ? ? ? ? ? ????????????????????????Android自帶
序列化原理:? ? ? ? ? ? ? ?將對(duì)象轉(zhuǎn)化為可存儲(chǔ)的狀態(tài) ????????將對(duì)象進(jìn)行分解,分解的部門(mén)都是傳遞可支持的數(shù)據(jù)類(lèi)型
? ? ? ?優(yōu)缺點(diǎn):? ? ? ? ? ? ? ?簡(jiǎn)單但是效率低? ? ? ? ? ? ? ? ? ? ? ? ? ?高效但是使用復(fù)雜
靜態(tài)屬性和靜態(tài)方法是否可以被繼承?是否可以被重寫(xiě)?以及原因?
可以被繼承,但是不能被重寫(xiě),靜態(tài)屬性和方法只屬于當(dāng)前類(lèi)。通過(guò)類(lèi)名.屬性,類(lèi)名.方法()調(diào)用
靜態(tài)內(nèi)部類(lèi)的設(shè)計(jì)意圖
非靜態(tài)內(nèi)部類(lèi)在創(chuàng)建的時(shí)候會(huì)持有外部的引用,而靜態(tài)內(nèi)部類(lèi)沒(méi)有
因此非靜態(tài)內(nèi)部類(lèi)有兩個(gè)重要的作用:
1、它的創(chuàng)建不需要外圍,不支持外部類(lèi)的引用
2、靜態(tài)內(nèi)部類(lèi)不能訪問(wèn)外部任何非靜態(tài)屬性和方法
談?wù)剬?duì)kotlin的理解
1、kotlin是一門(mén)靜態(tài)語(yǔ)言,支持多種平臺(tái) 移動(dòng)端、服務(wù)端、以及瀏覽器端
2、空安全的語(yǔ)言,支持泛型,空指針的判斷,支持與java進(jìn)行完全的交互
3、代碼末尾沒(méi)有分號(hào)、被調(diào)用的方法放在上邊等特點(diǎn)
閉包和局部?jī)?nèi)部類(lèi)的區(qū)別
閉包是一個(gè)可調(diào)用的對(duì)象,它包含了一些信息,這些信息來(lái)自創(chuàng)建它的作用域,就是我們常見(jiàn)的lambda 表達(dá)式()=>{ 作用域 };
局部?jī)?nèi)部類(lèi)是定義在某個(gè)方法或者某個(gè)局部中的類(lèi),它只能訪問(wèn)該方法中的變量
string 轉(zhuǎn)換成 integer的方式及原理
1、循環(huán)調(diào)用string的每個(gè)字符的十進(jìn)制數(shù)值
2、通過(guò)*=或/=進(jìn)行計(jì)算拼接
3、最后判斷是否為正負(fù)值,返回結(jié)果
(二) java深入源碼級(jí)的面試題(有難度)
哪些情況下的對(duì)象會(huì)被垃圾回收機(jī)制處理掉?
GC確定哪些對(duì)象回收有兩種算法:
1、引用計(jì)數(shù)法
對(duì)象頭處維護(hù)了一個(gè)引用計(jì)數(shù)去counter一個(gè)對(duì)象被引用一次計(jì)數(shù)器就會(huì)+1,不會(huì)引用就會(huì)-1,為0的時(shí)候GC工作的時(shí)候就會(huì)被回收,但是它不能解決循環(huán)引用帶來(lái)的問(wèn)題
2、可達(dá)性算法
java默認(rèn)的垃圾回收算法,虛擬機(jī)會(huì)先將一些對(duì)象定義為 GC Roots,沿著GC Roots向下尋找,如果對(duì)象不能通過(guò)GC Roots尋找到,那么虛擬機(jī)就認(rèn)為該對(duì)象是被回收的
講一下常見(jiàn)編碼方式?
ASCII:我理解為中文中的GB2312,使用8為二進(jìn)制來(lái)表示字母和字符
UTF-8:英文一個(gè)字符一個(gè)字節(jié),中文占用3/4字節(jié)
UTF-16:定長(zhǎng)編碼,所有字符占兩個(gè)字節(jié)
utf-8編碼中的中文占幾個(gè)字節(jié);int型幾個(gè)字節(jié)?
中文少數(shù)占3個(gè)字節(jié),多數(shù)占4個(gè)字節(jié),int型數(shù)字占1個(gè)字節(jié)
靜態(tài)代理和動(dòng)態(tài)代理的區(qū)別,什么場(chǎng)景使用?
靜態(tài)代理:在程序運(yùn)行前已經(jīng)存在的,提前寫(xiě)好的。代理類(lèi)和委托類(lèi)的關(guān)系提前確定好的。
優(yōu)點(diǎn):業(yè)務(wù)只關(guān)注業(yè)務(wù)本身,專(zhuān)一性
缺點(diǎn):代理對(duì)象只能服務(wù)一種類(lèi)型的對(duì)象,代理需要新的方法,每個(gè)委托都要實(shí)現(xiàn)
動(dòng)態(tài)代理:源碼在運(yùn)行期間JVM根據(jù)反射等機(jī)制動(dòng)態(tài)的生成
Java的異常體系
最近在看java編程思想,根據(jù)自己編碼經(jīng)歷,談?wù)剬?duì)異常的理解:
首先我們都知道java每個(gè)對(duì)象都有一個(gè)異常的超類(lèi)Throwable,它由兩個(gè)子類(lèi)Error(錯(cuò)誤)和Exception(異常)
Error:嚴(yán)重的不可處理的異常,會(huì)導(dǎo)致程序直接掛掉,比如內(nèi)存溢出、類(lèi)定義錯(cuò)誤等
Exception:可處理異常,可以捕獲并處理,比如對(duì)象空指針,文件找不到路徑等
????????????運(yùn)行時(shí)異常:時(shí)在程序運(yùn)行前編譯前檢查語(yǔ)法錯(cuò)誤來(lái)提醒
? ? ? ? ? ??編譯時(shí)異常:主要是程序在運(yùn)行后出現(xiàn)的邏輯錯(cuò)誤或者內(nèi)存溢出而導(dǎo)致的異常,?
1、除非你能解決處理異常,否則不要捕獲它,如果是記錄錯(cuò)誤消息,別忘了把它在拋出去
2、異常即代表一種錯(cuò)誤 也代表一種消息
Java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
多態(tài)的實(shí)現(xiàn)有三個(gè)必要條件:
繼承:再多態(tài)中必須有繼承關(guān)系的子類(lèi)、父類(lèi)
重寫(xiě):子類(lèi)重寫(xiě)父類(lèi)中的方法,調(diào)用這些方法就會(huì)調(diào)用子類(lèi)的方法
向上轉(zhuǎn)型:將子類(lèi)的引用賦給父類(lèi),這樣可以調(diào)用父類(lèi)中的方法,和父類(lèi)中沒(méi)有,子類(lèi)中有的方法
如何將一個(gè)Java對(duì)象序列化到文件里?
FileOutputStream fileOutputStream = new FileOutputStream("d://test.out");
ObjectOutputStream objectOutputStream= new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject("object");
objectOutputStream.close();?
說(shuō)說(shuō)你對(duì)Java反射的理解
定義:反射就是程序運(yùn)行時(shí)動(dòng)態(tài)的獲取類(lèi)和對(duì)象的方法或者屬性
作用:通過(guò)反射,我們可以獲取相應(yīng)的屬性和方法或者資源,比如我們?cè)诔绦蛑邢氆@取第三方的資源文件,就不能通過(guò)R.id的方式獲取,必須通過(guò)反射才能拿到資源文件
使用:可以通過(guò)對(duì)象.getClass()、類(lèi).class、Class.forName("")
說(shuō)說(shuō)你對(duì)Java注解的理解
定義:注解也稱(chēng)為元數(shù)據(jù),是一種代碼的級(jí)別說(shuō)明,聲明在包、類(lèi)、字段、方法、局部變量、方法參數(shù)等前面,來(lái)對(duì)這些元素進(jìn)行說(shuō)明,注釋等
作用:
?1)編寫(xiě)文檔:通過(guò)代碼里的標(biāo)識(shí)的元數(shù)據(jù)生成文檔【生成文檔doc文檔】
2)代碼分析:通過(guò)代碼里的標(biāo)識(shí)的元數(shù)據(jù)對(duì)代碼進(jìn)行分析【使用反射】
3)編譯檢查:通過(guò)代碼里的標(biāo)識(shí)的元數(shù)據(jù)讓編譯器能過(guò)實(shí)現(xiàn)基本的編譯檢查
java提供了四種元注解:
1.@Target,:規(guī)定注解所修飾的對(duì)象范圍
2.@Retention:表示注解的生命周期
3.@Documented:用于描述
4.@Inherited:主要說(shuō)明了一種繼承性,子類(lèi)可以繼承父類(lèi)注解
說(shuō)說(shuō)你對(duì)依賴注入的理解
我理解的依賴注入是你不需要關(guān)心對(duì)象的生命周期,什么時(shí)候調(diào)用、銷(xiāo)毀等過(guò)程,只需要關(guān)注,調(diào)用它的外部類(lèi)即可:
代碼舉例說(shuō)明:對(duì)象注入、屬性注入
說(shuō)一下泛型原理,并舉例說(shuō)明
泛型的本質(zhì)是參數(shù)化類(lèi)型,它可以用在接口,方法和類(lèi)中,泛型接口、泛型方法、泛型類(lèi)
比如List<String>:
1、它的好處就是在編譯時(shí)期就幫我們檢查類(lèi)型是否安全,不需要運(yùn)行,并且所有的強(qiáng)轉(zhuǎn)都是自動(dòng)和隱士的,效率高
Java中String的了解
String為什么要設(shè)計(jì)成不可變的?
final修飾,不可被繼承,不可被重寫(xiě),類(lèi)型安全,
Object類(lèi)的equal和hashCode方法重寫(xiě),為什么?
1、如果兩個(gè)對(duì)象的equal相同,那么hashCode一定相同,
2、如果hashCode相同。equal并不一定相同
如果equal重寫(xiě),hashCode沒(méi)有被重寫(xiě),可能會(huì)導(dǎo)致兩個(gè)沒(méi)有關(guān)系的對(duì)象equal相同。
(四) 線程、多線程和線程池
開(kāi)啟線程的三種方式?
繼承Thread類(lèi),調(diào)用run()或start()方法
實(shí)現(xiàn)Runnable接口,調(diào)用run()方法? ? ?沒(méi)有返回值,不能進(jìn)行容錯(cuò)處理
Callable接口實(shí)現(xiàn)類(lèi),調(diào)用call()實(shí)現(xiàn)? ? ? 有返回值,并且能容錯(cuò)處理,拋出錯(cuò)誤信息
線程和進(jìn)程的區(qū)別?
進(jìn)程是程序的執(zhí)行單元,一般指一個(gè)應(yīng)用或程序
線程是cpu調(diào)度的最小單元,是一種有限的系統(tǒng)資源,分為UI線程和子線程
一個(gè)進(jìn)程可以有多個(gè)線程。
為什么要有線程,而不是僅僅用進(jìn)程?
進(jìn)程的缺點(diǎn):
????進(jìn)程在同一時(shí)間只能干一件事,如果同時(shí)干多件事就無(wú)能為力
????進(jìn)程在處理任務(wù)一旦遇到阻塞,當(dāng)前程序就會(huì)掛起,下一步操作就無(wú)法繼續(xù)進(jìn)行
線程的優(yōu)點(diǎn):
? ? 減少程序的響應(yīng)時(shí)間,同時(shí)執(zhí)行多個(gè)耗時(shí)操作,充分利用系統(tǒng)資源,避免閑置浪費(fèi)。
run()和start()方法區(qū)別
我們首先來(lái)了解一下線程的五個(gè)狀態(tài):
創(chuàng)建:new Thread(new Runnable);這是線程的創(chuàng)建階段,等待被執(zhí)行
就緒:調(diào)用線程的start()方法,當(dāng)前線程就會(huì)告知虛擬機(jī)我已準(zhǔn)備就緒,由JVM進(jìn)行調(diào)度
運(yùn)行:線程會(huì)調(diào)用實(shí)現(xiàn)runnable的run()方法,此時(shí)線程才真正執(zhí)行
阻塞:執(zhí)行過(guò)程中的暫停等操作。sleep
死亡:run方法執(zhí)行完畢,線程死亡
總結(jié):start()方法只是讓線程處于就緒狀態(tài),告訴cpu我已準(zhǔn)備好了,請(qǐng)開(kāi)始執(zhí)行,然后調(diào)用run方法按順序執(zhí)行。
如何控制某個(gè)方法允許并發(fā)訪問(wèn)線程的個(gè)數(shù)?
java中有一個(gè)叫做信號(hào)量的類(lèi)Semaphore,負(fù)責(zé)控制線程的載入、釋放以及最大并發(fā)訪問(wèn)的個(gè)數(shù),只需要在構(gòu)造函數(shù)中傳入一個(gè)最大的并發(fā)數(shù)就可以。
在Java中wait和sleep方法的不同;
sleep:睡眠,一直持有鎖,事件過(guò)后任務(wù)繼續(xù)執(zhí)行,Thread方法
wait:等待,會(huì)釋放鎖,需要notify()喚醒才能繼續(xù)持有,Object方法
什么導(dǎo)致線程阻塞?
Thread.sleep() 線程睡眠
Object.wait() 線程等待
Thread.yeild() 線程禮讓
Thread.join() 線程自閉
線程如何關(guān)閉?
通常情況下線程運(yùn)行完畢會(huì)自動(dòng)結(jié)束,但是有時(shí)候需要提前讓用戶取消操作等。
1、通過(guò)退出標(biāo)識(shí),自定義一個(gè)isFlag標(biāo)識(shí),在Run方法中進(jìn)行判斷
2、?線程提供interrupted()方法判斷線程是否已經(jīng)中斷來(lái)停止
講一下java中的同步的方法
java允許多線程并發(fā)操作,在多線程并發(fā)中同時(shí)操作一個(gè)可共享的變量是容易造成數(shù)據(jù)不準(zhǔn)確,比如數(shù)據(jù)庫(kù)增刪查改,java引入同步來(lái)保持?jǐn)?shù)據(jù)的一致性final:變量的唯一性,不可變synchronized:作用域代碼塊,方法,通過(guò)線程互斥,同一時(shí)間只允許一個(gè)線程操作。Volatile:修飾變量變化保證立即對(duì)線程可見(jiàn)
數(shù)據(jù)一致性如何保證?
java允許多線程并發(fā)操作,在多線程并發(fā)中同時(shí)操作一個(gè)可共享的變量是容易造成數(shù)據(jù)不準(zhǔn)確,比如數(shù)據(jù)庫(kù)增刪查改,java引入同步來(lái)保持?jǐn)?shù)據(jù)的一致性
final:變量的唯一性,不可變
synchronized:作用域代碼塊,方法,通過(guò)線程互斥,同一時(shí)間只允許一個(gè)線程操作。
Volatile:修飾變量變化保證立即對(duì)線程可見(jiàn)
如何保證線程安全?
java中死鎖和臟數(shù)據(jù)就是典型的線程安全問(wèn)題,只有存在共享數(shù)據(jù)時(shí)才需要考慮線程安全問(wèn)題
synchronized:作用域代碼塊,方法,通過(guò)線程互斥,同一時(shí)間只允許一個(gè)線程操作。Volatile:修飾變量變化保證立即對(duì)線程可見(jiàn)
如何實(shí)現(xiàn)線程同步?
三種方式:
synchronized 同步代碼塊,同一時(shí)間只允許一個(gè)線程操作
Lock,手動(dòng)獲取鎖,釋放鎖
synchronized? 通過(guò)方法。
兩個(gè)進(jìn)程同時(shí)要求寫(xiě)或者讀,能不能實(shí)現(xiàn)?如何防止進(jìn)程的同步?
線程間操作List
多線程操作list容易引起并發(fā)操作導(dǎo)致數(shù)據(jù)的不一致性,
Java中對(duì)象的生命周期
1.??????創(chuàng)建階段(Created) New一個(gè)對(duì)象,有jvm分配內(nèi)存
2.??????應(yīng)用階段(In Use)? 至少被一個(gè)強(qiáng)引用持有
3.??????不可見(jiàn)階段(Invisible)? ?是指該對(duì)象不在當(dāng)前作用域中被訪問(wèn),編譯直接報(bào)錯(cuò)
4.??????不可達(dá)階段(Unreachable)? 不再持有,但是會(huì)被靜態(tài)變量或者jni底層引用
5.??????收集階段(Collected)?
6.??????終結(jié)階段(Finalized)??對(duì)象運(yùn)行完finalize()等待被回收
7.??????對(duì)象空間重分配階段(De-allocated)?對(duì)象徹底消失了
Synchronized用法
Synchronized(this){代碼塊}:其他想要訪問(wèn)此處代碼時(shí),會(huì)被阻塞
public syncchronized void method(){...} 修飾一個(gè)方法,表示其他任務(wù)訪問(wèn)該方法會(huì)被阻塞
synchronize的原理
Java對(duì)象頭和monitor是實(shí)現(xiàn)synchronized的基礎(chǔ)
對(duì)象頭:通過(guò)對(duì)象頭來(lái)確定對(duì)象是哪個(gè)類(lèi)的實(shí)例
monitor:對(duì)象監(jiān)視器,用來(lái)監(jiān)視對(duì)象狀態(tài),它是一種同步機(jī)制
談?wù)剬?duì)Synchronized關(guān)鍵字,類(lèi)鎖,方法鎖,重入鎖的理解
Synchronized是同步的一種機(jī)制,主要用來(lái)解決并發(fā)訪問(wèn)同一對(duì)象所造成的安全問(wèn)題。
Synchronized 修飾靜態(tài)方法獲取到的就是類(lèi)鎖,修飾整個(gè)類(lèi)
Synchronized 修飾代碼塊修飾一個(gè)方法獲取到的就是方法鎖,修飾當(dāng)前方法
沖入所:子類(lèi)繼承父類(lèi)的方法,子類(lèi)父類(lèi)都有方法鎖,
static synchronized 方法的多線程訪問(wèn)和作用
static? synchronized標(biāo)識(shí)當(dāng)前鎖的整個(gè)類(lèi)的靜態(tài)方法,修飾的是整個(gè)類(lèi),也成為類(lèi)鎖。
作用:它可以對(duì)類(lèi)的所有對(duì)象實(shí)例起作用,
同一個(gè)類(lèi)里面兩個(gè)synchronized方法,兩個(gè)線程同時(shí)訪問(wèn)的問(wèn)題
不能同步執(zhí)行,多線程同時(shí)訪問(wèn)同一個(gè)類(lèi)的兩個(gè)synchronized方法時(shí),jvm會(huì)檢測(cè)到當(dāng)前類(lèi)對(duì)象前面的synchronized關(guān)鍵字,會(huì)對(duì)對(duì)象ID加鎖,因此,兩個(gè)線程同時(shí)訪問(wèn),會(huì)等待一個(gè)執(zhí)行完成才能執(zhí)行另一個(gè)。
談?wù)剉olatile關(guān)鍵字的作用
禁止指令重排,修飾變量變化立即對(duì)線程可見(jiàn),線程每次使用的時(shí)候都會(huì)使用修改后的值
synchronized 和volatile 關(guān)鍵字的區(qū)別
synchronized 作用于方法,代碼塊,volatile只能修飾變量
synchronized 會(huì)造成線程阻塞,volatile不會(huì)
synchronized只要用于并發(fā)操作是保證數(shù)據(jù)的唯一性,volatile主要是變量變化時(shí)立馬對(duì)其他線程可見(jiàn)。
synchronized與Lock的區(qū)別
synchronized 時(shí)java內(nèi)置鎖,Lock不是java內(nèi)置
synchronized不需要用戶去手動(dòng)的釋放鎖,使用完后會(huì)自動(dòng)釋放,Lock需要用戶手動(dòng)釋放,不手動(dòng)釋放會(huì)造成死鎖現(xiàn)象
ReentrantLock 、synchronized和volatile比較
ReentrantLock的內(nèi)部實(shí)現(xiàn)
lock原理
死鎖的四個(gè)必要條件?
互斥:某個(gè)資源一次只能有一個(gè)進(jìn)程訪問(wèn),其他進(jìn)程需要先等待
占有且等待,當(dāng)前進(jìn)程本身占有著一種資源,同時(shí)也需要其他進(jìn)程正在訪問(wèn)的其他資源,需要等待
不可搶占:別人已經(jīng)占有,不可使用
循環(huán)等待:
怎么避免死鎖?
1、避免一個(gè)線程同時(shí)獲取多個(gè)鎖;
2、避免一個(gè)線程在鎖內(nèi)同時(shí)占用多個(gè)資源,盡量保證每個(gè)鎖只占用一個(gè)資源
對(duì)象鎖和類(lèi)鎖是否會(huì)互相影響?
類(lèi)鎖和對(duì)象鎖不是同1個(gè)東西,一個(gè)是類(lèi)的Class對(duì)象的鎖,一個(gè)是類(lèi)的實(shí)例的鎖。也就是說(shuō):1個(gè)線程訪問(wèn)靜態(tài)synchronized的時(shí)候,允許另一個(gè)線程訪問(wèn)對(duì)象的實(shí)例synchronized方法。反過(guò)來(lái)也是成立的,因?yàn)樗麄冃枰逆i是不同的
什么是線程池,如何使用?
線程池就是將任務(wù)添加到隊(duì)列中順序或并發(fā)執(zhí)行的一個(gè)集合,android線程池一般有這幾個(gè)參數(shù):核心線程數(shù),緩沖線程數(shù),最大線程數(shù)
Java的并發(fā)、多線程、線程模型
談?wù)剬?duì)多線程的理解
優(yōu)點(diǎn):多線程可以處理耗時(shí)操作,方便多任務(wù)同時(shí)執(zhí)行,比如網(wǎng)絡(luò)操作,后臺(tái)下載等。
缺點(diǎn):線程是一種有限的系統(tǒng)資源,因此,需要避免大量線程的開(kāi)銷(xiāo)以及內(nèi)存泄漏
多線程有什么要注意的問(wèn)題?
多線程是一種有限的系統(tǒng)資源,大量的創(chuàng)建會(huì)導(dǎo)致資源消耗,盡量使用線程池
Android中容易引起內(nèi)存泄漏:持有外部類(lèi)的引用。
談?wù)勀銓?duì)并發(fā)編程的理解并舉例說(shuō)明
cpu在同一時(shí)間只能處理一件事,因此并發(fā)看似是同時(shí)執(zhí)行,實(shí)際上實(shí)在不停的切換進(jìn)程
談?wù)勀銓?duì)多線程同步機(jī)制的理解?
線程同步是一種安全機(jī)制,它主要是解決多線程同時(shí)訪問(wèn)統(tǒng)一資源導(dǎo)致的數(shù)據(jù)安全問(wèn)題。
synchronized;volatile
如何保證多線程讀寫(xiě)文件的安全?
多線程 同時(shí)訪問(wèn)同一個(gè)文件回導(dǎo)致數(shù)據(jù)安全問(wèn)題,因此可以使用同步鎖來(lái)解決這種問(wèn)題。
可以使用synchronzied來(lái)保證在同一時(shí)間只能由一個(gè)線程來(lái)操作
斷點(diǎn)續(xù)傳原理及實(shí)現(xiàn)
斷點(diǎn)續(xù)傳分為單線程斷點(diǎn)續(xù)傳和多線程斷點(diǎn)續(xù)傳,
單線程斷點(diǎn)續(xù)傳:比較簡(jiǎn)單,至開(kāi)啟一個(gè)線程下載某一個(gè)文件起始位置是0-文件總大小,網(wǎng)絡(luò)斷開(kāi)記住當(dāng)前所下載的位置,下次下載重新定義http的Range
多線程斷點(diǎn)續(xù)傳:開(kāi)啟多個(gè)線程同時(shí)下載某個(gè)文件中的某一個(gè)部分,舉例說(shuō)明
實(shí)現(xiàn):
不管是單線程還是多線程都要用到:
1、斷點(diǎn)續(xù)傳需要指定http的Range和Content-Rang
2、如果檢測(cè)到網(wǎng)絡(luò)斷開(kāi)則要記錄當(dāng)前下載的位置也就是Range,等待下次重新連接的時(shí)候,指定當(dāng)前Range?
二、Android面試題
Android面試題包括Android基礎(chǔ),還有一些源碼級(jí)別的、原理這些等。所以想去大公司面試,一定要多看看源碼和實(shí)現(xiàn)方式,常用框架可以試試自己能不能手寫(xiě)實(shí)現(xiàn)一下,鍛煉一下自己。
(一)Android基礎(chǔ)知識(shí)點(diǎn)
四大組件是什么
Activity:Service:BoradcastReceiver:ContentProvider:
四大組件的生命周期和簡(jiǎn)單用法
Activity之間的通信方式
1、通過(guò)Intent傳遞,大小限制1Mb
2、通過(guò)類(lèi)靜態(tài)變量
3、通過(guò)全局變量
4、通過(guò)SharedPreferences、文件等用的較少
Activity各種情況下的生命周期
橫豎屏切換的時(shí)候,Activity 各種情況下的生命周期
橫屏:onSaveInstanceState->onPause()->onStop->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->onResume()
豎屏:橫屏*2
對(duì)android:configChanges屬性,一般認(rèn)為有以下幾點(diǎn):
1、不設(shè)置Activity的android:configChanges時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期,切橫屏?xí)r會(huì)執(zhí)行一次,切豎屏?xí)r會(huì)執(zhí)行兩次
2、設(shè)置Activity的android:configChanges="orientation"時(shí),切屏還是會(huì)重新調(diào)用各個(gè)生命周期,切橫、豎屏?xí)r只會(huì)執(zhí)行一次
3、設(shè)置Activity的android:configChanges="orientation|keyboardHidden"時(shí),切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行onConfigurationChanged方法?
Activity與Fragment之間生命周期比較
Activity:onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart
Fragment:
onAttach(與Activyty關(guān)聯(lián)時(shí)調(diào)用)、 onCreate、onCreateView(創(chuàng)建Fragment視圖時(shí)調(diào)用)、onActivityCreated(Activity 的Create方法調(diào)用時(shí)調(diào)用)
onStart、
onResume、
onPause、
onStop、
onDestroyView(Fragment視圖被移除時(shí)調(diào)用)、onDestroy、onDetach(與Activity取消關(guān)聯(lián)時(shí)調(diào)用)
Activity上有Dialog的時(shí)候按Home鍵時(shí)的生命周期
onPause()、onStop()
兩個(gè)Activity 之間跳轉(zhuǎn)時(shí)必然會(huì)執(zhí)行的是哪幾個(gè)方法?
A:onPause、B:onCreate、onStart、onResume、A:onStop
前臺(tái)切換到后臺(tái),然后再回到前臺(tái),Activity生命周期回調(diào)方法。
A->B:
A:onPause、B:onCreate、onStart、onResume、A:onStop
B返回A:
B:onPause、A:onRestart、onStart、onResume、B:onStop、onDestroy
彈出Dialog,生命值周期回調(diào)方法。
A:onPause、B:onCreate、onStart、onResume
Activity的四種啟動(dòng)模式對(duì)比
standard:默認(rèn)模式,每次都會(huì)創(chuàng)建一個(gè)新的頁(yè)面
singleTop:棧頂模式,創(chuàng)建時(shí)優(yōu)先檢查棧頂是否存在相同的活動(dòng),有展示,沒(méi)有創(chuàng)建
singleTask:棧內(nèi)模式,創(chuàng)建時(shí)優(yōu)先檢查棧內(nèi)是否存在相同的活動(dòng),有展示并清除當(dāng)前活動(dòng)以上所有頁(yè)面,沒(méi)有創(chuàng)建
singleInstance:?jiǎn)卫J?,存在于單?dú)的棧中,且只有一個(gè)實(shí)例
Activity狀態(tài)保存于恢復(fù)
一般我們指的狀態(tài)保存和恢復(fù)是指的非正常狀態(tài)下的activity生命周期
onSaveInstanceState
onRetoreInstanceState
如何實(shí)現(xiàn)Fragment的滑動(dòng)?
Fragment和Viewpager配合使用
給Viewpager設(shè)置setAdapter和setOnPageChangeListener即可
fragment之間傳遞數(shù)據(jù)的方式?
調(diào)用getFragmentManager()的findFragmentById()獲取fragment對(duì)象,根據(jù)對(duì)象調(diào)用方法來(lái)實(shí)現(xiàn)
Activity 怎么和Service 綁定?
Activity-Intent-Service
bindService(new Intent(Activity,Service.class),)
怎么在Activity 中啟動(dòng)自己對(duì)應(yīng)的Service?
startService(new Intent(...))
service和activity怎么進(jìn)行數(shù)據(jù)交互?
通過(guò)Intent進(jìn)行傳值
Service的開(kāi)啟方式 以及Service 的生命周期
startService:
startService、onCreate、onStart、service running、onStop、onDestroy
bindService、onCreate、onBind、service running,onUnBind,onDestroy
談?wù)勀銓?duì)ContentProvider的理解
定義:
ContentProvider它是一種數(shù)據(jù)共享性組件,用戶向其他組件乃至其他應(yīng)用共享數(shù)據(jù),和廣播一樣無(wú)法被用戶感知,他內(nèi)部需要實(shí)現(xiàn)增刪查改方法,內(nèi)部維護(hù)了一個(gè)數(shù)據(jù)集合,通過(guò)數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)
日常開(kāi)發(fā):自定義類(lèi)繼承ContentProvider,實(shí)現(xiàn)增刪查改方法,處理好線程同步,對(duì)外實(shí)現(xiàn)URL來(lái)實(shí)現(xiàn)。
說(shuō)說(shuō)ContentProvider、ContentResolver、ContentObserver 之間的關(guān)系
ContentProvider 內(nèi)容提供者,向外提供共享數(shù)據(jù)
ContentResolver:內(nèi)容解析者,對(duì)內(nèi)容提供者提供的數(shù)據(jù)進(jìn)行分析
ContentObserver:內(nèi)容觀察者,觀察內(nèi)容在各個(gè)階段的狀態(tài)
請(qǐng)描述一下廣播BroadcastReceiver的理解
1、BroadcastReceiver 時(shí)一種消息型組件,在不同組件乃至不同應(yīng)用之間傳遞消息,無(wú)法被用戶感知,因?yàn)樗ぷ髟谙到y(tǒng)內(nèi)部,
2、廣播有兩種注冊(cè)方式:靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè)。生命周期也根據(jù)注冊(cè)不同
3、廣播默認(rèn)運(yùn)行在主線程中,不支持耗時(shí)操作。
廣播的分類(lèi)
有序廣播:消息的照發(fā)送的順序接收
無(wú)序廣播:所有設(shè)備幾乎在同一時(shí)刻接收到廣播
本地廣播:只能在當(dāng)前應(yīng)用中接收到廣播
粘性廣播:先發(fā)送,后注冊(cè)
在manifest 和代碼中如何注冊(cè)和使用BroadcastReceiver?
靜態(tài)注冊(cè):mainfest中<receiver android:name=".MyReceiver">action</receiver>
動(dòng)態(tài)注冊(cè):regeisterReceiver(new MyReceiver(),filter);
廣播發(fā)送的原理:
1、首先自定義一個(gè)廣播接收者BroadcastRecevier,并重寫(xiě)onReceiver();
2、通過(guò)Binder機(jī)制像AMS進(jìn)行注冊(cè);
3、廣播發(fā)送者通過(guò)Binder機(jī)制向AMS發(fā)送廣播;
4、AMS查找符合條件的廣播,并發(fā)送到消息循環(huán)隊(duì)列中;
5、消息循環(huán)拿到此廣播并回調(diào)onReceiver()方法。
Application 和 Activity 的 Context 對(duì)象的區(qū)別
生命周期不同:
Application的Context代表的是整個(gè)應(yīng)用程序的生命周期,Activity的Context代表的是當(dāng)前Activity的生命周期。
Android屬性動(dòng)畫(huà)工作原理
在一定時(shí)間間隔內(nèi),通過(guò)不斷對(duì)值進(jìn)行改變,并不斷將該值賦給對(duì)象的屬性,從而實(shí)現(xiàn)該對(duì)象在該屬性上的動(dòng)畫(huà)效果
如何導(dǎo)入外部數(shù)據(jù)庫(kù)?
1、將外部數(shù)據(jù)庫(kù)放到文件目錄assets中,
2、通過(guò)InputStream讀取外部數(shù)據(jù)庫(kù),通過(guò)FileOutputStream導(dǎo)入內(nèi)部數(shù)據(jù)庫(kù)
3、需要注意外部數(shù)據(jù)庫(kù)與我們新建的數(shù)據(jù)庫(kù)屬性和數(shù)據(jù)類(lèi)型要一致
LinearLayout、RelativeLayout、FrameLayout的特性及對(duì)比,并介紹使用場(chǎng)景。
RelativeLayout 會(huì)橫向,縱向進(jìn)行兩次測(cè)量,也就是執(zhí)行兩次measure,效率肯定相對(duì)底
LinearLayout 線性布局,從上往下的順序繪制元素,如果LinearLayout 有weight屬性,也會(huì)執(zhí)行兩次measure
FrameLayout 無(wú)法控制子元素的位置,全部堆在左上角,無(wú)法改變。
談?wù)剬?duì)接口與回調(diào)的理解
接口的實(shí)現(xiàn)很簡(jiǎn)單,?
1、定義接口,編寫(xiě)回掉方法,給接口賦值
我們想象平時(shí)為什么需要接口
1、傳值,利用接口傳值,我們不關(guān)心過(guò)程只關(guān)心結(jié)果,
2、接口回調(diào)可以理解為一種設(shè)計(jì)模式,類(lèi)似于觀察者,程序負(fù)責(zé)項(xiàng)目大的時(shí)候,有利于頁(yè)面之間的解耦
介紹下SurefaceView
1、SurefaceView主要在被動(dòng)的情況下更新,
2、SurefaceView主要在子線程中進(jìn)行,常用于平凡刷新以及刷新是數(shù)據(jù)量大的情況下
3、SurefaceView底部采用了雙緩存機(jī)制,常見(jiàn)的視頻播放。
RecycleView的使用
recyckeView.setLayoutManager(設(shè)置布局管理器,支持三種:橫/縱向,流式布局,瀑布流);
recyckeView.setAdapter(設(shè)置適配源)
//也可以設(shè)置分割線、動(dòng)畫(huà)等
序列化的作用,以及Android兩種序列化的區(qū)別
序列化是指將對(duì)象轉(zhuǎn)化為文件存儲(chǔ)在本地存儲(chǔ)中的操作,主要是為了保存對(duì)象的狀態(tài)
Serializable:java自帶,使用簡(jiǎn)單,但是要重復(fù)讀寫(xiě)內(nèi)存,效率低
Parcelable:android自帶,使用復(fù)雜,重復(fù)利用內(nèi)存,效率高。
插值器
android中的插值器主要是為了實(shí)現(xiàn)動(dòng)畫(huà)的非線性需求而定義的,例如加減速等
估值器
協(xié)助插值器 實(shí)現(xiàn)非線性運(yùn)動(dòng)的動(dòng)畫(huà)效果
Android中數(shù)據(jù)存儲(chǔ)方式
sharedpreferences:android提供的基于key、value保存在xml文件中的存儲(chǔ)方式,基本數(shù)據(jù)類(lèi)型等。非線程安全
文件存儲(chǔ):將對(duì)象采用序列化的方式保存到本地
sqlite:數(shù)據(jù)庫(kù)存儲(chǔ)
contentprovider:通過(guò)程序之間共享數(shù)據(jù)存儲(chǔ):
網(wǎng)絡(luò)云存儲(chǔ):
(二)Android源碼相關(guān)分析
invalidate和postInvalidate的區(qū)別及使用
invalidate在主線程中使用,通知UI更新View
postInvalidate在子線程中調(diào)用,通知UI更新View,底層通過(guò)Handler來(lái)通知UI更新
Activity-Window-View三者的差別
1、Activity 創(chuàng)建時(shí)通過(guò)attach()初始化了
2、一個(gè) Window 一個(gè) Window 持有一個(gè) DecorView 的實(shí)例,DecorView 本身是一個(gè) FrameLayout,繼承于View, 3、Activty通過(guò)setContentView將xml布局控件不斷addView()添加到View中,最終顯示到Window于我們交互;
談?wù)剬?duì)Volley的理解
google推出的異步網(wǎng)絡(luò)框架,還能加載圖片,適合請(qǐng)求量小
使用:
1、將網(wǎng)絡(luò)請(qǐng)求添加到RequestQueue中
2、RequestQueue中有兩個(gè)分發(fā)器:CacheDispatch(緩存分發(fā)器)和NetworkDispatch(網(wǎng)絡(luò)分發(fā)器),其實(shí)就是開(kāi)啟兩個(gè)線程
3、網(wǎng)絡(luò)請(qǐng)求會(huì)有優(yōu)先從緩存中獲取,如果緩存中沒(méi)有就開(kāi)啟一個(gè)networkdispatch,并且將請(qǐng)求添加到cachediapatch中,
4、將請(qǐng)求結(jié)果傳遞到主線程。
如何優(yōu)化自定義View
優(yōu)化自定義view可以從兩個(gè)方面考慮:
1、減少invaildate調(diào)用次數(shù),invaildate在主線程中運(yùn)行,調(diào)用它會(huì)執(zhí)行view的onDraw方法,造成UI卡頓
2、requestLayout操作非常耗時(shí),因?yàn)閳?zhí)行requestLayout會(huì)使android Ui系統(tǒng)遍歷整個(gè)view層級(jí)來(lái)計(jì)算view大小
3、如果UI復(fù)雜,可以考慮使用ViewGroup,與view不同的是,自定義view僅僅測(cè)量一部分
低版本SDK如何實(shí)現(xiàn)高版本api?
低版本使用高版本的api最常見(jiàn)的是編譯報(bào)錯(cuò),android為開(kāi)發(fā)者提供了避免編譯報(bào)錯(cuò)的解決方案,那就是注解:
@SuppressLint(newApi)
讓編譯器忽略所有對(duì)新api版本的調(diào)用檢查
@TargetApi(11)
讓編譯器忽略對(duì)特定版本的便宜檢查
描述一次網(wǎng)絡(luò)請(qǐng)求的流程
1、通過(guò)url找到IP
2、根據(jù)IP簡(jiǎn)歷TCP連接(三次握手)
3、向服務(wù)器發(fā)送數(shù)據(jù)
4、服務(wù)器解析并返回結(jié)果
5、對(duì)結(jié)果進(jìn)行處理
Bitmap對(duì)象的理解
Bitmap核心思想有三個(gè):高效加載,緩存策略,性能優(yōu)化;
高效加載:在不影響圖片顯示的情況下,使用采樣率對(duì)圖片就行高效加載;流程
? ?1、將BitmapFactory.Options的inJustDecodeBounds設(shè)為true并加載圖片;
? ?2、從BitmapFactory.Options獲取圖片的信息,outHeight和outWidth參數(shù)
? ?3、根據(jù)采樣率的規(guī)則結(jié)果目標(biāo)view的大小,計(jì)算出inSampleSize采樣率
? ?4、將BitmapFactory.inJustDecodeBounds設(shè)為false,然后重新加載圖片
緩存策略:在實(shí)際開(kāi)發(fā)中我們經(jīng)常用bitmap進(jìn)行圖片緩存,使用緩存策略,我們不用每次都從網(wǎng)絡(luò)下載圖片,緩存策略一般是指緩存的添加、獲取和刪除,因此實(shí)際開(kāi)發(fā)中配合LRUCache能更高效的加載圖片
性能優(yōu)化:bitmap加載圖片所占用內(nèi)存一部分來(lái)自jvm分配,另一部分來(lái)自native也就是底層分配,jvm的分配的內(nèi)存有g(shù)c來(lái)回收,而native非配的內(nèi)存可以由recyle()進(jìn)行回收,因此如果我們當(dāng)前如果確定對(duì)象不是用可以調(diào)用recyle進(jìn)行釋放底層分配的內(nèi)存,實(shí)際上android可以不用我們調(diào)用這個(gè)方法,如果gc檢測(cè)到當(dāng)前bitmap沒(méi)有引用,會(huì)自動(dòng)釋放recycle,因此手動(dòng)調(diào)用也沒(méi)有關(guān)系
ActivityThread,AMS,WMS的工作原理
自定義View如何考慮機(jī)型適配
合理使用warp_content,match_parent.
使用RelativeLayout 減少層級(jí)布局
盡量使用點(diǎn)9圖片
針對(duì)不同的機(jī)型,使用不同的布局文件放在對(duì)應(yīng)的目錄下,android會(huì)自動(dòng)匹配
自定義View的事件
一個(gè)touch事件由,down事件、move事件、up事件組成,當(dāng)一個(gè)時(shí)間產(chǎn)生以后,系統(tǒng)會(huì)將這個(gè)點(diǎn)擊事件傳遞到某個(gè)具體的view上,傳遞的順序是activity、viewgroup、view,傳遞的過(guò)程中經(jīng)過(guò)三個(gè)過(guò)程。
AsyncTask 工作流程?重要方法?
AsyncTask內(nèi)部封裝了線程池和Handler,便于執(zhí)行后臺(tái)任務(wù)和在子線程中更新UI
工作流程:
1、耗時(shí)操作之前準(zhǔn)備 (Main Thread)
2、處理耗時(shí)操作 & 向主線程發(fā)送更新進(jìn)度的?message(Work Thread)
3、獲取進(jìn)度的回調(diào)并處理 (Work Thread)
4、耗時(shí)操作結(jié)束的處理 (Main Thread)
5、(如果調(diào)用cancel),則要處理取消后的相應(yīng)操作 (Main Thread)
主要涉及到的四個(gè)核心方法
onPreExecute():?在主線程處理一些準(zhǔn)備工作。
doInBackground(Params…params):?在子線程中處理異步耗時(shí)任務(wù),可以通過(guò)?publishProgress?方法來(lái)更新任務(wù)的進(jìn)度。
onProgressUpdate(Progress…values):?在主線程中執(zhí)行,當(dāng)后臺(tái)任務(wù)進(jìn)度改變觸發(fā)回調(diào)。
onPostExecute(Result result):?在主線程中,異步任務(wù)結(jié)束觸發(fā)回調(diào),其中 result 就是后臺(tái)任務(wù)的返回值。
SparseArray原理
1,SpareArray用兩個(gè)數(shù)組存儲(chǔ)key和value,保持相同索引,int數(shù)組和Object數(shù)組。key鍵是int基本數(shù)據(jù)類(lèi)型,不需要hash計(jì)算,直接返回索引。
2,HashMap的key鍵必須是引用類(lèi)型,SpareArray可以避免key的自動(dòng)裝箱,數(shù)據(jù)量不大時(shí)可以代替HashMap,更省內(nèi)存。
3,采用二分查找算法獲取數(shù)據(jù)value作者:光晨子鏈接:http://www.itdecent.cn/p/3dba26007242來(lái)源:簡(jiǎn)書(shū)簡(jiǎn)書(shū)著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。
請(qǐng)介紹下ContentProvider 是如何實(shí)現(xiàn)數(shù)據(jù)共享的?
1、自定義一個(gè)ContentProvider類(lèi),繼承ContentProvider,
2、實(shí)現(xiàn)它的增刪查改方法
3、在配置文件中進(jìn)行注冊(cè),并未這個(gè)Contentprovider制定一個(gè)URL供外部訪問(wèn)/
Android Service與Activity之間通信的幾種方式
1、Activity傳遞數(shù)據(jù)到Service,通過(guò)startService或者BinderService傳遞Intent傳遞數(shù)據(jù)通信
2、Service傳遞數(shù)據(jù)到Activity,通過(guò)Binder來(lái)傳遞
3、通過(guò)廣播來(lái)傳遞數(shù)據(jù),
4、通過(guò)接口回調(diào)
IntentService原理及作用是什么?
IntentService繼承Service,它是一個(gè)異步自動(dòng)停止的高級(jí)服務(wù)類(lèi),優(yōu)先級(jí)比線程高,不容易被殺死,內(nèi)部封裝了可供外部使用HanderThread.
原理:內(nèi)部封裝了HandlerThread和Handler,
作用:因?yàn)樗鼉?nèi)部的onHandleIntent是一個(gè)異步線程,因此可以執(zhí)行耗時(shí)操作,并將結(jié)果通過(guò)Handler通知給UI
SP是進(jìn)程同步的嗎?有什么方法做到同步?
android中進(jìn)程之間不支持內(nèi)存共享,每個(gè)進(jìn)程訪問(wèn)sp都有一個(gè)單獨(dú)的實(shí)例,因此多進(jìn)程訪問(wèn)sp容易造成數(shù)據(jù)丟失,不安全等因素。
配合ContentProvider 使用
談?wù)劧嗑€程在Android中的使用
android中ui線程不允許執(zhí)行耗時(shí)操作,因此我們平常都來(lái)開(kāi)啟多線程等操作來(lái)解決網(wǎng)絡(luò)請(qǐng)求,后臺(tái)下載,耗時(shí)操作的問(wèn)題,同時(shí)利用Handler來(lái)解決UI線程和子線程之間的通信問(wèn)題,這就解決了UI更新,
asyncTask、headerThread、interService
RecycleView原理
RecyclerView擁有四級(jí)緩存:
屏幕內(nèi)緩存 :指在屏幕中顯示的ViewHolder,這些ViewHolder會(huì)緩存在mAttachedScrap、mChangedScrap中 。mChangedScrap表示數(shù)據(jù)已經(jīng)改變的ViewHolder列表
mAttachedScrap未與RecyclerView分離的ViewHolder列表
屏幕外緩存:當(dāng)列表滑動(dòng)出了屏幕時(shí),ViewHolder會(huì)被緩存在 mCachedViews,其大小由mViewCacheMax決定,默認(rèn)DEFAULT_CACHE_SIZE為2,可通過(guò)Recyclerview.setItemViewCacheSize()動(dòng)態(tài)設(shè)置。
自定義緩存:可以自己實(shí)現(xiàn)ViewCacheExtension類(lèi)實(shí)現(xiàn)自定義緩存,可通過(guò)Recyclerview.setViewCacheExtension()設(shè)置。通常我們也不會(huì)去設(shè)置他,系統(tǒng)已經(jīng)預(yù)先提供了兩級(jí)緩存了,除非有特殊需求,比如要在調(diào)用系統(tǒng)的緩存池之前,返回一個(gè)特定的視圖,才會(huì)用到他。
緩存池 :ViewHolder首先會(huì)緩存在mCachedViews中,當(dāng)超過(guò)了2個(gè)(默認(rèn)為2),就會(huì)添加到mRecyclerPool中。mRecyclerPool會(huì)根據(jù)ViewType把ViewHolder分別存儲(chǔ)在不同的集合中,每個(gè)集合最多緩存5個(gè)ViewHolder。
(三)常見(jiàn)的一些原理性問(wèn)題
Handler機(jī)制和底層實(shí)現(xiàn)
定義:負(fù)責(zé)跨線程通信,這是因?yàn)樵谥骶€程不能做耗時(shí)操作,而子線程不能更新UI,所以handle用于接收子線程的數(shù)據(jù),配合UI線程更新界面
Handler包括Handler在內(nèi)有四大要素:handler、message、messageQueue、Looper
工作機(jī)制:異步通信準(zhǔn)備->消息入列->消息循環(huán)->消息處理
1、初始化Handler,主線程會(huì)默認(rèn)創(chuàng)建Looper,Looper會(huì)自動(dòng)創(chuàng)建一個(gè)MessageQueue,并開(kāi)啟自動(dòng)循環(huán),
2、Handler通過(guò)sendMessage/post兩個(gè)方法發(fā)送消息到消息隊(duì)列中。
3、Looper通過(guò)無(wú)限循環(huán)從消息隊(duì)列中取出消息,并交由Handler處理,如果MessageQueue為null,當(dāng)前會(huì)阻塞,不會(huì)繼續(xù)執(zhí)行。
4、Handler接收Looper發(fā)來(lái)的消息并處理
Handler 引起的內(nèi)存泄露原因以及最佳解決方案
?泄露原因:
Handler 允許我們發(fā)送延時(shí)消息,如果在延時(shí)期間用戶關(guān)閉了 Activity,那么該 Activity 會(huì)泄露。 這個(gè)泄露是因?yàn)?Message 會(huì)持有 Handler,而又因?yàn)?Java 的特性,內(nèi)部類(lèi)會(huì)持有外部類(lèi),使得 Activity 會(huì)被 Handler 持有,這樣最終就導(dǎo)致 Activity 泄露。
?解決方案:
?將 Handler 定義成靜態(tài)的內(nèi)部類(lèi),在內(nèi)部持有Activity的弱引用,并在Acitivity的onDestroy()中調(diào)用handler.removeCallbacksAndMessages(null)及時(shí)移除所有消息。?
ThreadLocal原理,實(shí)現(xiàn)及如何保證Local屬性?
ThreadLocal 不是 Thread,是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類(lèi),通過(guò)它可以在指定的線程中存儲(chǔ)數(shù)據(jù),對(duì)數(shù)據(jù)存儲(chǔ)后,只有在線程中才可以獲取到存儲(chǔ)的數(shù)據(jù),對(duì)于其他線程來(lái)說(shuō)是無(wú)法獲取到數(shù)據(jù)
請(qǐng)描述一下View事件傳遞分發(fā)機(jī)制
1、事件分發(fā)的機(jī)制就是手指觸摸屏幕后所產(chǎn)生的一些列事件,這些事件包括:action_down、action_move、action_up
2、當(dāng)一個(gè)點(diǎn)擊事件產(chǎn)生以后系統(tǒng)會(huì)將這個(gè)點(diǎn)擊事件傳遞到某個(gè)具體的view上,傳遞順序是:activity、viewgroup、view
3、傳遞過(guò)程中有三個(gè)重要事件:
diapatchTouchEvent:
? ? 對(duì)事件進(jìn)行分發(fā),標(biāo)識(shí)是否消耗當(dāng)前事件
onInterceptTouchEvent:
? ? 在上述方法內(nèi)部調(diào)用,標(biāo)識(shí)當(dāng)前事件事件是否被攔截;
onTouchEvent:
? ? 在第一個(gè)方法內(nèi)部調(diào)用,表示用來(lái)處理點(diǎn)擊事件
對(duì)于一個(gè)根ViewGroup來(lái)說(shuō),當(dāng)點(diǎn)擊事件產(chǎn)生以后,首先會(huì)傳遞給它,這時(shí)它的diapatchTouchEvent就會(huì)被調(diào)用,如果這個(gè)viewgroup的onInterceptTouchEvent方法返回true,表示它要攔截當(dāng)前事件,接著這個(gè)事件就會(huì)交給viewgroup處理,即它的TouchEvent方法會(huì)被調(diào)用,如果不攔截,那么事件就傳遞給它的子元素,接著子元素的diapatchTouchEvent就會(huì)被調(diào)用,如此反復(fù)
View和ViewGroup分別有哪些事件分發(fā)相關(guān)的回調(diào)方法
View刷新機(jī)制
在Android的View刷新機(jī)制中,父View負(fù)責(zé)刷新(invalidateChild)、布局(layoutChild)顯示子View。而當(dāng)子View需要刷新時(shí),則是通知父View刷新子view來(lái)完成。
View繪制流程
View的繪制是從根節(jié)點(diǎn)開(kāi)始,是一種自上而下的過(guò)程,分別經(jīng)歷測(cè)量、布局、繪制,即:measure、layout、draw
mesasure:負(fù)責(zé)確定view四個(gè)頂點(diǎn)的位置;
layout:確定view最終四個(gè)頂點(diǎn)的位置和寬高
draw:將view繪制到界面中
AsyncTask機(jī)制
?一些方法:
execute串行執(zhí)行(一次只能執(zhí)行一個(gè)任務(wù))
executeOnExecutor并行執(zhí)行(多個(gè)任務(wù)同時(shí)執(zhí)行)
onPreExecute 運(yùn)行在主線程中
doInBackground工作線程
publishProgress工作線程,通過(guò)Handler通知更新UI
工作原理: AnsycTask執(zhí)行任務(wù)時(shí),內(nèi)部會(huì)創(chuàng)建一個(gè)進(jìn)程作用域的線程池來(lái)管理要運(yùn)行的任務(wù),也就就是 說(shuō)當(dāng)你調(diào)用了AsyncTask.execute()后,AsyncTask會(huì)把任務(wù)交給線程池,由線程池來(lái)管理創(chuàng)建Thread和運(yùn)行Therad。最后和UI打交道就交給Handler去處理了
接著問(wèn)線程池問(wèn)題:線程池可以同時(shí)執(zhí)行多少個(gè)TASK
3.0以前核心線程池5個(gè),緩沖線程池10個(gè),最大線程池128個(gè),面試時(shí)畫(huà)圖描述
AsyncTask任務(wù)是串行還是并行?
3.0以前是并行執(zhí)行,3.0以后是串行執(zhí)行,默認(rèn)定義了一個(gè)串行調(diào)度??梢愿鶕?jù)設(shè)置來(lái)調(diào)用串行或者并行方法。
使用AsyncTask遇到過(guò)哪些問(wèn)題? 定義過(guò)AsyncTask為Activity的非靜態(tài)內(nèi)部類(lèi)導(dǎo)致內(nèi)存泄漏,java特性,內(nèi)部類(lèi)持有外部類(lèi)的引用導(dǎo)致的。 解決辦法:定義為靜態(tài)內(nèi)部類(lèi)持有activity的弱引用
如何取消AsyncTask?
AsyncTask.cancle()
為什么不能在子線程更新UI?
android中的UI控件都是非線程安全的,子線程中并發(fā)訪問(wèn)可能會(huì)導(dǎo)致控件處于不可預(yù)期的狀態(tài)
ANR產(chǎn)生的原因是什么?
ANR只會(huì)發(fā)生在主線程中,產(chǎn)生的原因主要是主線程進(jìn)行了耗時(shí)操作超過(guò)固定時(shí)間得不到響應(yīng):
1、耗時(shí)的網(wǎng)絡(luò)操作
2、界面繪制得不到相應(yīng)
3、大量的數(shù)據(jù)讀寫(xiě)操作
ANR定位和修正
ANR產(chǎn)生時(shí), 系統(tǒng)會(huì)生成一個(gè)traces.txt的文件放在/data/anr/下. 開(kāi)發(fā)人員可通過(guò)adb命令將其導(dǎo)出到本地 ($adb pull data/anr/traces.txt .)通過(guò)分析,我們可以根據(jù)具體的日志查看Anr原因( 如: 普通阻塞,CPU滿負(fù)荷,內(nèi)存泄露 )
oom是什么?
內(nèi)存溢出
當(dāng)一個(gè)對(duì)象分配內(nèi)存,當(dāng)前系統(tǒng)沒(méi)有內(nèi)存可供非配時(shí)會(huì)導(dǎo)致內(nèi)存溢出,常見(jiàn)的有圖片加載
什么情況導(dǎo)致oom?
1、圖片加載過(guò)大;
2、重復(fù)創(chuàng)建view
3、一些常見(jiàn)的內(nèi)存泄漏也引起內(nèi)存溢出的原因之一,比如:?jiǎn)卫?、靜態(tài)變量、屬性動(dòng)畫(huà)、Handler等
有什么解決方法可以避免OOM?
1、使用bitmap的inSampleSize采樣率加載大圖,
2、重復(fù)創(chuàng)建view不僅會(huì)造成內(nèi)存溢出,還會(huì)造成界面卡頓,因此重復(fù)的利用view,比如在listview中
3、規(guī)范代碼編程,盡可能少使用靜態(tài)變量,
Oom 是否可以try catch?為什么?
oom不能被try catch,會(huì)直接掛掉
我們都知道Java中異常超類(lèi)時(shí)Throwable,Throwable派生兩個(gè)子類(lèi)Error和Exception,Error是不會(huì)被捕獲得,Exception會(huì)被捕獲,oom繼承Error因此它不會(huì)被try catch
內(nèi)存泄漏是什么?
內(nèi)存泄漏是指當(dāng)前程序申請(qǐng)內(nèi)存,申請(qǐng)的內(nèi)存得不到釋放,這就是內(nèi)存泄漏
什么情況導(dǎo)致內(nèi)存泄漏?
1、靜態(tài)變量引起的內(nèi)存泄漏
2、單例引起的內(nèi)存泄漏
3、屬性動(dòng)畫(huà)引起的內(nèi)存泄漏
4、handler引起的內(nèi)存泄漏
如何防止線程的內(nèi)存泄漏?
1、避免使用靜態(tài)變量引用當(dāng)前activity上下文,引文靜態(tài)變量會(huì)始終常駐內(nèi)存得不到釋放
2、避免過(guò)多的使用單例,單例的實(shí)現(xiàn)也會(huì)用到static
3、屬性動(dòng)畫(huà)中有一類(lèi)無(wú)限循環(huán)的動(dòng)畫(huà),如果當(dāng)前頁(yè)面退出要機(jī)制停止
4、Handler在進(jìn)行跨線程通信中,如果在子線程中持有了外部類(lèi)的引用就得不到及時(shí)釋放,將handler定義為靜態(tài)內(nèi)部類(lèi)并持有外部類(lèi)的弱引用,及時(shí)執(zhí)行removeCallbackAndMessage方法
Android中緩存更新策略 ?
Android的緩存策略是指緩存的添加、獲取和刪除這三類(lèi)操作,但不管是內(nèi)存緩存還是存儲(chǔ)設(shè)備緩存,它們的緩存容量是有限制的,因此針對(duì)這種限制android為我們提供了LRU算法。
LRU的原理 ?
為減少流量消耗,可采用緩存策略。常用的緩存算法是LRU(Least Recently Used):當(dāng)緩存滿時(shí), 會(huì)優(yōu)先淘汰那些近期最少使用的緩存對(duì)象。主要是兩種方式:
LruCache(內(nèi)存緩存):LruCache類(lèi)是一個(gè)線程安全的泛型類(lèi):內(nèi)部采用一個(gè)LinkedHashMap以強(qiáng)引用的方式存儲(chǔ)外界的緩存對(duì)象,并提供get和put方法來(lái)完成緩存的獲取和添加操作,當(dāng)緩存滿時(shí)會(huì)移除較早使用的緩存對(duì)象,再添加新的緩存對(duì)象。
DiskLruCache(磁盤(pán)緩存): 通過(guò)將緩存對(duì)象寫(xiě)入文件系統(tǒng)從而實(shí)現(xiàn)緩存效果
ContentProvider的權(quán)限管理(解答:讀寫(xiě)分離,權(quán)限控制-精確到表級(jí),URL控制)
如何通過(guò)廣播攔截和abort一條短信?
1、自定義一個(gè)SmsReceiver繼承Receiver
2、重寫(xiě)onReciver方法,
3、在onReceiver中監(jiān)聽(tīng)系統(tǒng)短信,如果監(jiān)聽(tīng)到來(lái)了短信,判斷intent.getAction()和系統(tǒng)的廣播action是否相等,如果相等就攔截,調(diào)用abourboardCast()
廣播是否可以請(qǐng)求網(wǎng)絡(luò)?
不可以,廣播默認(rèn)執(zhí)行在主線程中,不能進(jìn)行耗時(shí)操作
廣播引起anr的時(shí)間限制是多少?
10s
計(jì)算一個(gè)view的嵌套層級(jí)
public void getParents(ViewParent parent) {
????if (parent == null) {
????Log.w("parent", "沒(méi)有啦?。?!");
????return;
}
????Log.w("parent", parent.toString());
????getParents(parent.getParent());
}
Android線程有沒(méi)有上限?
線程是cpu的最小執(zhí)行單元,同時(shí)也是一種有線的資源,相對(duì)于系統(tǒng)來(lái)說(shuō),只要系統(tǒng)有足夠的cpu資源,線程就能無(wú)限的開(kāi)啟
線程池有沒(méi)有上限?
有,
核心線程:5個(gè)
緩沖線程:10個(gè)
最大線程:128個(gè)
Android為什么引入Parcelable?
我們來(lái)看一下android兩種序列化的方式,Serializable和Parcelable
Serializable 序列化利用反射的原理,過(guò)程需要大量的I/O操作,性能低
Parcelable 原理是將對(duì)象進(jìn)行分解,分解的部門(mén)都是傳遞可支持的數(shù)據(jù)類(lèi)型,操作不需要用反射,數(shù)據(jù)也存放在 Native 內(nèi)存中,效率要快很多
有沒(méi)有嘗試簡(jiǎn)化Parcelable的使用?
kotlin使用Parcelize注解簡(jiǎn)化Parcelable的書(shū)寫(xiě)
(四)開(kāi)發(fā)中常見(jiàn)的一些問(wèn)題
ListView 中圖片錯(cuò)位的問(wèn)題是如何產(chǎn)生的?
圖片錯(cuò)位的問(wèn)題 原因是使用了緩存,當(dāng)ListView從底網(wǎng)上滑動(dòng)的時(shí)候,當(dāng)最頂部的view移出當(dāng)前屏幕的時(shí)候,底部的進(jìn)入的屏幕的view就復(fù)用了頂部的view,因此如果當(dāng)前view數(shù)據(jù)源沒(méi)有及時(shí)清空就會(huì)導(dǎo)致圖片錯(cuò)位問(wèn)題。
解決辦法:給convertView綁定viewHolder,利用viewHodler的tag機(jī)制解決,預(yù)先給圖片設(shè)置一張默認(rèn)加載圖,同時(shí)也減少重復(fù)創(chuàng)建view的問(wèn)題
混合開(kāi)發(fā)有了解嗎?
混合開(kāi)發(fā)就是在app中嵌套一個(gè)輕量級(jí)的瀏覽器,一部分功能采用html 5來(lái)開(kāi)發(fā),好處就是在不升級(jí)app的情況下就能實(shí)現(xiàn)動(dòng)態(tài)更新,同時(shí)也能在其他客戶端使用。
混合開(kāi)發(fā)最主要的功能就是實(shí)現(xiàn)html5 和native的交互
mWebView.addJavascriptInterface(new JsBridge(), "bxbxbai")
知道哪些混合開(kāi)發(fā)的方式?說(shuō)出它們的優(yōu)缺點(diǎn)和各自使用場(chǎng)景?(解答:比如:RN,weex,H5,小程序,WPA等。做Android的了解一些前- 端js等還是很有好處的);
屏幕適配的處理技巧都有哪些?

動(dòng)態(tài)布局的理解
動(dòng)態(tài)布局相對(duì)靜態(tài)布局xml相比,它不是可視化,需要運(yùn)行起來(lái)才能看見(jiàn)效果,但它忽略了將xml轉(zhuǎn)化為布局代碼,提高了效率;
動(dòng)態(tài)布局使用較為靈活,但是需要技巧,需要掌握常見(jiàn)的集中布局的屬性設(shè)置。
怎么去除重復(fù)代碼?
項(xiàng)目越大,activity或者fragment就會(huì)越多,因此難免會(huì)有一些重復(fù)的代碼,
1、設(shè)置Base(基)activity和fragment
2、采用提煉技巧,提煉方法,抽象基類(lèi),提煉常量
3、使用include減少布局重復(fù),原理:引用其他布局,id要相同,
4、用ViewStub減少整體的布局的重復(fù),適合整體相同,局部不同的情況
畫(huà)出 Android 的大體架構(gòu)圖
Linux內(nèi)核:
????????Android是基于Linux內(nèi)核開(kāi)發(fā)
????????Linux提供了安全、內(nèi)存管理、進(jìn)程管理等服務(wù)。
系統(tǒng)庫(kù)和Android運(yùn)行時(shí):
????????系統(tǒng)庫(kù)是一個(gè)C/C++庫(kù)的集合,包含OpenGL,SQlite等,在開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)者通過(guò)框架層來(lái)調(diào)用這些庫(kù)
????????Android虛擬機(jī)位于Android運(yùn)行時(shí)
框架層:
????????框架成提供了日常開(kāi)發(fā)所用的API包管理器、內(nèi)容提供者等位于此層
應(yīng)用程序?qū)樱?/p>
????????包含了一些原生應(yīng)用程序,如日歷、短信等
Recycleview和ListView的區(qū)別
布局:
? ??Recycleview 支持橫向/縱向布局、流式布局、瀑布流;ListView僅支持橫向布局
點(diǎn)擊事件:
? ? ? Recycleview不支持itemClick事件,ListView支持
動(dòng)畫(huà):
? ??????Recycleview 支持item動(dòng)畫(huà),ListView不支持
ViewHolder:
? ? ? ? 我們都知道ViewHolder是保存視圖引用的類(lèi),在ListView中ViewHolder可用可不用,用需要自定義,而RecyclerView中則必須使用,RecyclerView.ViewHolder
緩存機(jī)制:ListView緩存機(jī)制是RecyclerBin,RecyclerView是Recycler和ViewHolder配合使用
動(dòng)態(tài)權(quán)限適配方案,權(quán)限組的概念
我們每個(gè)程序機(jī)會(huì)都會(huì)用到用戶權(quán)限,權(quán)限提醒分為,系統(tǒng)彈窗和自定義彈窗,自定義彈窗一般用于用戶拒絕系統(tǒng)彈窗的提醒窗口后并不再提醒后,我們?yōu)榱擞脩趔w驗(yàn),自己后臺(tái)檢測(cè)比較人性化的一種彈窗體驗(yàn)。


Android系統(tǒng)為什么會(huì)設(shè)計(jì)ContentProvider?
如果我們項(xiàng)目中有需求要使用通訊錄、短信等內(nèi)容,假如說(shuō):我們讀取內(nèi)容后將內(nèi)容以數(shù)據(jù)庫(kù)、SP或者xml的形式保存到本地,當(dāng)數(shù)據(jù)來(lái)源發(fā)生改變時(shí),那么我們保存的內(nèi)容也需要修改,這就造成了很大的關(guān)聯(lián)性的問(wèn)題,因此系統(tǒng)為開(kāi)發(fā)者提供了用于不同程序之間共享數(shù)據(jù)(跨境成通信)的一種方式ContentPrivoder;
ContentProvider厲害的地方在于:
1、封裝、對(duì)數(shù)據(jù)進(jìn)行了封裝、提供統(tǒng)一接口,當(dāng)數(shù)據(jù)來(lái)源改變時(shí),程序不需要做任何修改
2、提供了一種跨進(jìn)程數(shù)據(jù)共享的方式
既然是對(duì)外提供數(shù)據(jù)共享,那么如何限制對(duì)方的使用呢?
答:android:exported屬性非常重要 true可以交互,false不能交互,同一app組件可以使用
ContentProvider接口方法運(yùn)行在哪個(gè)線程中呢?
答:配置文件中有一個(gè)叫android:multiprocess,false為單例,true為每個(gè)進(jìn)程創(chuàng)建一個(gè)實(shí)例
ContentProvider和調(diào)用者在同一個(gè)進(jìn)程,ContentProvider的增刪查改方法和調(diào)用者在同一線程中;
ContentProvider和調(diào)用者在不同的進(jìn)程,ContentProvider的方法會(huì)運(yùn)行在它自身所在進(jìn)程的一個(gè)Binder線程中。?
ContentProvider是如何在不同應(yīng)用程序之間傳輸數(shù)據(jù)的?
答:
下拉狀態(tài)欄是不是影響activity的生命周期
不會(huì)
Bitmap 使用時(shí)候注意什么?
內(nèi)存溢出:
使用緩存
Bitmap的recycler()
Bitmap對(duì)象占用的內(nèi)存分為兩部分:JVM分配和native分配,jvm分配的由GC自動(dòng)回收,native分配的執(zhí)行recycler()方法才能回收,recycler()并不會(huì)立即回收掉,等待下一次GC工作之前才會(huì)被回收掉,當(dāng)前目前的android版本即使不調(diào)用這個(gè)方法,系統(tǒng)也會(huì)自動(dòng)執(zhí)行recycler回收native部分內(nèi)存
Android中開(kāi)啟攝像頭的主要步驟
1、配置文件中添加權(quán)限
2、?要將攝像頭捕獲的圖像實(shí)時(shí)地顯示在手機(jī)上,使用surfaceView
3、設(shè)置窗口的顯示方式
LRUCache原理
LRUCache是一個(gè)線程安全的泛型類(lèi),它內(nèi)部維護(hù)了一個(gè)LinkHashMap以強(qiáng)引用的方式對(duì)外緩存對(duì)象,并提供get和put方法用來(lái)獲取和添加緩存,它內(nèi)部原理是刪除掉最近最少使用的緩存,添加新的緩存。
MVC、MVP、MVVM
MVC:Model(數(shù)據(jù)模型層)、View(視圖展示層)、Controller(業(yè)務(wù)邏輯層)
MVP:Model(數(shù)據(jù)模型層)、View(視圖展示層)、Presenter(業(yè)務(wù)邏輯層)
MVP可以降低代碼耦合度,提高代碼的結(jié)構(gòu)清晰度、可讀性更高、復(fù)用性更強(qiáng)。
具體些來(lái)說(shuō)(參考JessYan的例子):
現(xiàn)在有這么一個(gè)需求:Activity中從網(wǎng)絡(luò)獲取數(shù)據(jù)然后展示在A控件上。
如果不用MVP的話,那就直接把獲取展示等代碼都寫(xiě)在Activity中,很快便可以寫(xiě)完。
但現(xiàn)在需求變動(dòng)了:
1.要求加入緩存功能,如果本地有數(shù)據(jù),則先從本地獲取數(shù)據(jù),然后再?gòu)木W(wǎng)絡(luò)獲取最新數(shù)據(jù)進(jìn)行替換
2.要求數(shù)據(jù)展示在B控件上而不是A控件。
如果代碼都是你自己寫(xiě)的,那改起來(lái)還比較輕松,但假如是團(tuán)隊(duì)開(kāi)發(fā),代碼不是你寫(xiě)的,你需要花時(shí)間把邏輯重新看一遍再開(kāi)始改,而且如果改錯(cuò)的話,會(huì)影響之前已經(jīng)寫(xiě)好的功能。
但使用MVP模式進(jìn)行開(kāi)發(fā)就不同了。由于它的分工結(jié)構(gòu)清晰,V層僅負(fù)責(zé)數(shù)據(jù)展示,P層僅負(fù)責(zé)業(yè)務(wù)邏輯,M層僅負(fù)責(zé)數(shù)據(jù)獲取/處理。所以改動(dòng)起來(lái)就輕松很多。
對(duì)于變動(dòng)的需求1:我們只需在P層加入邏輯判斷(先從本地獲取,再網(wǎng)絡(luò)獲?。缓驧層增加一個(gè)從本地獲取數(shù)據(jù)方法。
對(duì)于變動(dòng)的需求2:我們只需在V層修改獲取到數(shù)據(jù)后的展示方式,從控件A改成控件B。