2019年了蒐集了很多面試題,希望能對大家有所幫助
1.View的繪製流程;自定義View如何考慮機型適配;自定義View的事件分發機制;View和ViewGroup分別有哪些事件分發相關的回撥方法;自定義View如何提供獲取View屬性的介面。
View的繪製流程:
流程一:mesarue()過程;
流程二:layout佈局過程;
流程三:draw()繪圖過程。
詳情:http://blog.csdn.net/qinjuning/article/details/7110211/
自定義View如何考慮機型適配:
這篇博文解決了Android適配的絕大多數問題:
http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023
自定義View的事件分發機制:
對於 dispatchTouchEvent,onTouchEvent,return true是終結事件傳遞。return false 是回溯到父View的onTouchEvent方法。
ViewGroup 想把自己分發給自己的onTouchEvent,需要攔截器onInterceptTouchEvent方法return true 把事件攔截下來。
ViewGroup 的攔截器onInterceptTouchEvent 預設是不攔截的,所以return super.onInterceptTouchEvent()=return false;
View 沒有攔截器,為了讓View可以把事件分發給自己的onTouchEvent,View的dispatchTouchEvent預設實現(super)就是把事件分發給自己的onTouchEvent。
對於ACTION_MOVE、ACTION_UP總結:ACTION_DOWN事件在哪個控制元件消費了(return true), 那麼ACTION_MOVE和ACTION_UP就會從上往下(通過dispatchTouchEvent)做事件分發往下傳,就只會傳到這個控制元件,不會繼續往下傳,如果ACTION_DOWN事件是在dispatchTouchEvent消費,那麼事件到此為止停止傳遞,如果ACTION_DOWN事件是在onTouchEvent消費的,那麼會把ACTION_MOVE或ACTION_UP事件傳給該控制元件的onTouchEvent處理並結束傳遞。
詳情:http://www.jianshu.com/p/e99b5e8bd67b
以及下面這個的第五部分:
http://imtianx.cn/2016/12/17/Android%20View%20%E7%9A%84%E4%BA%8B%E4%BB%B6%E4%BD%93%E7%B3%BB/
View和ViewGroup分別有哪些事件分發相關的回撥方法:
View中跟事件分發機制有關的就是兩個方法:dispatchTouchEvent和onTouchEvent。整個View的事件轉發流程是:
View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent
在dispatchTouchEvent中會進行OnTouchListener的判斷,如果OnTouchListener不為null且返回true,則表示事件被消費,onTouchEvent不會被執行;否則執行onTouchEvent。
對於ViewGroup中的分發事件:
如果ViewGroup找到了能夠處理該事件的View,則直接交給子View處理,自己的onTouchEvent不會被觸發;
可以通過複寫onInterceptTouchEvent(ev)方法,攔截子View的事件(即return true),把事件交給自己處理,則會執行自己對應的onTouchEvent方法
子View可以通過呼叫getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup對其MOVE或者UP事件進行攔截;
詳情:http://blog.csdn.net/lmj623565791/article/details/38960443
http://blog.csdn.net/lmj623565791/article/details/39102591
自定義View如何提供獲取View屬性的介面:
關於View所要具備的一般功能,View類中都有了基本的實現,比如確定位置,它有layout方法,當然,這個只適用於ViewGroup,實現自己的ViewGroup時,才需要修改該方法。確定大小,它有onMeasure方法,如果你不滿意預設的確認大小的方法,也可以自己定義。改變預設的繪製,就覆寫onDraw方法。
詳情:http://www.jianshu.com/p/d507e3514b65
2.Art和Dalvik對比;虛擬機器原理,如何自己設計一個虛擬機器(記憶體管理,類載入,雙親委派);JVM記憶體模型及類載入機制;記憶體物件的迴圈引用及避免
Art和Dalvik對比:
Dalvik是Google公司自己設計用於Android平臺的虛擬機器。
ART即Android Runtime
Dalvik和ART的幾點區別:
dalvik是執行的時候編譯+執行,安裝比較快,開啟應用比較慢,應用佔用空間小
ART是安裝的時候就編譯好了,執行的時候直接就可以執行的,安裝慢,開啟應用快,佔用空間大
用個比喻來說就是,騎自行車
dalvik 是已經摺疊起來的自行車,每次騎都要先組裝自行車才能騎
ART 是已經組裝好的自行車,每次騎直接上車就能走人
詳情:http://www.jb51.net/article/88708.htm
虛擬機器原理,如何自己設計一個虛擬機器(記憶體管理,類載入,雙親委派):
在載入階段,java虛擬機器需要完成以下3件事:
a.通過一個類的全限定名來獲取定義此類的二進位制位元組流。
b.將定義類的二進位制位元組流所代表的靜態儲存結構轉換為方法區的執行時資料結構。
c.在java堆中生成一個代表該類的java.lang.Class物件,作為方法區資料的訪問入口。
類載入:
從類被載入到虛擬機器記憶體中開始,到解除安裝出記憶體為止,類的生命週期包括載入(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和解除安裝(Unloading)7個階段
雙親委派:
系統提供的類載入器主要有下面3個:
.啟動類載入器(Bootstarp ClassLoader)
.擴充套件類載入器(Extension ClassLoader)
.應用程式類載入器(Application ClassLoader)
注意:上述三個JDK提供的類載入器雖然是父子類載入器關係,但是沒有使用繼承,而是使用了組合關係。
詳情:http://blog.csdn.net/ochangwen/article/details/51473120
http://blog.csdn.net/ochangwen/article/details/51472311
JVM記憶體模型及類載入機制:
JVM要想執行class檔案,首先會將檔案載入虛擬機器的方法區內,根據類檔案的格式相應的存放資料。在需要產生物件時,從方法區中獲取對應的類資訊,在堆中建立物件。
詳情:http://blog.csdn.net/dragon_cat_han/article/details/52150955
記憶體物件的迴圈引用及避免:
如果有兩個或者以上的物件,它們彼此引用,就會造成迴圈引用。
避免:引用計數GC處理,引用遍歷GC處理。
詳情:http://www.wtoutiao.com/p/11elsk6.html
3.記憶體回收機制與GC演算法(各種演算法的優缺點以及應用場景);GC原理時機以及GC物件;記憶體洩露場景及解決方法;OOM的避免及解決方法
記憶體回收機制與GC演算法(各種演算法的優缺點以及應用場景):
GC是通過物件是否存活來決定是否進行回收,最常用的判定演算法是引用計數演算法以及Java中使用的判定演算法為根搜尋演算法(GC Roots Tracing)
常用的垃圾收集演算法
a、標記——清除演算法(Mark——Sweep)
首先標記出所有需要回收的物件,在標記完成後統一回收掉所有被標記的物件。
缺點:效率問題,標記和清除過程的效率不高;
b、複製演算法(Copying)
為了解決標記清除演算法的效率問題,複製演算法將可用的記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活的物件複製到另一塊上,然後再把已使用過的記憶體空間一次清理掉。
優點:實現簡單,執行高效
缺點:對記憶體空間的利用不高,可用記憶體變成一半,這代價過高
c、標記——整理演算法(Mark——Compact)
與標記清除演算法的標記階段相同,但標記後會將所有存活的物件向一端移動,然後直接清理掉端邊界以外的記憶體。這種演算法一般用於老年代的記憶體回收上,因為老年代中物件的存活時間都比較長,可能存在100%存活的極端情況,因此不能選擇Copying演算法來進行回收。
d、分代收集演算法(Generational Collection)
這種演算法只是根據物件的存活週期的不同將記憶體劃分為幾塊,一般都劃分為新生代和老年代,這樣可以根據各個年代的特點採用最適當的收集演算法。新生代中,每次垃圾收集時都發現有大批物件死去,只有少量存活,因此選取複製演算法,只需要付出少量存活物件的複製成本就可以完成收集;老年代中因為物件存活率高,沒有額外的空間對它進行分配擔保,就必須使用“標記——清除”或是“標記——整理”演算法來進行回收。在之前的三種演算法中已經有所描述。
詳情:http://www.open-open.com/lib/view/open1380593930103.html
GC原理時機以及GC物件:
JVM 分別對新生代和舊生代採用不同的垃圾回收機制
Java中那些不可達的物件就會變成垃圾。那麼什麼叫做不可達?其實就是沒有辦法再引用到該物件了。主要有以下情況使物件變為垃圾:
1.對非執行緒的物件來說,所有的活動執行緒都不能訪問該物件,那麼該物件就會變為垃圾。
2.對執行緒物件來說,滿足上面的條件,且執行緒未啟動或者已停止。
GC將負責回收所有“不可達”物件的記憶體空間。
詳情:https://segmentfault.com/a/1190000002579346
記憶體洩露場景及解決方法:
因為靜態變數造成的記憶體洩漏;
Handler 的錯誤使用;
非靜態內部類的靜態例項的錯誤使用;
不正確使用執行緒,造成記憶體洩漏;
資源沒有及時關閉;
詳情例子解決方案參見:http://blog.csdn.net/adrian24/article/details/53248255
或者http://www.jianshu.com/p/51072faadf51
OOM的避免及解決方法:
高效載入大圖片:
在展示高解析度圖片的時候,最好先將圖片進行壓縮。壓縮後的圖片大小應該和用來展示它的控制元件大小相近,在一個很小的ImageView上顯示一張超大的圖片不會帶來任何視覺上的好處,但卻會佔用我們相當多寶貴的記憶體,而且在效能上還可能會帶來負面影響。下面我們就來看一看,如何對一張大圖片進行適當的壓縮,讓它能夠以最佳大小顯示的同時,還能防止OOM的出現。
使用圖片快取技術:
記憶體快取技術對那些大量佔用應用程式寶貴記憶體的圖片提供了快速訪問的方法。其中最核心的類是LruCache (此類在android-support-v4的包中提供) 。這個類非常適合用來快取圖片,它的主要演算法原理是把最近使用的物件用強引用儲存在 LinkedHashMap 中,並且把最近最少使用的物件在快取值達到預設定值之前從記憶體中移除。
詳情:http://blog.csdn.net/guolin_blog/article/details/9316683
4.四大元件及生命週期;ContentProvider的許可權管理(讀寫分離,許可權控制-精確到表級,URL控制);Activity的四種啟動模式對比;Activity狀態儲存於恢復
都是一些基礎知識,詳情歸類下:
Activity:詳細知識:http://blog.csdn.net/amazing7/article/details/51244219
Service:詳細知識:http://blog.csdn.net/amazing7/article/details/51305911
ContentProvider:詳細知識:http://blog.csdn.net/amazing7/article/details/51324022
BroadcastReceiver:詳細知識:http://blog.csdn.net/amazing7/article/details/51352139
ContentProvider的許可權管理:http://blog.csdn.net/robertcpp/article/details/51337891
Activity的四種啟動模式對比:http://blog.csdn.net/knlnzhao/article/details/8005277
Activity狀態儲存於恢復:http://blog.csdn.net/js331455217/article/details/40930157
5.Fragment生命週期;Fragment狀態儲存
生命週期及相關:http://blog.csdn.net/amazing7/article/details/51282082
狀態儲存:http://www.jianshu.com/p/75dc2f51cd63
6.startActivityForResult是哪個類的方法,在什麼情況下使用,如果在Adapter中使用應該如何解耦
startActivityForResult是Activity類裡的方法,在原Activity裡通過Intent跳轉到其他類再跳回到原Activity裡時候,回傳資料所用
詳情:http://blog.csdn.net/sunchaoenter/article/details/6612039
在Adapter以及其他非Activity類使用的時候,可以將由原Activity類傳入的Context強轉為Activity類,再在原Activity裡重寫onActivityResult方法接受到返回值。
7.AsyncTask原理及不足;IntentService原理
AsyncTask是一個輕量級的非同步類,繼承時候有三個泛型引數:
1. Params,在執行AsyncTask時需要傳入的引數,可用於在後臺任務中使用;
2. Progress,後臺任務執行時,如果需要在介面上顯示當前的進度,則使用這裡指定的泛型作為進度單位;
3. Result,當任務執行完畢後,如果需要對結果進行返回,則使用這裡指定的泛型作為返回值型別。
需要重寫四個方法(至少是2個,2和4):
1. onPreExecute(),這個方法會在後臺任務開始執行之間呼叫,用於進行一些介面上的初始化操作,比如顯示一個進度條對話方塊等。
2. doInBackground(Params...),這個方法中的所有程式碼都會在子執行緒中執行,我們應該在這裡去處理所有的耗時任務。任務一旦完成就可以通過return語句來將任務的執行結果進行返回,如果AsyncTask的第三個泛型引數指定的是Void,就可以不返回任務執行結果。注意,在這個方法中是不可以進行UI操作的,如果需要更新UI元素,比如說反饋當前任務的執行進度,可以呼叫publishProgress(Progress...)方法來完成。
3. onProgressUpdate(Progress...),當在後臺任務中呼叫了publishProgress(Progress...)方法後,這個方法就很快會被呼叫,方法中攜帶的引數就是在後臺任務中傳遞過來的。在這個方法中可以對UI進行操作,利用引數中的數值就可以對介面元素進行相應的更新。
4. onPostExecute(Result),當後臺任務執行完畢並通過return語句進行返回時,這個方法就很快會被呼叫。返回的資料會作為引數傳遞到此方法中,可以利用返回的資料來進行一些UI操作,比如說提醒任務執行的結果,以及關閉掉進度條對話方塊等。
AnsycTask執行任務時,內部會建立一個程式作用域的執行緒池來管理要執行的任務,也就就是說當你呼叫了AsyncTask.execute()後,AsyncTask會把任務交給執行緒池,由執行緒池來管理建立Thread和執行Therad,本質上是對Thread+Handler的良好封裝,減少了開發者處理問題的複雜度,提高了開發效率。
AsyncTask缺陷:
最大的缺點:在使用多個非同步操作和並需要進行Ui變更時,就變得複雜起來。
其他的參考下面的文章。
詳情:http://blog.csdn.net/liuhe688/article/details/6532519
http://blog.csdn.net/boyupeng/article/details/49001215
IntentService原理
IntentService是繼承於Service並處理非同步請求的一個類,在IntentService內有一個工作執行緒來處理耗時操作,啟動IntentService的方式和啟動傳統Service一樣,同時,當任務執行完後,IntentService會自動停止,而不需要我們去手動控制。
詳情:http://blog.csdn.net/qq_18402085/article/details/50753005
http://blog.csdn.net/ryantang03/article/details/8146154/
8.AstncTask+HttpClient與AsyncHttpClient有什麼區別
AsyncHttpClient來自android-async-http庫是在Apache的HttpClient庫的基礎上開發構建而成的,這裡的非同步,是指它所有的網路請求都是在app的UI執行緒之外的獨立工作執行緒中執行。而開發者通過利用Android的訊息處理機制,把我們所需要編寫的回撥函式放在這個回撥函式的建立執行緒中執行(一般就是UI執行緒),所以使用起來非常方便除了能應用在開發普通App上,還可以用來開發Service或後臺執行緒,async-http-client庫可以自已分辨是被用在哪一種應用下,不需要額外的設定。
詳情:https://my.oschina.net/u/725054/blog/494494
http://blog.csdn.net/wangpeng047/article/details/19624529
9.如何保證一個後臺服務不被殺死;比較省電的方式是什麼
服務不被殺死分3種來討論
1.系統根據資源分配情況殺死服務
2.使用者通過 settings -> Apps -> Running -> Stop 方式殺死服務
3.使用者通過 settings -> Apps -> Downloaded -> Force Stop 方式殺死服務
第一種情況:
使用者不干預,完全靠系統來控制,辦法有很多。比如 onStartCommand() 方法的返回值設為 START_STICKY ,服務就會在資源緊張的時候被殺掉,然後在資源足夠的時候再恢復。當然也可設定為前臺服務,使其有高的優先順序,在資源緊張的時候也不會被殺掉。
第二種情況:
使用者干預,主動殺掉執行中的服務。這個過程殺死服務會通過服務的生命週期,也就是會呼叫 onDestory() 方法,這時候一個方案就是在 onDestory() 中傳送廣播開啟自己。這樣殺死服務後會立即啟動。
當然,從理論上來講這個方案是可行的,實驗一下也可以。但有些情況下,傳送的廣播在訊息佇列中排的靠後,就有可能服務還沒接收到廣播就銷燬了(這是我對實驗結果的猜想,具體執行步驟暫時還不瞭解)。所以為了能讓這個機制完美執行,可以開啟兩個服務,相互監聽,相互啟動。服務A監聽B的廣播來啟動B,服務B監聽A的廣播來啟動A。經過實驗,這個方案可行,並且用360殺掉後幾秒後服務也還是能自啟的。到這裡再說一句,如果不是某些功能需要的服務,不建議這麼做,會降低使用者體驗。
第三種情況:
強制關閉就沒有辦法。這個好像是從包的level去關的,並不走完整的生命週期。所以在服務里加程式碼是無法被呼叫的。處理這個情況的唯一方法是遮蔽掉 force stop和 uninstall 按鈕,讓其不可用。方法自己去找吧。當然有些手機自帶的清理功能就是從這個地方清理的,比如華為的清理。所以第三種情況我也沒有什麼更好的辦法了。
詳情:http://www.tuicool.com/articles/iu22QnF
10.如何通過廣播攔截和abort一條簡訊;廣播是否可以請求網路;廣播引起anr的時間限制
目前找到方法都是適用於Android4.4預設簡訊應用以前的方法:
第一步:新建一個類繼承BroadcastReceiver,並重寫onReceive()方法.
第二步:訂閱簡訊的廣播Intent,訂閱方法有兩種:
1:使用程式碼進行訂閱
2:在AndroidManifest.xml檔案中的<application>節點中進行訂閱
在Android中,每次廣播訊息到來時都會建立BroadcastReceiver例項並執行onReceive() 方法,
onReceive() 方法執行完後,BroadcastReceiver 的例項就會被銷燬。攔截簡訊的方法就寫在onReceive() 方法裡即可。
詳情:http://blog.csdn.net/jason0539/article/details/11720419
廣播可以監聽網路狀態,網路變化等,好像不能請求網路。
在 Android中,程式的響應(Responsive)被活動管理器(Activity Manager)和視窗管理器(Window Manager)這兩個系統服務所監視,當BroadcastReceiver在10秒內沒有執行完畢,Android會認為該程式無響應,所以在 BroadcastReceiver裡不能做一些比較耗時的操作,否則會彈出ANR(Application No Response)的對話方塊。如果需要完成一項比較耗時的工作,應該通過傳送Intent給Service,由Service來完成,而不是使用子執行緒的方法來解決,因為BroadcastReceiver的生命週期很短(在onReceive()執行後BroadcastReceiver的例項就會被銷燬),子執行緒可能還沒有結束BroadcastReceiver就先結束了。如果BroadcastReceiver結束了,它的宿主程式還在執行,那麼 子執行緒還會繼續執行。但宿主程式此時很容易在系統需要內在時被優先殺死。因為它屬於空程式(沒有任何活動元件的程式)。
詳情:http://blog.csdn.net/wufen1103/article/details/7839107
11.程式間通訊,AIDL
aidl是 Android Interface definition language的縮寫,一看就明白,它是一種android內部程式通訊介面的描述語言,通過它我們可以定義程式間的通訊介面
詳情:http://blog.csdn.net/stonecao/article/details/6425019
12.Handler機制及底層實現
詳情:http://www.jianshu.com/p/9e4d1fab0f36
http://blog.csdn.net/itachi85/article/details/8035333
13.Binder機制及底層實現
詳情:http://blog.csdn.net/weijinqian0/article/details/52233529
14.ApplicationContext和ActivityContext的區別
Context,中文直譯為“上下文”,它是一個抽象類,描述的是一個應用程式環境的資訊,通過它我們可以獲取應用程式的資源和類,也包括一些應用級別操作。
應用程式建立Context例項的情況一共有三種:
1、建立Application 物件時
2、建立Service物件時
3、建立Activity物件時
其中對於ApplicationContext,每個應用程式在第一次啟動時,都會首先建立Application物件。如果對應用程式啟動一個Activity(startActivity)流程比較清楚的話,建立Application的時機在建立handleBindApplication()方法中,該函式位於 ActivityThread.java類中;
對於ActivityContext,通過startActivity()或startActivityForResult()請求啟動一個Activity時,如果系統檢測需要新建一個Activity物件時,就會回撥handleLaunchActivity()方法,該方法繼而呼叫performLaunchActivity()方法,去建立一個Activity例項,並且回撥onCreate(),onStart()方法等, 函式都位於 ActivityThread.java類。
詳情:http://blog.csdn.net/qinjuning/article/details/7310620
寫在最後
在最後,我整理了一份資料,如果有需要學習的同學可以聯絡我免費分享出來的,希望在學習的道路少走彎路,共勉之
資料領取方式技術交流群:653583088