轉(zhuǎn)載請(qǐng)注明出處:http://www.reibang.com/p/cbac49563ace
1. ThreadLocal的理解
可以保證線程的安全。在多個(gè)線程共享相同的數(shù)據(jù)的時(shí)候摊趾,會(huì)為每個(gè)線程創(chuàng)建單獨(dú)的副本币狠,在單獨(dú)的副本上進(jìn)行數(shù)據(jù)的操作,不會(huì)對(duì)其它線程的數(shù)據(jù)產(chǎn)生影響砾层,保證了線程安全漩绵。
2. HashMap HashSet HashTable的區(qū)別?
都是集合肛炮,底層都是Hash算法實(shí)現(xiàn)的止吐。HashMap是Hashtable的替代品,這兩個(gè)都是雙列集合侨糟,而HashSet是單列集合碍扔。HashMap線程不安全、效率高秕重、可以存儲(chǔ)null鍵和null值不同;Hashtable線程安全,效率低溶耘,不可以存儲(chǔ)null鍵和null值二拐。
3. 如何讓HashMap可以線程安全?
HashMap 在并發(fā)執(zhí)行 put 操作時(shí)會(huì)引起死循環(huán)凳兵,導(dǎo)致 CPU 利用率接近100%百新。因?yàn)槎嗑€程會(huì)導(dǎo)致 HashMap 的 Node 鏈表形成環(huán)形數(shù)據(jù)結(jié)構(gòu),一旦形成環(huán)形數(shù)據(jù)結(jié)構(gòu)庐扫,Node 的 next 節(jié)點(diǎn)永遠(yuǎn)不為空饭望,就會(huì)在獲取 Node 時(shí)產(chǎn)生死循環(huán)澜倦。
使用下面三種替換方式:
Hashtable
ConcurrentHashMap
Synchronized Map
4. Android對(duì)HashMap做了優(yōu)化后推出的新的容器類是什么?
SparseArray
它要比 HashMap 節(jié)省內(nèi)存杰妓,某些情況下比HashMap性能更好藻治,按照官方問答的解釋,主要是因?yàn)镾parseArray不需要對(duì)key和value進(jìn)行auto-boxing(將原始類型封裝為對(duì)象類型巷挥,比如把int類型封裝成Integer類型)桩卵,結(jié)構(gòu)比HashMap簡(jiǎn)單(SparseArray內(nèi)部主要使用兩個(gè)一維數(shù)組來保存數(shù)據(jù),一個(gè)用來存key倍宾,一個(gè)用來存value)不需要額外的額外的數(shù)據(jù)結(jié)構(gòu)(主要是針對(duì)HashMap中的HashMapEntry而言的)雏节。
5. Java多線程之間如何通信
等待喚醒機(jī)制
6. 線程池的實(shí)現(xiàn)機(jī)制
向線程池提交任務(wù),會(huì)依次啟動(dòng)核心線程高职,如果提交的任務(wù)數(shù)超過了核心線程數(shù)钩乍,會(huì)將任務(wù)保存到阻塞隊(duì)列中,如果阻塞隊(duì)列也滿了怔锌,且繼續(xù)提交任務(wù)寥粹,則會(huì)創(chuàng)建新線程執(zhí)行任務(wù),直到任務(wù)數(shù)達(dá)到最大線程數(shù)埃元。此時(shí)如果再提交任務(wù)的話會(huì)拋出異忱缘樱或者直接丟棄任務(wù)。通過Executor.execute()無法得到返回值岛杀,通過ExecutorService.submit()可以得到返回值阔拳。
7. RxJava中map和flatmap操作符的區(qū)別及底層實(shí)現(xiàn)
Map返回的是結(jié)果集,flatmap返回的是包含結(jié)果集的Observable类嗤。Map只能一對(duì)一糊肠,flatmap可以一對(duì)多、多對(duì)多遗锣。
RxJava是通過觀察者模式實(shí)現(xiàn)的货裹。
8. 對(duì)消息機(jī)制中Looper的理解
Looper在消息機(jī)制中扮演的角色是創(chuàng)造無限循環(huán)從Messagequeue中取得消息然后分發(fā)。
9. 單例模式有哪些實(shí)現(xiàn)方式
餓漢模式(線程安全黄伊,調(diào)用效率高泪酱,但是不能延時(shí)加載)
懶漢模式(線程安全,調(diào)用效率不高还最,但是能延時(shí)加載)
雙重檢測(cè)鎖模式(由于JVM底層模型原因墓阀,偶爾會(huì)出問題,不建議使用)
靜態(tài)內(nèi)部類式(線程安全拓轻,調(diào)用效率高斯撮,可以延時(shí)加載)
枚舉類(線程安全,調(diào)用效率高扶叉,不能延時(shí)加載勿锅,可以天然的防止反射和反序列化調(diào)用)
10. 通過靜態(tài)內(nèi)部類實(shí)現(xiàn)單例模式有哪些優(yōu)點(diǎn)
線程安全帕膜,調(diào)用效率高,可以延時(shí)加載
11. synchronized volatile關(guān)鍵字有什么區(qū)別溢十?以及還有哪些同樣功能的關(guān)鍵字
(1) volatile是變量修飾符智绸,而synchronized則作用于一段代碼或者方法适篙。
(2) volatile只是在線程內(nèi)存和main memory(主內(nèi)存)間同步某個(gè)變量的值粉臊;而synchronized通過鎖定和解鎖某個(gè)監(jiān)視器同步所有變量的值意推。顯然synchronized要比volatile消耗更多資源。
const吞鸭、final寺董、lock
12. 界面卡頓的原因有哪些?
UI線程(main)有耗時(shí)操作
視圖渲染時(shí)間過長(zhǎng)刻剥,導(dǎo)致卡頓
13. 造成OOM/ANR 的原因遮咖?
OOM: (1)不恰當(dāng)?shù)厥褂胹tatic關(guān)鍵字 (2)內(nèi)部類對(duì)Activity的引用 (3)大量Bitmap的使用會(huì)導(dǎo)致程序包運(yùn)行時(shí)的內(nèi)存消耗變大 (4)游標(biāo)Cursor對(duì)象用完應(yīng)該及時(shí)關(guān)閉 (5)加載對(duì)象過大 (6)相應(yīng)資源過多,來不及釋放造虏。
ANR: (1)在5秒內(nèi)沒有響應(yīng)輸入的事件(IO操作耗時(shí)御吞、數(shù)據(jù)庫操作復(fù)雜耗時(shí)、主線程非主線程產(chǎn)生死鎖等待酗电、網(wǎng)絡(luò)加載/圖片操作耗時(shí)魄藕、硬件操作耗時(shí)) (2)BroadcastReceiver在10秒內(nèi)沒有執(zhí)行完畢(Service binder數(shù)量達(dá)到上限内列、Service忙導(dǎo)致超時(shí)無響應(yīng))
14. Activity與Fragment生命周期有何聯(lián)系
在創(chuàng)建的過程中,是Activity帶領(lǐng)著Fragment,在銷毀的過程中,是Fragment帶領(lǐng)著Activity撵术。
15. Glide三級(jí)緩存
內(nèi)存緩存,磁盤緩存话瞧、網(wǎng)絡(luò)緩存(由于網(wǎng)絡(luò)緩存嚴(yán)格來說不算是緩存的一種嫩与,故也稱為二級(jí)緩存)。緩存的資源分為兩種:原圖(SOURCE)交排、處理圖(RESULT)(默認(rèn))划滋。
內(nèi)存緩存:默認(rèn)開啟的,可以通過調(diào)用skipMemoryCache(true)來設(shè)置跳過內(nèi)存緩存埃篓,緩存最大空間:每個(gè)進(jìn)程可用的最大內(nèi)存*0.4处坪。(低配手機(jī)0.33)
磁盤緩存:分為四種:ALL(緩存原圖)、NONE(什么都不緩存)架专、SOURCE(只緩存原圖)同窘、RESULT(之后處理圖),通過diskCacheStrategy(DiskCacheStrategy.ALL)來設(shè)置部脚,緩存大小250M想邦。
16. MVC、MVP委刘、MVVM的原理
(1) MVC丧没,Model View Controller鹰椒,是軟件架構(gòu)中最常見的一種框架,簡(jiǎn)單來說就是通過controller的控制去操作model層的數(shù)據(jù)呕童,并且返回給view層展示漆际。當(dāng)用戶發(fā)出事件的時(shí)候,view層會(huì)發(fā)送指令到controller層夺饲,接著controller去通知model層更新數(shù)據(jù)灿椅,model層更新完數(shù)據(jù)以后直接顯示在view層上,這就是MVC的工作原理钞支。
(2) MVP是MVC的演化茫蛹。MVP的model層相對(duì)于MVC是一樣的,而activity和fragment不再是controller層烁挟,而是純粹的view層婴洼,所有關(guān)于用戶事件的轉(zhuǎn)發(fā)全部交由presenter層處理。presenter層充當(dāng)了橋梁的作用撼嗓,用于操作view層發(fā)出的事件傳遞到presenter層中柬采,presenter層去操作model層,并且將數(shù)據(jù)返回給view層且警。
(3) MVVM和MVP的區(qū)別貌似不大粉捻,只不過是presenter層換成了viewmodel層,還有一點(diǎn)就是view層和viewmodel層是相互綁定的關(guān)系斑芜,這意味著當(dāng)你更新viewmodel層的數(shù)據(jù)的時(shí)候肩刃,view層會(huì)相應(yīng)的變動(dòng)ui。
17. 數(shù)據(jù)庫的操作類型有哪些杏头,如何導(dǎo)入外部數(shù)據(jù)庫盈包?
(1) 增刪改查
(2) 將外部數(shù)據(jù)庫放在項(xiàng)目的res/raw目錄下。因?yàn)榘沧肯到y(tǒng)下數(shù)據(jù)庫要放在data/data/packagename/databases的目錄下,然后要做的就是將外部數(shù)據(jù)庫導(dǎo)入到該目錄下醇王,操作方法是通過FileInputStream讀取外部數(shù)據(jù)庫呢燥,再用FileOutputStrean把讀取到的東西寫入到該目錄下。
18. 是否使用過 IntentService寓娩,作用是什么叛氨, AIDL 解決了什么問題?
(1) IntentService繼承自Service棘伴。由于Service運(yùn)行在主線程寞埠,無法進(jìn)行耗時(shí)操作。所以你需要在Service中開啟一個(gè)子線程排嫌,并且在子線程中運(yùn)行畸裳。為了簡(jiǎn)化這一操作,Android中提供了IntentService來進(jìn)行這一處理淳地。通過查看IntentService的源碼可以看到怖糊,在onCreate中帅容,我們開啟了一個(gè)HandlerThread線程,之后獲取HandlerThread線程中的Looper伍伤,并通過這個(gè)Looper創(chuàng)建了一個(gè)Handler并徘。然后在onStart方法中通過這個(gè)Handler將intent與startId作為Message的參數(shù)進(jìn)行發(fā)送到消息隊(duì)列中,然后交由Handler中的handleMessage中進(jìn)行處理扰魂。由于在onStart方法是在主線程內(nèi)運(yùn)行的麦乞,而Handler是通過工作者線程HandlerThread中的Looper創(chuàng)建的。所以也就是在主線程中發(fā)送消息劝评,在工作者接收到消息后便可以進(jìn)行一些耗時(shí)的操作姐直。
(2) 進(jìn)程間通信
19. 是否使用過本地廣播,和全局廣播有什么差別蒋畜?
本地廣播的數(shù)據(jù)在本應(yīng)用范圍內(nèi)傳播声畏,不用擔(dān)心隱私數(shù)據(jù)泄露的問題。不用擔(dān)心別的應(yīng)用偽造廣播姻成,造成安全隱患插龄。相比在系統(tǒng)內(nèi)發(fā)送全局廣播,它更高效科展。
20. Activity均牢、 Window、 View 三者的差別才睹, fragment 的特點(diǎn)徘跪?
(1) Activity像一個(gè)工匠(控制單元),Window像窗戶(承載模型)砂竖,View像窗花(顯示視圖) LayoutInflater像剪刀真椿,Xml配置像窗花圖紙。
(2) a. Fragment可以作為Activity界面的一部分組成出現(xiàn)乎澄;
b. 可以在一個(gè)Activity中同時(shí)出現(xiàn)多個(gè)Fragment,并且一個(gè)Fragment也可以在多個(gè)Activity中使用测摔;
c. 在Activity運(yùn)行過程中置济,可以添加、移除或者替換Fragment锋八;
d. Fragment可以響應(yīng)自己的輸入事件浙于,并且有自己的生命周期,它們的生命周期會(huì)受宿主Activity的生命周期影響挟纱。
21. Handler羞酗、 Thread 和 HandlerThread 的差別
從Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android的Thread沒有對(duì)Java的Thread做任何封裝紊服,但是Android提供了一個(gè)繼承自Thread的類HandlerThread(android.os.HandlerThread -> java.lang.Thread)檀轨,這個(gè)類對(duì)Java的Thread做了很多便利Android系統(tǒng)的封裝胸竞。
android.os.Handler可以通過Looper對(duì)象實(shí)例化,并運(yùn)行于另外的線程中参萄,Android提供了讓Handler運(yùn)行于其它線程的線程實(shí)現(xiàn)卫枝,也是就HandlerThread。HandlerThread對(duì)象start后可以獲得其Looper對(duì)象讹挎,并且使用這個(gè)Looper對(duì)象實(shí)例Handler校赤。
22. 低版本 SDK 實(shí)現(xiàn)高版本 api
自己實(shí)現(xiàn)或使用注解@TargetApi annotation
23. launch mode 應(yīng)用場(chǎng)景
(1) standard:標(biāo)準(zhǔn)的啟動(dòng)模式。
(2) singleTop:?jiǎn)我豁敳磕J?/h5>
如果Activity已經(jīng)被開啟筒溃,并且處于任務(wù)棧的棧頂马篮,就不會(huì)創(chuàng)建新的Activity,而是復(fù)用這個(gè)已經(jīng)開啟的Activity怜奖。
為了防止出現(xiàn)一些奇怪的用戶體驗(yàn)积蔚,推薦使用單一頂部模式,整個(gè)任務(wù)椃持埽可以有多個(gè)實(shí)例存在.
應(yīng)用場(chǎng)景:短信發(fā)送界面.
(3)singletask:?jiǎn)我蝗蝿?wù)棧
在整個(gè)任務(wù)棧里面只允許有一個(gè)當(dāng)前Activity的實(shí)例存在
如果要開啟的Activity在任務(wù)棧中已經(jīng)存在尽爆,直接復(fù)用這個(gè)已經(jīng)存在的Activity,并且把這個(gè)Activity上面的所有的其他Activity給清空
應(yīng)用場(chǎng)景:如果一個(gè)Activity非常消耗內(nèi)存和cpu資源读慎,建議把這個(gè)Activity做成singletask的模式漱贱。瀏覽器的browserActivity
(4)singleinstance:?jiǎn)我粚?shí)例.
整個(gè)手機(jī)操作系統(tǒng)只有一個(gè)實(shí)例存在,并且是運(yùn)行在自己?jiǎn)为?dú)的任務(wù)棧里面.
應(yīng)用場(chǎng)景:通話界面的Activity
24. touch 事件傳遞流程
事件處理包括三種情況,分別為:傳遞—-dispatchTouchEvent()函數(shù)夭委、攔截——onInterceptTouchEvent()函數(shù)幅狮、消費(fèi)—-onTouchEvent()函數(shù)和OnTouchListener。
Android事件傳遞流程:
(1) 事件都是從Activity.dispatchTouchEvent()開始傳遞
(2) 事件由父View傳遞給子View株灸,ViewGroup可以通過onInterceptTouchEvent()方法對(duì)事件攔截崇摄,停止其向子view傳遞
(3) 如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費(fèi)事件慌烧,事件會(huì)反向往上傳遞逐抑,這時(shí)父View(ViewGroup)可以進(jìn)行消費(fèi),如果還是沒有被消費(fèi)的話屹蚊,最后會(huì)到Activity的onTouchEvent()函數(shù)厕氨。
(4) 如果View沒有對(duì)ACTION_DOWN進(jìn)行消費(fèi),之后的其他事件不會(huì)傳遞過來汹粤,也就是說ACTION_DOWN必須返回true命斧,之后的事件才會(huì)傳遞進(jìn)來
(5) OnTouchListener優(yōu)先于onTouchEvent()對(duì)事件進(jìn)行消費(fèi)
View不處理事件流程圖
View處理事件流程圖
事件攔截
25.Android性能優(yōu)化
一、代碼優(yōu)化
1.使用AndroidLint分析結(jié)果進(jìn)行相應(yīng)優(yōu)化
2.不使用枚舉及IOC框架嘱兼,反射性能低
3.常量加static
4.靜態(tài)方法
5.減少不必要的對(duì)象国葬、成員變量
6.盡量使用線程池
7.適當(dāng)使用軟引用和弱引用
8.盡量使用靜態(tài)內(nèi)部類,避免潛在的內(nèi)存泄露
9.圖片緩存,采用內(nèi)存緩存LRUCache和硬盤緩存DiskLRUCache
10.Bitmap優(yōu)化汇四,采用適當(dāng)分辨率大小并及時(shí)回收
二接奈、布局優(yōu)化
避免OverDraw過渡繪制
優(yōu)化布局層級(jí)
避免嵌套過多無用布局
當(dāng)我們?cè)诋嫴季值臅r(shí)候,如果能實(shí)現(xiàn)相同的功能船殉,優(yōu)先考慮相對(duì)布局鲫趁,然后在考慮別的布局,不要用絕對(duì)布局利虫。
使用<include />標(biāo)簽把復(fù)雜的界面需要抽取出來
使用<merge />標(biāo)簽挨厚,因?yàn)樗趦?yōu)化UI結(jié)構(gòu)時(shí)起到很重要的作用。目的是通過刪減多余或者額外的層級(jí)糠惫,從而優(yōu)化整個(gè)Android Layout的結(jié)構(gòu)疫剃。核心功能就是減少冗余的層次從而達(dá)到優(yōu)化UI的目的!
ViewStub 是一個(gè)隱藏的硼讽,不占用內(nèi)存空間的視圖對(duì)象巢价,它可以在運(yùn)行時(shí)延遲加載布局資源文件。
三固阁、ListView和GridView優(yōu)化
1.采用ViewHolder復(fù)用convertView
2.避免在getView中執(zhí)行耗時(shí)操作
3.列表在滑動(dòng)狀態(tài)時(shí)不加載圖片
4.開啟硬件加速
26.Android內(nèi)存泄漏
內(nèi)存泄漏簡(jiǎn)單地說就是申請(qǐng)了一塊內(nèi)存空間壤躲,使用完畢后沒有釋放掉。它的一般表現(xiàn)方式是程序運(yùn)行時(shí)間越長(zhǎng)备燃,占用內(nèi)存越多碉克,最終用盡全部?jī)?nèi)存,整個(gè)系統(tǒng)崩潰并齐。由程序申請(qǐng)的一塊內(nèi)存漏麦,且沒有任何一個(gè)指針指向它,那么這塊內(nèi)存就泄露了况褪∷赫辏可能的原因有:
1.注冊(cè)沒取消造成內(nèi)存泄露,如:廣播
2.靜態(tài)變量持有Activity的引用
3.單例模式持有Activity的引用
4.查詢數(shù)據(jù)庫后沒有關(guān)閉游標(biāo)cursor
5.構(gòu)造Adapter時(shí)测垛,沒有使用 convertView 重用
6.Bitmap對(duì)象不在使用時(shí)調(diào)用recycle()釋放內(nèi)存
7.對(duì)象被生命周期長(zhǎng)的對(duì)象引用捏膨,如activity被靜態(tài)集合引用導(dǎo)致activity不能釋放
8.使用Handler造成的內(nèi)存泄露