Android高階開發面試題目,再也不用擔心不能升職加薪了。

想念你的Android發表於2019-01-05

Java基礎

1、內部類的作用

  • 內部類可以用多個例項,每個例項都有自己的狀態資訊,並且與其他外圍物件的資訊相互獨立。

  • 在單個外部類中,可以讓多個內部類以不同的方式實現同一個介面,或者繼承同一個類。

  • 建立內部類物件的時刻並不依賴於外圍類物件的建立。

  • 內部類並沒有令人迷惑的“is-a”關係,他就是一個獨立的實體。

  • 內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問

2、父類的靜態方法能否被子類重寫,為什麼?

  • 不能

  • 子類繼承父類後,用相同的靜態方法和非靜態方法,這時非靜態方法覆蓋父類中的方法(即方法重寫),父類的該靜態方法被隱藏(如果物件是父類則呼叫該隱藏的方法),另外子類可繼承父類的靜態與非靜態方法,至於方法過載我覺得它其中一要素就是在同一類中,不能說父類中的什麼方法與子類裡的什麼方法是方法過載的體現

3、哪些情況下的物件會被垃圾回收機制處理掉

  • Java垃圾回收機制最基本的做法是分代回收。記憶體中的區域被劃分成不同的世代,物件根據其存活的時間被儲存在對應世代的區域中。一般的實現是劃分成3個世代:年輕、年老和永久。記憶體的分配是發生在年輕世代中的。當一個物件存活時間足夠長的時候,它就會被複制到年老世代中。對於不同的世代可以使用不同的垃圾回收演算法。進行世代劃分的出發點是對應用中物件存活時間進行研究之後得出的統計規律。一般來說,一個應用中的大部分物件的存活時間都很短。比如區域性變數的存活時間就只在方法的執行過程中。基於這一點,對於年輕世代的垃圾回收演算法就可以很有針對性。

4、程式和執行緒的區別

  • 簡而言之,一個程式至少有一個程式,一個程式至少有一個執行緒。

  • 執行緒的劃分尺度小於程式,使得多執行緒程式的併發性高。

  • 另外,程式在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。

  • 執行緒在執行過程中與程式還是有區別的。每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。

  • 從邏輯角度來看,多執行緒的意義在於一個應用程式中,有多個執行部分可以同時執行。但作業系統並沒有將多個執行緒看做多個獨立的應用,來實現程式的排程和管理以及資源分配。這就是程式和執行緒的重要區別。

  • 程式是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程式是系統進行資源分配和排程的一個獨立單位.

  • 執行緒是程式的一個實體,是CPU排程和分派的基本單位,它是比程式更小的能獨立執行的基本單位.執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一組暫存器和棧),但是它可與同屬一個程式的其他的執行緒共享程式所擁有的全部資源.

  • 一個執行緒可以建立和撤銷另一個執行緒;同一個程式中的多個執行緒之間可以併發執行.

  • 程式和執行緒的主要差別在於它們是不同的作業系統資源管理方式。程式有獨立的地址空間,一個程式崩潰後,在保護模式下不會對其它程式產生影響,而執行緒只是一個程式中的不同執行路徑。執行緒有自己的堆疊和區域性變數,但執行緒之間沒有單獨的地址空間,一個執行緒死掉就等於整個程式死掉,所以多程式的程式要比多執行緒的程式健壯,但在程式切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變數的併發操作,只能用執行緒,不能用程式。如果有興趣深入的話,我建議你們看看《現代作業系統》或者《作業系統的設計與實現》。對就個問題說得比較清楚。

5、HashMap的實現原理

  • HashMap概述:HashMap是基於雜湊表的Map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。

  • HashMap的資料結構:在java程式語言中,最基本的結構就是兩種,一個是陣列,另外一個是模擬指標(引用),所有的資料結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“連結串列雜湊”的資料結構,即陣列和連結串列的結合體。

  • HashMap底層就是一個陣列結構,陣列中的每一項又是一個連結串列。當新建一個HashMap的時候,就會初始化一個陣列。

6、String、StringBuffer、StringBuilder區別

  • String 字串常量

  • StringBuffer 字串變數(執行緒安全)

  • StringBuilder 字串變數(非執行緒安全)

  • 簡要的說, String 型別和 StringBuffer 型別的主要效能區別其實在於 String 是不可變的物件, 因此在每次對 String 型別進行改變的時候其實都等同於生成了一個新的 String 物件,然後將指標指向新的 String 物件,所以經常改變內容的字串最好不要用String ,因為每次生成物件都會對系統效能產生影響,特別當記憶體中無引用物件多了以後,JVM 的 GC 就會開始工作,那速度是一定會相當慢的。

  • 而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 物件本身進行操作,而不是生成新的物件,再改變物件引用。所以在一般情況下我們推薦使用 StringBuffer ,特別是字串物件經常改變的情況下。而在某些特別情況下, String 物件的字串拼接其實是被 JVM 解釋成了 StringBuffer 物件的拼接,所以這些時候 String 物件的速度並不會比 StringBuffer 物件慢,而特別是以下的字串物件生成中, String 效率是遠要比 StringBuffer 快的:

在大部分情況下 StringBuffer > String

  • Java.lang.StringBuffer執行緒安全的可變字元序列。一個類似於 String 的字串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字元序列,但通過某些方法呼叫可以改變該序列的長度和內容。

  • 可將字串緩衝區安全地用於多個執行緒。可以在必要時對這些方法進行同步,因此任意特定例項上的所有操作就好像是以序列順序發生的,該順序與所涉及的每個執行緒進行的方法呼叫順序一致。

  • StringBuffer 上的主要操作是 append 和 insert 方法,可過載這些方法,以接受任意型別的資料。每個方法都能有效地將給定的資料轉換成字串,然後將該字串的字元追加或插入到字串緩衝區中。append 方法始終將這些字元新增到緩衝區的末端;而 insert 方法則在指定的點新增字元。

在大部分情況下 StringBuilder > StringBuffer

  • java.lang.StringBuilder一個可變的字元序列是5.0新增的。此類提供一個與 StringBuffer 相容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字串緩衝區被單個執行緒使用的時候(這種情況很普遍)。如果可能,建議優先採用該類,因為在大多數實現中,它比 StringBuffer 要快。兩者的方法基本相同

7、什麼導致執行緒阻塞

執行緒的阻塞

  • 為了解決對共享儲存區的訪問衝突,Java 引入了同步機制,現在讓我們來考察多個執行緒對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經準備好了被訪問,反過來,同一時刻準備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支援.

  • 阻塞指的是暫停一個執行緒的執行以等待某個條件發生(如某資源就緒),學過作業系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支援阻塞,下面讓我們逐一分析。

  • sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為引數,它使得執行緒在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,執行緒重新進入可執行狀態。 典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓執行緒阻塞一段時間後重新測試,直到條件滿足為止。

  • suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得執行緒進入阻塞狀態,並且不會自動恢復,必須其對應的resume() 被呼叫,才能使得執行緒重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個執行緒產生的結果的情形:測試發現結果還沒有產生後,讓執行緒阻塞,另一個執行緒產生了結果後,呼叫 resume() 使其恢復。

  • yield() 方法:yield() 使得執行緒放棄當前分得的 CPU 時間,但是不使執行緒阻塞,即執行緒仍處於可執行狀態,隨時可能再次分得 CPU 時間。呼叫 yield() 的效果等價於排程程式認為該執行緒已執行了足夠的時間從而轉到另一個執行緒.

  • wait() 和 notify() 方法:兩個方法配套使用,wait() 使得執行緒進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為引數,另一種沒有引數,前者當對應的 notify() 被呼叫或者超出指定時間時執行緒重新進入可執行狀態,後者則必須對應的 notify() 被呼叫.

  • 初看起來它們與 suspend() 和 resume() 方法對沒有什麼分別,但是事實上它們是截然不同的。區別的核心在於,前面敘述的所有方法,阻塞時都不會釋放佔用的鎖(如果佔用了的話),而這一對方法則相反。

  • 首先,前面敘述的所有方法都隸屬於 Thread 類,但是這一對卻直接隸屬於 Object 類,也就是說,所有物件都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放佔用的鎖,而鎖是任何物件都具有的,呼叫任意物件的 wait() 方法導致執行緒阻塞,並且該物件上的鎖被釋放。而呼叫 任意物件的notify()方法則導致因呼叫該物件的 wait() 方法而阻塞的執行緒中隨機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。

  • 其次,前面敘述的所有方法都可在任何位置呼叫,但是這一對方法卻必須在 synchronized 方法或塊中呼叫,理由也很簡單,只有在synchronized 方法或塊中當前執行緒才佔有鎖,才有鎖可以釋放。同樣的道理,呼叫這一對方法的物件上的鎖必須為當前執行緒所擁有,這樣才有鎖可以釋放。因此,這一對方法呼叫必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖物件就是呼叫這一對方法的物件。若不滿足這一條件,則程式雖然仍能編譯,但在執行時會出現IllegalMonitorStateException 異常。

  • wait() 和 notify() 方法的上述特性決定了它們經常和synchronized方法或塊一起使用,將它們和作業系統的程式間通訊機制作一個比較就會發現它們的相似性:synchronized方法或塊提供了類似於作業系統原語的功能,它們的執行不會受到多執行緒機制的干擾,而這一對方法則相當於 block 和wakeup 原語(這一對方法均宣告為 synchronized)。它們的結合使得我們可以實現作業系統上一系列精妙的程式間通訊的演算法(如訊號量演算法),並用於解決各種複雜的執行緒間通訊問題。

關於 wait() 和 notify() 方法最後再說明兩點:

  • a、呼叫 notify() 方法導致解除阻塞的執行緒是從因呼叫該物件的 wait() 方法而阻塞的執行緒中隨機選取的,我們無法預料哪一個執行緒將會被選擇,所以程式設計時要特別小心,避免因這種不確定性而產生問題。

  • b、除了 notify(),還有一個方法 notifyAll() 也可起到類似作用,唯一的區別在於,呼叫 notifyAll() 方法將把因呼叫該物件的 wait() 方法而阻塞的所有執行緒一次性全部解除阻塞。當然,只有獲得鎖的那一個執行緒才能進入可執行狀態。

Android基礎

1、是否使用過IntentService,作用是什麼,AIDL解決了什麼問題?

  • 生成一個預設的且與主執行緒互相獨立的工作者執行緒來執行所有傳送至onStartCommand() 方法的Intetnt。

  • 生成一個工作佇列來傳送Intent物件給你的onHandleIntent()方法,同一時刻只傳送一個Intent物件,這樣一來,你就不必擔心多執行緒的問題。在所有的請求(Intent)都被執行完以後會自動停止服務,所以,你不需要自己去呼叫stopSelf()方法來停止。

  • 該服務提供了一個onBind()方法的預設實現,它返回null

  • 提供了一個onStartCommand()方法的預設實現,它將Intent先傳送至工作佇列,然後從工作佇列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent對相應的處理。

  • AIDL (Android Interface Definition Language) 是一種IDL 語言,用於生成可以在Android裝置上兩個程式之間進行程式間通訊(interprocess communication, IPC)的程式碼。如果在一個程式中(例如Activity)要呼叫另一個程式中(例如Service)物件的操作,就可以使用AIDL生成可序列化的引數。 AIDL IPC機制是面向介面的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞資料。

2、Activity、Window、View三者的差別?

  • Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示檢視) LayoutInflater像剪刀,Xml配置像窗花圖紙。

  • 在Activity中呼叫attach,建立了一個Window

  • 建立的window是其子類PhoneWindow,在attach中建立PhoneWindow

  • 在Activity中呼叫setContentView(R.layout.xxx)

  • 其中實際上是呼叫的getWindow().setContentView()

  • 呼叫PhoneWindow中的setContentView方法

  • 建立ParentView: 作為ViewGroup的子類,實際是建立的DecorView(作為FramLayout的子類)

  • 將指定的R.layout.xxx進行填充 通過佈局填充器進行填充【其中的parent指的就是DecorView】

  • 呼叫到ViewGroup

  • 呼叫ViewGroup的removeAllView(),先將所有的view移除掉

    新增新的view:addView()

3、Fragment 特點

  • Fragment可以作為Activity介面的一部分組成出現;

  • 可以在一個Activity中同時出現多個Fragment,並且一個Fragment也可以在多個Activity中使用;

  • 在Activity執行過程中,可以新增、移除或者替換Fragment;

  • Fragment可以響應自己的輸入事件,並且有自己的生命週期,它們的生命週期會受宿主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系統的封裝。

  • android.os.Handler可以通過Looper物件例項化,並執行於另外的執行緒中,Android提供了讓Handler執行於其它執行緒的執行緒實現,也就是HandlerThread。HandlerThread物件start後可以獲得其Looper物件,並且使用這個Looper物件例項Handler。

5、Launch mode應用場景

  • Standard,建立一個新的Activity。

  • SingleTop,棧頂不是該型別的Activity,建立一個新的Activity。否則,onNewIntent。

  • SingleTask,回退棧中沒有該型別的Activity,建立Activity,否則,onNewIntent+ClearTop。

注意:

  • 設定了"singleTask"啟動模式的Activity,它在啟動的時候,會先在系統中查詢屬性值affinity等於它的屬性值taskAffinity的Task存在; 如果存在這樣的Task,它就會在這個Task中啟動,否則就會在新的任務棧中啟動。因此, 如果我們想要設定了"singleTask"啟動模式的Activity在新的任務中啟動,就要為它設定一個獨立的taskAffinity屬性值。

  • 如果設定了"singleTask"啟動模式的Activity不是在新的任務中啟動時,它會在已有的任務中檢視是否已經存在相應的Activity例項, 如果存在,就會把位於這個Activity例項上面的Activity全部結束掉,即最終這個Activity 例項會位於任務的Stack頂端中。

  • 在一個任務棧中只有一個”singleTask”啟動模式的Activity存在。他的上面可以有其他的Activity。這點與singleInstance是有區別的。

    singleInstance,回退棧中,只有這一個Activity,沒有其他Activity。

  • SingleTop適合接收通知啟動的內容顯示頁面。

  • 例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都開啟一個新聞內容頁面是很煩人的。

  • singleTask適合作為程式入口點。

  • 例如瀏覽器的主介面。不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。

  • singleInstance應用場景:

  • 鬧鈴的響鈴介面。 你以前設定了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設定介面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,並且彈出了一個對話方塊形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 載入模式開啟的),你按返回鍵,回到的是微信的聊天介面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 開啟 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設定介面。

6、Android事件分發機制

  • https://www.jianshu.com/p/38015afcdb58

7、view繪製流程

  • https://www.jianshu.com/p/bb7977990baa

8、post和postDelay

9、執行緒同步

  • http://www.itzhai.com/java-based-notebook-thread-synchronization-problem-solving-synchronization-problems-synchronized-block-synchronized-methods.html#read-more

    推薦:Android開發面試題彙總

    [收集的Android面試題,有時間看看~1、 Android dvm的程式和Linux的程式, 應用程式的程式是否為同一個概念DVM指Dalvik的虛擬機器。每一個Android應用程式都在它自己的程式中

  • 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、什麼情況導致記憶體洩漏

a、資源物件沒關閉造成的記憶體洩漏

  • 描述: 資源性物件比如(Cursor,File檔案等)往往都用了一些緩衝,我們在不使用的時候,應該及時關閉它們,以便它們的緩衝及時回收記憶體。它們的緩衝不僅存在於 java虛擬機器內,還存在於java虛擬機器外。如果我們僅僅是把它的引用設定為null,而不關閉它們,往往會造成記憶體洩漏。因為有些資源性物件,比如 SQLiteCursor(在解構函式finalize(),如果我們沒有關閉它,它自己會調close()關閉),如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。因此對於資源性物件在不使用的時候,應該呼叫它的close()函式,將其關閉掉,然後才置為null.在我們的程式退出時一定要確保我們的資源性物件已經關閉。 程式中經常會進行查詢資料庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小,對記憶體的消耗不容易被發現,只有在常時間大量操作的情況下才會復現記憶體問題,這樣就會給以後的測試和問題排查帶來困難和風險。

b、構造Adapter時,沒有使用快取的convertView

  • 以構造ListView的BaseAdapter為例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 來向ListView提供每一個item所需要的view物件。初始時ListView會從BaseAdapter中根據當前的螢幕佈局例項化一定數量的 view物件,同時ListView會將這些view物件快取起來。當向上滾動ListView時,原先位於最上面的list item的view物件會被回收,然後被用來構造新出現的最下面的list item。這個構造過程就是由getView()方法完成的,getView()的第二個形參View convertView就是被快取起來的list item的view物件(初始化時快取中沒有view物件則convertView是null)。由此可以看出,如果我們不去使用 convertView,而是每次都在getView()中重新例項化一個View物件的話,即浪費資源也浪費時間,也會使得記憶體佔用越來越大。 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物件不在使用時呼叫recycle()釋放記憶體

  • 有時我們會手工的操作Bitmap物件,如果一個Bitmap物件比較佔記憶體,當它不在被使用的時候,可以呼叫Bitmap.recycle()方法回收此物件的畫素所佔用的記憶體,但這不是必須的,視情況而定。

d、試著使用關於application的context來替代和activity相關的context

  • 這是一個很隱晦的記憶體洩漏的情況。有一種簡單的方法來避免context相關的記憶體洩漏。最顯著地一個是避免context逃出他自己的範圍之外。使用Application context。這個context的生存週期和你的應用的生存週期一樣長,而不是取決於activity的生存週期。如果你想保持一個長期生存的物件,並且這個物件需要一個context,記得使用application物件。你可以通過呼叫 Context.getApplicationContext() or Activity.getApplication()來獲得。更多的請看這篇文章如何避免 Android記憶體洩漏。

e、註冊沒反註冊造成的記憶體洩漏

  • 一些Android程式可能引用我們的Anroid程式的物件(比如序號產生器制)。即使我們的Android程式已經結束了,但是別的引用程式仍然還有對我們的Android程式的某個物件的引用,洩漏的記憶體依然不能被垃圾回收。呼叫registerReceiver後未呼叫unregisterReceiver。 比如:假設我們希望在鎖屏介面(LockScreen)中,監聽系統中的電話服務以獲取一些資訊(如訊號強度等),則可以在LockScreen中定義一個 PhoneStateListener的物件,同時將它註冊到TelephonyManager服務中。對於LockScreen物件,當需要顯示鎖屏介面的時候就會建立一個LockScreen物件,而當鎖屏介面消失的時候LockScreen物件就會被釋放掉。 但是如果在釋放 LockScreen物件的時候忘記取消我們之前註冊的PhoneStateListener物件,則會導致LockScreen無法被垃圾回收。如果不斷的使鎖屏介面顯示和消失,則最終會由於大量的LockScreen物件沒有辦法被回收而引起OutOfMemory,使得system_process 程式掛掉。 雖然有些系統程式,它本身好像是可以自動取消註冊的(當然不及時),但是我們還是應該在我們的程式中明確的取消註冊,程式結束時應該把所有的註冊都取消掉。

f、集合中物件沒清理造成的記憶體洩漏

  • 我們通常把一些物件的引用加入到了集合中,當我們不需要該物件時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。

12、ANR定位和如何避免?

  • 如果開發機器上出現問題,我們可以通過檢視/data/anr/traces.txt即可,最新的ANR資訊在最開始部分。

  • 主執行緒被IO操作(從4.0之後網路IO不允許在主執行緒中)阻塞。

  • 主執行緒中存在耗時的計算

  • 主執行緒中錯誤的操作,比如Thread.wait或者Thread.sleep等 Android系統會監控程式的響應狀況,一旦出現下面兩種情況,則彈出ANR對話方塊

  • 應用在5秒內未響應使用者的輸入事件(如按鍵或者觸控)

  • BroadcastReceiver未在10秒內完成相關的處理

  • Service在特定的時間內無法處理完成 20秒

避免

  • 使用AsyncTask處理耗時IO操作。

  • 使用Thread或者HandlerThread時,呼叫Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設定優先順序,否則仍然會降低程式響應,因為預設Thread的優先順序和主執行緒相同。

  • 使用Handler處理工作執行緒結果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主執行緒。

  • Activity的onCreate和onResume回撥中儘量避免耗時的程式碼

  • BroadcastReceiver中onReceive程式碼也要儘量減少耗時,建議使用IntentService處理。

13、什麼情況導致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後,那將保留在開始狀態,但是不保留那些傳入的intent。不久後service就會再次嘗試重新建立,因為保留在開始狀態,在建立 service後將保證呼叫onstartCommand。如果沒有傳遞任何開始命令給service,那將獲取到null的intent。

  • START_NOT_STICKY 在執行onStartCommand後service程式被kill後,並且沒有新的intent傳遞給它。Service將移出開始狀態,並且直到新的明顯的方法(startService)呼叫才重新建立。因為如果沒有傳遞任何未決定的intent那麼service是不會啟動,也就是期間onstartCommand不會接收到任何null的intent。

  • START_REDELIVER_INTENT 在執行onStartCommand後service程式被kill後,系統將會再次啟動service,並傳入最後一個intent給onstartCommand。直到呼叫stopSelf(int)才停止傳遞intent。如果在被kill後還有未處理好的intent,那被kill後服務還是會自動啟動。因此onstartCommand不會接收到任何null的intent。

提升service優先順序

  • 在AndroidManifest.xml檔案中對於intent-filter可以通過android:priority="1000"這個屬性設定最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。

提升service程式優先順序

  • Android中的程式是託管的,當系統程式空間緊張的時候,會依照優先順序自動進行程式的回收。Android將程式分為6個等級,它們按優先順序順序由高到低依次是:

  • 前臺程式( FOREGROUND_APP)

  • 可視程式(VISIBLE_APP )

  • 次要服務程式(SECONDARY_SERVER )

  • 後臺程式 (HIDDEN_APP)

  • 內容供應節點(CONTENT_PROVIDER)

  • 空程式(EMPTY_APP)

  • 當service執行在低記憶體的環境時,將會kill掉一些存在的程式。因此程式的優先順序將會很重要,可以使用startForeground 將service放到前臺狀態。這樣在低記憶體時被kill的機率會低一些。

onDestroy方法裡重啟service

service+broadcast方式,就是當service走ondestory的時候,傳送一個自定義的廣播,當收到廣播的時候,重新啟動service;

Application加上Persistent屬性

監聽系統廣播判斷Service狀態

16、RequestLayout,onLayout,onDraw,DrawChild區別與聯絡

  • requestLayout()方法 :會導致呼叫measure()過程 和 layout()過程 。說明:只是對View樹重新佈局layout過程包括measure()和layout()過程,不會呼叫draw()過程,但不會重新繪製 任何檢視包括該呼叫者本身。

  • onLayout()方法(如果該View是ViewGroup物件,需要實現該方法,對每個子檢視進行佈局)

  • 呼叫onDraw()方法繪製檢視本身(每個View都需要過載該方法,ViewGroup不需要實現該方法)

  • drawChild()去重新回撥每個子檢視的draw()方法

17、invalidate()和postInvalidate() 的區別及使用

  • http://blog.csdn.net/mars2639/article/details/6650876

18、LinearLayout對比RelativeLayout

  • RelativeLayout會讓子View呼叫2次onMeasure,LinearLayout 在有weight時,也會呼叫子View2次onMeasure

  • RelativeLayout的子View如果高度和RelativeLayout不同,則會引發效率問題,當子View很複雜時,這個問題會更加嚴重。如果可以,儘量使用padding代替margin。

  • 在不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是RelativeLayout。

19、優化自定義view

  • 為了加速你的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法則,直接設定它們的大小。

20、ContentProvider

  • https://www.jianshu.com/p/ea8bc4aaf057

21、Android 設計模式

  • http://blog.csdn.net/bboyfeiyu/article/details/44563871

22、MVC、MVP、MVM區別?

  • https://www.cnblogs.com/guwei4037/p/5591183.html

喜歡的話點個贊吧


相關文章