Android 面試題:Handler、自定義View、Java三大特性、分發機制、動畫(第1期)
(授權轉載)微信碼個蛋授權轉載
以下原文:
碼個蛋(codeegg)第 611 次推文
碼個蛋,碼上養成好習慣!
碼個蛋社群升級已經將近兩個月了,通過兩個月的觀察,感覺群友們每天學習的積極性都是很高的,每天的活躍度也很高(當然不是吹水)基本上大家討論的都是跟學習相關的內容
期間通過群友投票,我們選出了 碼個蛋 新的solgan: 碼個蛋,碼上養成好習慣!
為了幫助大家養成好習慣,碼仔們自發在社群裡提出了 每日一問! 每天一道面試題!然後收錄大家的答案整合到一起,方便大家的學習和複習。
為了讓大家更方便的找到每日問題,碼仔決定在公號內推出一個新的文章系列: 《每週面試題總結》
這個系列是整合在碼個蛋學習群裡面的每日一題,這篇是第一週整理集合, 後續每週都會更新。
學習群詳細可見:《社群升級:Max你的學習效率》
如何正確使用Handler?
Handler的工作是依賴於Looper的,而Looper(與訊息佇列)又是屬於某一個執行緒(ThreadLocal是執行緒內部的資料儲存類,通過它可以在指定執行緒中儲存資料,其他執行緒則無法獲取到),其他執行緒不能訪問。因此Handler就是間接跟執行緒是繫結在一起了。因此要使用Handler必須要保證Handler所建立的執行緒中有Looper物件並且啟動迴圈。因為子執行緒中預設是沒有Looper的,所以會報錯。正確的使用方法是:
private final class WorkThread extends Thread {
private Handler mHandler;
public Handler getHandler() {
return mHandler;
}
public void quit() {
mHandler.getLooper().quit();
}
@Override
public void run() {
super.run();
//建立該執行緒對應的Looper,
// 內部實現
// 1。new Looper()
// 2。將1步中的lopper 放在ThreadLocal裡,ThreadLocal是儲存資料的,主要應用場景是:執行緒間資料互不影響的情況
// 3。在1步中的Looper的建構函式中new MessageQueue();
//其實就是建立了該執行緒對用的Looper,Looper裡建立MessageQueue來實現訊息機制
//對訊息機制不懂得同學可以查閱資料,網上很多也講的很不錯。
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("WorkThread", (Looper.getMainLooper() == Looper.myLooper()) + "," + msg.what);
}
};
//開啟訊息的死迴圈處理即:dispatchMessage
Looper.loop();
//注意這3個的順序不能顛倒
Log.d("WorkThread", "end");
}
}
自定義控制元件優化方案
為了加速你的view,對於頻繁呼叫的方法,需要儘量減少不必要的程式碼。先從onDraw開始,需要特別注意不應該在這裡做記憶體分配的事情,因為它會導致GC,從而導致卡頓。在初始化或者動畫間隙期間做分配記憶體的動作。不要在動畫正在執行的時候做記憶體分配的事情。
你還需要儘可能的減少onDraw被呼叫的次數,大多數時候導致onDraw都是因為呼叫了invalidate().因此請儘量減少呼叫invaildate()的次數。如果可能的話,儘量呼叫含有4個引數的invalidate()方法而不是沒有引數的invalidate()。沒有引數的invalidate會強制重繪整個view。
另外一個非常耗時的操作是請求layout。任何時候執行requestLayout(),會使得Android UI系統去遍歷整個View的層級來計算出每一個view的大小。如果找到有衝突的值,它會需要重新計算好幾次。另外需要儘量保持View的層級是扁平化的,這樣對提高效率很有幫助。如果你有一個複雜的UI,你應該考慮寫一個自定義的ViewGroup來執行他的layout操作。與內建的view不同,自定義的view可以使得程式僅僅測量這一部分,這避免了遍歷整個view的層級結構來計算大小。這個PieChart 例子展示瞭如何繼承ViewGroup作為自定義view的一部分。PieChart 有子views,但是它從來不測量它們。而是根據他自身的layout法則,直接設定它們的大小。
談談你對Java三大特性的理解
封裝
封裝最好理解了。封裝是面向物件的特徵之一,是物件和類概念的主要特性。
封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。
繼承
面向物件程式設計 (OOP) 語言的一個主要功能就是“繼承”。繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴充套件。
通過繼承建立的新類稱為“子類”或“派生類”。
被繼承的類稱為“基類”、“父類”或“超類”。
繼承的過程,就是從一般到特殊的過程。
多型
多型性(polymorphisn)是允許你將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。
實現多型,有二種方式,覆蓋,過載。
覆蓋,是指子類重新定義父類的虛擬函式的做法。
過載,是指允許存在多個同名函式,而這些函式的引數表不同(或許引數個數不同,或許引數型別不同,或許兩者都不同)。
談談Android的事件分發機制
事件的傳遞流程:
Activity(PhoneWindow)->DecorView->ViewGroup->View。
事件分發過程中三個重要的方法:
dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent();
事件傳遞規則
一般一次點選會有一系列的MotionEvent,可以簡單分為:down->move->….->move->up,當一次event分發到ViewGroup時,ViewGroup收到事件後呼叫dispatchTouchEvent,在dispatchTouchEvent中先檢查是否要攔截,若攔截則ViewGroup處理事件,否則交給有處理能力的子容器處理。
Android動畫有幾種,對其理解
檢視動畫。檢視移動、view真真的位置並未移動。
幀動畫。就和放電影一樣,一幀一幀的播
屬性動畫。檢視移動、其位置也會隨著移動。
觸控返回動畫。發生觸控事件時有反饋效果。比如波紋效果
揭露動畫。從某一個點向四周展開或者從四周向某一點聚合起來。
轉場動畫 & 共享元素。比如切換activity。共享元素一般我們使用在轉換的前後兩個頁面有共同元素時。
檢視狀態動畫。就是 View 在狀態改變時執行的動畫效果
向量圖動畫。在圖片的基礎上做動畫。
約束佈局實現的關鍵幀動畫。就是給需要動畫效果的屬性,準備一組與時間相關的值。關鍵的幾個值。
結束語
如果你有好的答案可以提交至:
https://github.com/codeegginterviewgroup/CodeEggDailyInterview