最近金三銀四典阵,相信不少朋友都在躍躍欲動,看看市場機會谣妻,連夜整理了一波Android高級開發(fā)面試題目萄喳,幫你助力卒稳!
Java基礎(chǔ)
1蹋半、內(nèi)部類的作用
內(nèi)部類可以用多個實例,每個實例都有自己的狀態(tài)信息充坑,并且與其他外圍對象的信息相互獨立减江。
在單個外部類中,可以讓多個內(nèi)部類以不同的方式實現(xiàn)同一個接口捻爷,或者繼承同一個類辈灼。
創(chuàng)建內(nèi)部類對象的時刻并不依賴于外圍類對象的創(chuàng)建。
內(nèi)部類并沒有令人迷惑的“is-a”關(guān)系也榄,他就是一個獨立的實體巡莹。
內(nèi)部類提供了更好的封裝,除了該外圍類甜紫,其他類都不能訪問
2降宅、父類的靜態(tài)方法能否被子類重寫,為什么囚霸?
不能
子類繼承父類后腰根,用相同的靜態(tài)方法和非靜態(tài)方法,這時非靜態(tài)方法覆蓋父類中的方法(即方法重寫)拓型,父類的該靜態(tài)方法被隱藏(如果對象是父類則調(diào)用該隱藏的方法)额嘿,另外子類可繼承父類的靜態(tài)與非靜態(tài)方法,至于方法重載我覺得它其中一要素就是在同一類中劣挫,不能說父類中的什么方法與子類里的什么方法是方法重載的體現(xiàn)
3册养、哪些情況下的對象會被垃圾回收機制處理掉
Java垃圾回收機制最基本的做法是分代回收。內(nèi)存中的區(qū)域被劃分成不同的世代压固,對象根據(jù)其存活的時間被保存在對應(yīng)世代的區(qū)域中球拦。一般的實現(xiàn)是劃分成3個世代:年輕、年老和永久。內(nèi)存的分配是發(fā)生在年輕世代中的刘莹。當(dāng)一個對象存活時間足夠長的時候阎毅,它就會被復(fù)制到年老世代中。對于不同的世代可以使用不同的垃圾回收算法点弯。進行世代劃分的出發(fā)點是對應(yīng)用中對象存活時間進行研究之后得出的統(tǒng)計規(guī)律扇调。一般來說,一個應(yīng)用中的大部分對象的存活時間都很短抢肛。比如局部變量的存活時間就只在方法的執(zhí)行過程中狼钮。基于這一點捡絮,對于年輕世代的垃圾回收算法就可以很有針對性熬芜。
4、進程和線程的區(qū)別
簡而言之,一個程序至少有一個進程,一個進程至少有一個線程福稳。
線程的劃分尺度小于進程涎拉,使得多線程程序的并發(fā)性高。
另外的圆,進程在執(zhí)行過程中擁有獨立的內(nèi)存單元鼓拧,而多個線程共享內(nèi)存,從而極大地提高了程序的運行效率越妈。
線程在執(zhí)行過程中與進程還是有區(qū)別的季俩。每個獨立的線程有一個程序運行的入口、順序執(zhí)行序列和程序的出口梅掠。但是線程不能夠獨立執(zhí)行酌住,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制阎抒。
從邏輯角度來看酪我,多線程的意義在于一個應(yīng)用程序中,有多個執(zhí)行部分可以同時執(zhí)行挠蛉。但操作系統(tǒng)并沒有將多個線程看做多個獨立的應(yīng)用祭示,來實現(xiàn)進程的調(diào)度和管理以及資源分配。這就是進程和線程的重要區(qū)別谴古。
進程是具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運行活動,進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位.
線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
一個線程可以創(chuàng)建和撤銷另一個線程;同一個進程中的多個線程之間可以并發(fā)執(zhí)行.
進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式质涛。進程有獨立的地址空間,一個進程崩潰后掰担,在保護模式下不會對其它進程產(chǎn)生影響汇陆,而線程只是一個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量带饱,但線程之間沒有單獨的地址空間毡代,一個線程死掉就等于整個進程死掉阅羹,所以多進程的程序要比多線程的程序健壯,但在進程切換時教寂,耗費資源較大捏鱼,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作酪耕,只能用線程导梆,不能用進程。如果有興趣深入的話迂烁,我建議你們看看《現(xiàn)代操作系統(tǒng)》或者《操作系統(tǒng)的設(shè)計與實現(xiàn)》看尼。對就個問題說得比較清楚。
5盟步、HashMap的實現(xiàn)原理
HashMap概述:HashMap是基于哈希表的Map接口的非同步實現(xiàn)藏斩。此實現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵却盘。此類不保證映射的順序狰域,特別是它不保證該順序恒久不變。
HashMap的數(shù)據(jù)結(jié)構(gòu):在java編程語言中谷炸,最基本的結(jié)構(gòu)就是兩種北专,一個是數(shù)組,另外一個是模擬指針(引用)旬陡,所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個基本結(jié)構(gòu)來構(gòu)造的,HashMap也不例外语婴。HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結(jié)構(gòu)描孟,即數(shù)組和鏈表的結(jié)合體。
HashMap底層就是一個數(shù)組結(jié)構(gòu)砰左,數(shù)組中的每一項又是一個鏈表匿醒。當(dāng)新建一個HashMap的時候,就會初始化一個數(shù)組缠导。
6廉羔、String、StringBuffer僻造、StringBuilder區(qū)別
String 字符串常量
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)
簡要的說憋他, String 類型和 StringBuffer 類型的主要性能區(qū)別其實在于 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同于生成了一個新的 String 對象,然后將指針指向新的 String 對象髓削,所以經(jīng)常改變內(nèi)容的字符串最好不要用String 竹挡,因為每次生成對象都會對系統(tǒng)性能產(chǎn)生影響,特別當(dāng)內(nèi)存中無引用對象多了以后,JVM 的 GC 就會開始工作立膛,那速度是一定會相當(dāng)慢的揪罕。
而如果是使用 StringBuffer 類則結(jié)果就不一樣了梯码,每次結(jié)果都會對 StringBuffer 對象本身進行操作嚷兔,而不是生成新的對象模庐,再改變對象引用属铁。所以在一般情況下我們推薦使用 StringBuffer 行剂,特別是字符串對象經(jīng)常改變的情況下埠况。而在某些特別情況下敦迄, String 對象的字符串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接鲜滩,所以這些時候 String 對象的速度并不會比 StringBuffer 對象慢搭独,而特別是以下的字符串對象生成中搅窿, String 效率是遠要比 StringBuffer 快的:
在大部分情況下 StringBuffer > String
Java.lang.StringBuffer線程安全的可變字符序列嘁酿。一個類似于 String 的字符串緩沖區(qū),但不能修改男应。雖然在任意時間點上它都包含某種特定的字符序列闹司,但通過某些方法調(diào)用可以改變該序列的長度和內(nèi)容。
可將字符串緩沖區(qū)安全地用于多個線程沐飘∮巫可以在必要時對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發(fā)生的耐朴,該順序與所涉及的每個線程進行的方法調(diào)用順序一致借卧。
StringBuffer 上的主要操作是 append 和 insert 方法,可重載這些方法筛峭,以接受任意類型的數(shù)據(jù)铐刘。每個方法都能有效地將給定的數(shù)據(jù)轉(zhuǎn)換成字符串,然后將該字符串的字符追加或插入到字符串緩沖區(qū)中影晓。append 方法始終將這些字符添加到緩沖區(qū)的末端镰吵;而 insert 方法則在指定的點添加字符。
在大部分情況下 StringBuilder > StringBuffer
java.lang.StringBuilder一個可變的字符序列是5.0新增的挂签。此類提供一個與 StringBuffer 兼容的 API疤祭,但不保證同步。該類被設(shè)計用作 StringBuffer 的一個簡易替換饵婆,用在字符串緩沖區(qū)被單個線程使用的時候(這種情況很普遍)勺馆。如果可能,建議優(yōu)先采用該類侨核,因為在大多數(shù)實現(xiàn)中草穆,它比 StringBuffer 要快。兩者的方法基本相同
7芹关、什么導(dǎo)致線程阻塞
線程的阻塞
為了解決對共享存儲區(qū)的訪問沖突续挟,Java 引入了同步機制,現(xiàn)在讓我們來考察多個線程對共享資源的訪問侥衬,顯然同步機制已經(jīng)不夠了诗祸,因為在任意時刻所要求的資源不一定已經(jīng)準(zhǔn)備好了被訪問跑芳,反過來,同一時刻準(zhǔn)備好了的資源也可能不止一個直颅。為了解決這種情況下的訪問控制問題博个,Java 引入了對阻塞機制的支持.
阻塞指的是暫停一個線程的執(zhí)行以等待某個條件發(fā)生(如某資源就緒),學(xué)過操作系統(tǒng)的同學(xué)對它一定已經(jīng)很熟悉了功偿。Java 提供了大量方法來支持阻塞盆佣,下面讓我們逐一分析。
sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數(shù)械荷,它使得線程在指定的時間內(nèi)進入阻塞狀態(tài)共耍,不能得到CPU 時間,指定的時間一過吨瞎,線程重新進入可執(zhí)行狀態(tài)痹兜。 典型地,sleep() 被用在等待某個資源就緒的情形:測試發(fā)現(xiàn)條件不滿足后颤诀,讓線程阻塞一段時間后重新測試字旭,直到條件滿足為止。
suspend() 和 resume() 方法:兩個方法配套使用崖叫,suspend()使得線程進入阻塞狀態(tài)遗淳,并且不會自動恢復(fù),必須其對應(yīng)的resume() 被調(diào)用心傀,才能使得線程重新進入可執(zhí)行狀態(tài)屈暗。典型地,suspend() 和 resume() 被用在等待另一個線程產(chǎn)生的結(jié)果的情形:測試發(fā)現(xiàn)結(jié)果還沒有產(chǎn)生后剧包,讓線程阻塞恐锦,另一個線程產(chǎn)生了結(jié)果后,調(diào)用 resume() 使其恢復(fù)疆液。
yield() 方法:yield() 使得線程放棄當(dāng)前分得的 CPU 時間,但是不使線程阻塞陕贮,即線程仍處于可執(zhí)行狀態(tài)堕油,隨時可能再次分得 CPU 時間。調(diào)用 yield() 的效果等價于調(diào)度程序認為該線程已執(zhí)行了足夠的時間從而轉(zhuǎn)到另一個線程.
wait() 和 notify() 方法:兩個方法配套使用肮之,wait() 使得線程進入阻塞狀態(tài)掉缺,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數(shù)戈擒,另一種沒有參數(shù)眶明,前者當(dāng)對應(yīng)的 notify() 被調(diào)用或者超出指定時間時線程重新進入可執(zhí)行狀態(tài),后者則必須對應(yīng)的 notify() 被調(diào)用.
初看起來它們與 suspend() 和 resume() 方法對沒有什么分別筐高,但是事實上它們是截然不同的搜囱。區(qū)別的核心在于丑瞧,前面敘述的所有方法,阻塞時都不會釋放占用的鎖(如果占用了的話)蜀肘,而這一對方法則相反绊汹。
首先,前面敘述的所有方法都隸屬于 Thread 類扮宠,但是這一對卻直接隸屬于 Object 類西乖,也就是說,所有對象都擁有這一對方法坛增。初看起來這十分不可思議获雕,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放占用的鎖收捣,而鎖是任何對象都具有的届案,調(diào)用任意對象的 wait() 方法導(dǎo)致線程阻塞,并且該對象上的鎖被釋放坏晦。而調(diào)用 任意對象的notify()方法則導(dǎo)致因調(diào)用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)萝玷。
其次,前面敘述的所有方法都可在任何位置調(diào)用昆婿,但是這一對方法卻必須在 synchronized 方法或塊中調(diào)用球碉,理由也很簡單,只有在synchronized 方法或塊中當(dāng)前線程才占有鎖仓蛆,才有鎖可以釋放睁冬。同樣的道理,調(diào)用這一對方法的對象上的鎖必須為當(dāng)前線程所擁有看疙,這樣才有鎖可以釋放豆拨。因此,這一對方法調(diào)用必須放置在這樣的 synchronized 方法或塊中能庆,該方法或塊的上鎖對象就是調(diào)用這一對方法的對象施禾。若不滿足這一條件,則程序雖然仍能編譯搁胆,但在運行時會出現(xiàn)IllegalMonitorStateException 異常弥搞。
wait() 和 notify() 方法的上述特性決定了它們經(jīng)常和synchronized方法或塊一起使用,將它們和操作系統(tǒng)的進程間通信機制作一個比較就會發(fā)現(xiàn)它們的相似性:synchronized方法或塊提供了類似于操作系統(tǒng)原語的功能渠旁,它們的執(zhí)行不會受到多線程機制的干擾攀例,而這一對方法則相當(dāng)于 block 和wakeup 原語(這一對方法均聲明為 synchronized)。它們的結(jié)合使得我們可以實現(xiàn)操作系統(tǒng)上一系列精妙的進程間通信的算法(如信號量算法)顾腊,并用于解決各種復(fù)雜的線程間通信問題粤铭。
關(guān)于 wait() 和 notify() 方法最后再說明兩點:
a、調(diào)用 notify() 方法導(dǎo)致解除阻塞的線程是從因調(diào)用該對象的 wait() 方法而阻塞的線程中隨機選取的杂靶,我們無法預(yù)料哪一個線程將會被選擇梆惯,所以編程時要特別小心酱鸭,避免因這種不確定性而產(chǎn)生問題。
b加袋、除了 notify()凛辣,還有一個方法 notifyAll() 也可起到類似作用,唯一的區(qū)別在于职烧,調(diào)用 notifyAll() 方法將把因調(diào)用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞扁誓。當(dāng)然,只有獲得鎖的那一個線程才能進入可執(zhí)行狀態(tài)蚀之。
Android基礎(chǔ)
1蝗敢、是否使用過IntentService,作用是什么足删,AIDL解決了什么問題寿谴?
生成一個默認的且與主線程互相獨立的工作者線程來執(zhí)行所有傳送至onStartCommand() 方法的Intetnt。
生成一個工作隊列來傳送Intent對象給你的onHandleIntent()方法失受,同一時刻只傳送一個Intent對象讶泰,這樣一來,你就不必擔(dān)心多線程的問題拂到。在所有的請求(Intent)都被執(zhí)行完以后會自動停止服務(wù)痪署,所以,你不需要自己去調(diào)用stopSelf()方法來停止兄旬。
該服務(wù)提供了一個onBind()方法的默認實現(xiàn)狼犯,它返回null
提供了一個onStartCommand()方法的默認實現(xiàn),它將Intent先傳送至工作隊列领铐,然后從工作隊列中每次取出一個傳送至onHandleIntent()方法悯森,在該方法中對Intent對相應(yīng)的處理。
AIDL (Android Interface Definition Language) 是一種IDL 語言绪撵,用于生成可以在Android設(shè)備上兩個進程之間進行進程間通信(interprocess communication, IPC)的代碼瓢姻。如果在一個進程中(例如Activity)要調(diào)用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數(shù)音诈。 AIDL IPC機制是面向接口的汹来,像COM或Corba一樣,但是更加輕量級改艇。它是使用代理類在客戶端和實現(xiàn)端傳遞數(shù)據(jù)。
2坟岔、Activity谒兄、Window、View三者的差別社付?
Activity像一個工匠(控制單元)承疲,Window像窗戶(承載模型)邻耕,View像窗花(顯示視圖) LayoutInflater像剪刀,Xml配置像窗花圖紙燕鸽。
在Activity中調(diào)用attach兄世,創(chuàng)建了一個Window
創(chuàng)建的window是其子類PhoneWindow,在attach中創(chuàng)建PhoneWindow
在Activity中調(diào)用setContentView(R.layout.xxx)
其中實際上是調(diào)用的getWindow().setContentView()
調(diào)用PhoneWindow中的setContentView方法
創(chuàng)建ParentView:作為ViewGroup的子類啊研,實際是創(chuàng)建的DecorView(作為FramLayout的子類)
將指定的R.layout.xxx進行填充通過布局填充器進行填充【其中的parent指的就是DecorView】
調(diào)用到ViewGroup
調(diào)用ViewGroup的removeAllView()御滩,先將所有的view移除掉
添加新的view:addView()
3、Fragment 特點
Fragment可以作為Activity界面的一部分組成出現(xiàn)党远;
可以在一個Activity中同時出現(xiàn)多個Fragment削解,并且一個Fragment也可以在多個Activity中使用;
在Activity運行過程中沟娱,可以添加氛驮、移除或者替換Fragment;
Fragment可以響應(yīng)自己的輸入事件济似,并且有自己的生命周期矫废,它們的生命周期會受宿主Activity的生命周期影響。
4砰蠢、Handler蓖扑、Thread和HandlerThread的差別?
http://blog.csdn.net/guolin_blog/article/details/9991569
http://droidyue.com/blog/2015/11/08/make-use-of-handlerthread/
從Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出娩脾,Android的Thread沒有對Java的Thread做任何封裝赵誓,但是Android提供了一個繼承自Thread的類HandlerThread(android.os.HandlerThread -> java.lang.Thread),這個類對Java的Thread做了很多便利Android系統(tǒng)的封裝柿赊。
android.os.Handler可以通過Looper對象實例化俩功,并運行于另外的線程中,Android提供了讓Handler運行于其它線程的線程實現(xiàn)碰声,也就是HandlerThread诡蜓。HandlerThread對象start后可以獲得其Looper對象,并且使用這個Looper對象實例Handler胰挑。
5蔓罚、Launch mode應(yīng)用場景
Standard,創(chuàng)建一個新的Activity瞻颂。
SingleTop豺谈,棧頂不是該類型的Activity,創(chuàng)建一個新的Activity贡这。否則茬末,onNewIntent。
SingleTask,回退棧中沒有該類型的Activity丽惭,創(chuàng)建Activity击奶,否則,onNewIntent+ClearTop责掏。
注意:
設(shè)置了"singleTask"啟動模式的Activity柜砾,它在啟動的時候,會先在系統(tǒng)中查找屬性值affinity等于它的屬性值taskAffinity的Task存在换衬; 如果存在這樣的Task痰驱,它就會在這個Task中啟動,否則就會在新的任務(wù)棧中啟動冗疮。因此萄唇, 如果我們想要設(shè)置了"singleTask"啟動模式的Activity在新的任務(wù)中啟動,就要為它設(shè)置一個獨立的taskAffinity屬性值术幔。
如果設(shè)置了"singleTask"啟動模式的Activity不是在新的任務(wù)中啟動時另萤,它會在已有的任務(wù)中查看是否已經(jīng)存在相應(yīng)的Activity實例, 如果存在诅挑,就會把位于這個Activity實例上面的Activity全部結(jié)束掉四敞,即最終這個Activity 實例會位于任務(wù)的Stack頂端中。
在一個任務(wù)棧中只有一個”singleTask”啟動模式的Activity存在拔妥。他的上面可以有其他的Activity忿危。這點與singleInstance是有區(qū)別的。
singleInstance没龙,回退棧中铺厨,只有這一個Activity,沒有其他Activity硬纤。
SingleTop適合接收通知啟動的內(nèi)容顯示頁面解滓。
例如,某個新聞客戶端的新聞內(nèi)容頁面筝家,如果收到10個新聞推送洼裤,每次都打開一個新聞內(nèi)容頁面是很煩人的。
singleTask適合作為程序入口點溪王。
例如瀏覽器的主界面腮鞍。不管從多少個應(yīng)用啟動瀏覽器,只會啟動主界面一次莹菱,其余情況都會走onNewIntent移国,并且會清空主界面上面的其他頁面。
singleInstance應(yīng)用場景:
鬧鈴的響鈴界面道伟。 你以前設(shè)置了一個鬧鈴:上午6點桥狡。在上午5點58分,你啟動了鬧鈴設(shè)置界面,并按 Home 鍵回桌面裹芝;在上午5點59分時,你在微信和朋友聊天娜汁;在6點時嫂易,鬧鈴響了,并且彈出了一個對話框形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 加載模式打開的)掐禁,你按返回鍵怜械,回到的是微信的聊天界面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素傅事, 因此退出之后這個 Task 的椔圃剩空了。如果是以 SingleTask 打開 AlarmAlertActivity蹭越,那么當(dāng)鬧鈴響了的時候障本,按返回鍵應(yīng)該進入鬧鈴設(shè)置界面。
6响鹃、Android事件分發(fā)機制
http://www.reibang.com/p/38015afcdb58
7驾霜、view繪制流程
http://www.reibang.com/p/bb7977990baa
8、post和postDelay
9买置、線程同步
http://www.juwends.com/tech/android/android-inter-thread-comm.html
10粪糙、單例模式
public class Singleton{
private volatile static Singleton mSingleton;
private Singleton(){
}
public static Singleton getInstance(){
if(mSingleton == null){
synchronized(Singleton.class){
if(mSingleton == null)
mSingleton = new Singleton();
}
}
return mSingleton;
}
}
11、什么情況導(dǎo)致內(nèi)存泄漏
a忿项、資源對象沒關(guān)閉造成的內(nèi)存泄漏
描述: 資源性對象比如(Cursor蓉冈,F(xiàn)ile文件等)往往都用了一些緩沖,我們在不使用的時候轩触,應(yīng)該及時關(guān)閉它們寞酿,以便它們的緩沖及時回收內(nèi)存。它們的緩沖不僅存在于 java虛擬機內(nèi)怕膛,還存在于java虛擬機外熟嫩。如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會造成內(nèi)存泄漏褐捻。因為有些資源性對象掸茅,比如 SQLiteCursor(在析構(gòu)函數(shù)finalize(),如果我們沒有關(guān)閉它,它自己會調(diào)close()關(guān)閉)柠逞,如果我們沒有關(guān)閉它昧狮,系統(tǒng)在回收它時也會關(guān)閉它,但是這樣的效率太低了板壮。因此對于資源性對象在不使用的時候逗鸣,應(yīng)該調(diào)用它的close()函數(shù),將其關(guān)閉掉,然后才置為null.在我們的程序退出時一定要確保我們的資源性對象已經(jīng)關(guān)閉撒璧。 程序中經(jīng)常會進行查詢數(shù)據(jù)庫的操作透葛,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小卿樱,對內(nèi)存的消耗不容易被發(fā)現(xiàn)僚害,只有在常時間大量操作的情況下才會復(fù)現(xiàn)內(nèi)存問題,這樣就會給以后的測試和問題排查帶來困難和風(fēng)險繁调。
b萨蚕、構(gòu)造Adapter時,沒有使用緩存的convertView
以構(gòu)造ListView的BaseAdapter為例蹄胰,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 來向ListView提供每一個item所需要的view對象岳遥。初始時ListView會從BaseAdapter中根據(jù)當(dāng)前的屏幕布局實例化一定數(shù)量的 view對象,同時ListView會將這些view對象緩存起來裕寨。當(dāng)向上滾動ListView時浩蓉,原先位于最上面的list item的view對象會被回收,然后被用來構(gòu)造新出現(xiàn)的最下面的list item帮坚。這個構(gòu)造過程就是由getView()方法完成的妻往,getView()的第二個形參View convertView就是被緩存起來的list item的view對象(初始化時緩存中沒有view對象則convertView是null)。由此可以看出试和,如果我們不去使用 convertView讯泣,而是每次都在getView()中重新實例化一個View對象的話,即浪費資源也浪費時間阅悍,也會使得內(nèi)存占用越來越大好渠。 ListView回收list item的view對象的過程可以查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代碼:
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
修正示例代碼:
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}
c节视、Bitmap對象不在使用時調(diào)用recycle()釋放內(nèi)存
有時我們會手工的操作Bitmap對象拳锚,如果一個Bitmap對象比較占內(nèi)存,當(dāng)它不在被使用的時候寻行,可以調(diào)用Bitmap.recycle()方法回收此對象的像素所占用的內(nèi)存霍掺,但這不是必須的,視情況而定拌蜘。
d膝藕、試著使用關(guān)于application的context來替代和activity相關(guān)的context
這是一個很隱晦的內(nèi)存泄漏的情況荠商。有一種簡單的方法來避免context相關(guān)的內(nèi)存泄漏膳算。最顯著地一個是避免context逃出他自己的范圍之外族跛。使用Application context。這個context的生存周期和你的應(yīng)用的生存周期一樣長举娩,而不是取決于activity的生存周期析校。如果你想保持一個長期生存的對象构罗,并且這個對象需要一個context,記得使用application對象。你可以通過調(diào)用 Context.getApplicationContext() or Activity.getApplication()來獲得智玻。更多的請看這篇文章如何避免 Android內(nèi)存泄漏遂唧。
e、注冊沒反注冊造成的內(nèi)存泄漏
一些Android程序可能引用我們的Anroid程序的對象(比如注冊機制)尚困。即使我們的Android程序已經(jīng)結(jié)束了蠢箩,但是別的引用程序仍然還有對我們的Android程序的某個對象的引用,泄漏的內(nèi)存依然不能被垃圾回收事甜。調(diào)用registerReceiver后未調(diào)用unregisterReceiver。 比如:假設(shè)我們希望在鎖屏界面(LockScreen)中滔韵,監(jiān)聽系統(tǒng)中的電話服務(wù)以獲取一些信息(如信號強度等)逻谦,則可以在LockScreen中定義一個 PhoneStateListener的對象,同時將它注冊到TelephonyManager服務(wù)中陪蜻。對于LockScreen對象邦马,當(dāng)需要顯示鎖屏界面的時候就會創(chuàng)建一個LockScreen對象,而當(dāng)鎖屏界面消失的時候LockScreen對象就會被釋放掉宴卖。 但是如果在釋放 LockScreen對象的時候忘記取消我們之前注冊的PhoneStateListener對象滋将,則會導(dǎo)致LockScreen無法被垃圾回收。如果不斷的使鎖屏界面顯示和消失症昏,則最終會由于大量的LockScreen對象沒有辦法被回收而引起OutOfMemory,使得system_process 進程掛掉随闽。 雖然有些系統(tǒng)程序,它本身好像是可以自動取消注冊的(當(dāng)然不及時)肝谭,但是我們還是應(yīng)該在我們的程序中明確的取消注冊掘宪,程序結(jié)束時應(yīng)該把所有的注冊都取消掉。
f攘烛、集合中對象沒清理造成的內(nèi)存泄漏
我們通常把一些對象的引用加入到了集合中魏滚,當(dāng)我們不需要該對象時,并沒有把它的引用從集合中清理掉坟漱,這樣這個集合就會越來越大鼠次。如果這個集合是static的話,那情況就更嚴重了芋齿。
12腥寇、ANR定位和如何避免?
如果開發(fā)機器上出現(xiàn)問題沟突,我們可以通過查看/data/anr/traces.txt即可花颗,最新的ANR信息在最開始部分。
主線程被IO操作(從4.0之后網(wǎng)絡(luò)IO不允許在主線程中)阻塞惠拭。
主線程中存在耗時的計算
主線程中錯誤的操作扩劝,比如Thread.wait或者Thread.sleep等 Android系統(tǒng)會監(jiān)控程序的響應(yīng)狀況庸论,一旦出現(xiàn)下面兩種情況,則彈出ANR對話框
應(yīng)用在5秒內(nèi)未響應(yīng)用戶的輸入事件(如按鍵或者觸摸)
BroadcastReceiver未在10秒內(nèi)完成相關(guān)的處理
Service在特定的時間內(nèi)無法處理完成 20秒
避免
使用AsyncTask處理耗時IO操作棒呛。
使用Thread或者HandlerThread時聂示,調(diào)用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設(shè)置優(yōu)先級,否則仍然會降低程序響應(yīng)簇秒,因為默認Thread的優(yōu)先級和主線程相同鱼喉。
使用Handler處理工作線程結(jié)果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程趋观。
Activity的onCreate和onResume回調(diào)中盡量避免耗時的代碼
BroadcastReceiver中onReceive代碼也要盡量減少耗時扛禽,建議使用IntentService處理。
13皱坛、什么情況導(dǎo)致OOM以及如何避免?
http://blog.csdn.net/yangxuehui1990/article/details/44994763
http://blog.csdn.net/ljx19900116/article/details/50037627
14编曼、Android Service與Activity之間通信的幾種方式?
通過Binder對象
通過Broadcast(廣播)的形式
15剩辟、如何保證service在后臺盡量不被kill
onStartCommand方法掐场,返回START_STICKY
START_STICKY 在運行onStartCommand后service進程被kill后,那將保留在開始狀態(tài)贩猎,但是不保留那些傳入的intent熊户。不久后service就會再次嘗試重新創(chuàng)建,因為保留在開始狀態(tài)吭服,在創(chuàng)建 service后將保證調(diào)用onstartCommand嚷堡。如果沒有傳遞任何開始命令給service,那將獲取到null的intent噪馏。
START_NOT_STICKY 在運行onStartCommand后service進程被kill后麦到,并且沒有新的intent傳遞給它。Service將移出開始狀態(tài)欠肾,并且直到新的明顯的方法(startService)調(diào)用才重新創(chuàng)建瓶颠。因為如果沒有傳遞任何未決定的intent那么service是不會啟動,也就是期間onstartCommand不會接收到任何null的intent刺桃。
START_REDELIVER_INTENT 在運行onStartCommand后service進程被kill后粹淋,系統(tǒng)將會再次啟動service,并傳入最后一個intent給onstartCommand瑟慈。直到調(diào)用stopSelf(int)才停止傳遞intent桃移。如果在被kill后還有未處理好的intent,那被kill后服務(wù)還是會自動啟動葛碧。因此onstartCommand不會接收到任何null的intent借杰。
提升service優(yōu)先級
在AndroidManifest.xml文件中對于intent-filter可以通過android:priority="1000"這個屬性設(shè)置最高優(yōu)先級,1000是最高值进泼,如果數(shù)字越小則優(yōu)先級越低蔗衡,同時適用于廣播纤虽。
提升service進程優(yōu)先級
Android中的進程是托管的,當(dāng)系統(tǒng)進程空間緊張的時候绞惦,會依照優(yōu)先級自動進行進程的回收逼纸。Android將進程分為6個等級,它們按優(yōu)先級順序由高到低依次是:
前臺進程( FOREGROUND_APP)
可視進程(VISIBLE_APP )
次要服務(wù)進程(SECONDARY_SERVER )
后臺進程 (HIDDEN_APP)
內(nèi)容供應(yīng)節(jié)點(CONTENT_PROVIDER)
空進程(EMPTY_APP)
當(dāng)service運行在低內(nèi)存的環(huán)境時,將會kill掉一些存在的進程济蝉。因此進程的優(yōu)先級將會很重要杰刽,可以使用startForeground 將service放到前臺狀態(tài)。這樣在低內(nèi)存時被kill的幾率會低一些王滤。
onDestroy方法里重啟service
service+broadcast方式贺嫂,就是當(dāng)service走ondestory的時候,發(fā)送一個自定義的廣播雁乡,當(dāng)收到廣播的時候涝婉,重新啟動service;
Application加上Persistent屬性
監(jiān)聽系統(tǒng)廣播判斷Service狀態(tài)
16蔗怠、RequestLayout,onLayout吩跋,onDraw寞射,DrawChild區(qū)別與聯(lián)系
requestLayout()方法 :會導(dǎo)致調(diào)用measure()過程 和 layout()過程 。說明:只是對View樹重新布局layout過程包括measure()和layout()過程锌钮,不會調(diào)用draw()過程桥温,但不會重新繪制 任何視圖包括該調(diào)用者本身。
onLayout()方法(如果該View是ViewGroup對象梁丘,需要實現(xiàn)該方法侵浸,對每個子視圖進行布局)
調(diào)用onDraw()方法繪制視圖本身(每個View都需要重載該方法,ViewGroup不需要實現(xiàn)該方法)
drawChild()去重新回調(diào)每個子視圖的draw()方法
17氛谜、invalidate()和postInvalidate() 的區(qū)別及使用
http://blog.csdn.net/mars2639/article/details/6650876
18掏觉、LinearLayout對比RelativeLayout
RelativeLayout會讓子View調(diào)用2次onMeasure,LinearLayout 在有weight時值漫,也會調(diào)用子View2次onMeasure
RelativeLayout的子View如果高度和RelativeLayout不同澳腹,則會引發(fā)效率問題,當(dāng)子View很復(fù)雜時杨何,這個問題會更加嚴重酱塔。如果可以,盡量使用padding代替margin危虱。
在不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是RelativeLayout羊娃。
19、優(yōu)化自定義view
為了加速你的view埃跷,對于頻繁調(diào)用的方法蕊玷,需要盡量減少不必要的代碼邮利。先從onDraw開始,需要特別注意不應(yīng)該在這里做內(nèi)存分配的事情集畅,因為它會導(dǎo)致GC近弟,從而導(dǎo)致卡頓。在初始化或者動畫間隙期間做分配內(nèi)存的動作挺智。不要在動畫正在執(zhí)行的時候做內(nèi)存分配的事情祷愉。
你還需要盡可能的減少onDraw被調(diào)用的次數(shù),大多數(shù)時候?qū)е耾nDraw都是因為調(diào)用了invalidate().因此請盡量減少調(diào)用invaildate()的次數(shù)赦颇。如果可能的話二鳄,盡量調(diào)用含有4個參數(shù)的invalidate()方法而不是沒有參數(shù)的invalidate()。沒有參數(shù)的invalidate會強制重繪整個view媒怯。
另外一個非常耗時的操作是請求layout订讼。任何時候執(zhí)行requestLayout(),會使得Android UI系統(tǒng)去遍歷整個View的層級來計算出每一個view的大小扇苞。如果找到有沖突的值欺殿,它會需要重新計算好幾次。另外需要盡量保持View的層級是扁平化的鳖敷,這樣對提高效率很有幫助脖苏。
如果你有一個復(fù)雜的UI,你應(yīng)該考慮寫一個自定義的ViewGroup來執(zhí)行他的layout操作定踱。與內(nèi)置的view不同棍潘,自定義的view可以使得程序僅僅測量這一部分,這避免了遍歷整個view的層級結(jié)構(gòu)來計算大小崖媚。這個PieChart 例子展示了如何繼承ViewGroup作為自定義view的一部分亦歉。PieChart 有子views,但是它從來不測量它們畅哑。而是根據(jù)他自身的layout法則肴楷,直接設(shè)置它們的大小。
20敢课、ContentProvider
http://www.reibang.com/p/ea8bc4aaf057
21阶祭、Android 設(shè)計模式
http://blog.csdn.net/bboyfeiyu/article/details/44563871
22、MVC直秆、MVP濒募、MVM區(qū)別?
https://www.cnblogs.com/guwei4037/p/5591183.html
小編給大家準(zhǔn)備安卓高級開發(fā)資料
QQ群號:4112676