Android工程師面試題大全

超低空發表於2016-02-01

校招的日子結束了,結果也算圓滿。忙碌了一陣子,現在終於可以安安靜靜的做做專案看看書寫寫論文了。下面對這段時間面試遇到的問題並結合網上各位的大神秒下的面試題做個總結,本文會持續更新,希望能在面試中助各位一臂之力!

Java基礎:

1、記憶體洩露的原因:

  1. 資源物件沒關閉。
    如Cursor、File等資源。他們會在finalize中關閉,但這樣效率太低。容易造成記憶體洩露。
    SQLiteCursor,當資料量大的時候容易洩露
  2. 使用Adapter時,沒有使用系統快取的converView。
  3. 即時呼叫recycle()釋放不再使用的Bitmap。
    適當降低Bitmap的取樣率,如:
    BitmapFactory.Options options = newBitmapFactory.Options();    
    options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一    
    Bitmap bitmap =BitmapFactory.decodeStream(cr.openInputStream(uri), null, options); preview.setImageBitmap(bitmap);
  4. 使用application的context來替代activity相關的context。
    儘量避免activity的context在自己的範圍外被使用,這樣會導致activity無法釋放。
  5. 註冊沒取消造成記憶體洩露
    如:廣播
  6. 集合中的物件沒清理造成的記憶體洩露我們通常把一些物件的引用加入到了集合中,當我們不需要該物件時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
  7. Handler應該申明為靜態物件, 並在其內部類中儲存一個對外部類的弱引用。如下:
    static class MyHandler extends Handler 
    {
           WeakReference<Activity > mActivityReference;
           MyHandler(Activity activity)
          { 
                mActivityReference= new WeakReference<Activity>(activity);
          }
         @Override
         public void handleMessage(Message msg)
        {
               final Activity activity = mActivityReference.get();
               if (activity != null)
              {
                     mImageView.setImageBitmap(mBitmap);
              }    
         }
    }

2、ArrayList和LinkedList的區別

  • ArrayList初試大小為10,大小不夠會呼叫grow擴容:length = length + (length >> 1)
  • LinkedList中Node first,last。分別指向頭尾

ArrayList和LinkedList在效能上各 有優缺點,都有各自所適用的地方,總的說來可以描述如下:

  1. 對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對 ArrayList而言,主要是在內部陣列中增加一項,指向所新增的元素,偶爾可能會導致對陣列重新進行分配;而對LinkedList而言,這個開銷是 統一的,分配一個內部Entry物件。
  2. 在ArrayList的 中間插入或刪除一個元素意味著這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
  3. LinkedList不 支援高效的隨機元素訪問。
  4. ArrayList的空 間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間。
    可以這樣說:當操作是在一列 資料的後面新增資料而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的效能;當你的操作是在一列資料的前面或中 間新增或刪除資料,並且按照順序訪問其中的元素時,就應該使用LinkedList了。

3、hashmap和hashtable的不同

  1. 繼承不同。
    public class Hashtable extends Dictionary implements Map
    public class HashMap extends AbstractMap implements Map
  2. Hashtable 中的方法是同步的,而HashMap中的方法在預設情況下是非同步的。在多執行緒併發的環境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。
  3. Hashtable中,key和value都不允許出現null值。
    在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
  4. 兩個遍歷方式的內部實現上不同。
    Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
  5. 雜湊值的使用不同,HashTable直接使用物件的hashCode。而HashMap重新計算hash值。
    6.Hashtable和HashMap它們兩個內部實現方式的陣列的初始大小和擴容的方式。HashTable中hash陣列預設大小是11,增加的方式是 old*2+1。HashMap中hash陣列的預設大小是16,而且一定是2的指數。

4、Iterator和Enumeration的不同

  1. 函式介面不同
    Enumeration只有2個函式介面。通過Enumeration,我們只能讀取集合的資料,而不能對資料進行修改。 Iterator只有3個函式介面。Iterator除了能讀取集合的資料之外,也能資料進行刪除操作。
  2. Iterator支援fail-fast機制,而Enumeration不支援。 Enumeration 是JDK 1.0新增的介面。使用到它的函式包括Vector、Hashtable等類,這些類都是JDK 1.0中加入的,Enumeration存在的目的就是為它們提供遍歷介面。Enumeration本身並沒有支援同步,而在Vector、Hashtable實現Enumeration時,新增了同步。而Iterator 是JDK 1.2才新增的介面,它也是為了HashMap、ArrayList等集合提供遍歷介面。Iterator是支援fail-fast機制的:當多個執行緒對同一個集合的內容進行操作時,就可能會產生fail-fast事件。

ail-fast 機制是java集合(Collection)中的一種錯誤機制。當多個執行緒對同一個集合的內容進行操作時,就可能會產生fail-fast事件。例如:當某一個執行緒A通過iterator去遍歷某集合的過程中,若該集合的內容被其他執行緒所改變了;那麼執行緒A訪問集合時,就會丟擲ConcurrentModificationException異常,產生fail-fast事件。

5、介面的注意點

  1. 介面中的欄位全部預設為 public static型別。
  2. 介面中的方法全部預設為 public型別。
  3. 介面中可以申明內部類,而預設為public static,正因為是static,只是名稱空間屬於介面,程式碼邏輯不屬於介面。所以不違法介面定義。
  4. 介面本身可以申明為public或者預設。
  5. 抽象類繼承自某介面。如果在抽象類中實現了父類(介面)中的方法,在其子類可以不用實現,否則在子類必須實現。

6、final方法

將方法宣告為final那有兩個原因,第一就是說明你已經知道這個方法提供的功能已經滿足你要求,不需要進行擴充套件,並且也不允許任何從此類繼承的類來覆寫這個方法,但是繼承仍然可以繼承這個方法,也就是說可以直接使用。第二就是允許編譯器將所有對此方法的呼叫轉化為inline呼叫的機制,它會使你在呼叫final方法時,直接將方法主體插入到呼叫處,而不是進行例行的方法呼叫,例如儲存斷點,壓棧等,這樣可能會使你的程式效率有所提高,然而當你的方法主體非常龐大時,或你在多處呼叫此方法,那麼你的呼叫主體程式碼便會迅速膨脹,可能反而會影響效率,所以你要慎用final進行方法定義。

Android知識點

1、Handler機制

  1. Handler對Activity finish影響。
    在開發的過程中碰到一個棘手的問題,呼叫Activity.finish函式Acitivity沒有執行生命週期的ondestory函式,後面查詢半天是因為有一個handler成員,因為它有一個delay訊息沒有處理,呼叫Activity.finish,Activity不會馬上destory,所以記得在Ativity finish前清理一下handle中的未處理的訊息,這樣Activity才會順利的destory
  2. Looper
    通過呼叫Looper.prepare()建立Looper()物件並繫結到ThreadLocal變數中。
    Looper裡面包含了messageQueue。
    構造器如下:
    private Looper()
    {
         mQueue = new MessageQueue();
         mRun = true;
         mThread = Thread.currentThread();
    }
  3. loop()函式
    1)從Looper中取出MessageQueue;
    2)迴圈從MessageQueue中取出Message;
    3)從Message中取出Target(Handler物件);
    4)呼叫tartget的dispatchMessage分發訊息。
  4. Handler物件
    重要成員變數:
    final MessageQueue mQueue;
    final Looper  mLooper;
    final Callback mCallback;   //用於回撥

    Handler物件在傳送訊息的時候,將MSG的target變數設為自己。這樣在Looper物件迴圈取出msg的時候就可以呼叫對應handler的dispatchMessage()。此函式分發訊息的優先順序如下:
    Message在建立的時候呼叫Obtain設定了Callback。
    Handler在建立的時候傳入了Callback。
    交給Handler子類的HandleMessage處理(通常的做法)。

2、Android啟動模式

standard和singleTop模式。
這兩種比較簡單。建立Activity放入當前的任務棧中,若當前是singleInstace,則放入設定的任務棧中。其中如果Activity在棧頂,則呼叫onNewIntent。

singletask:棧內複用模式。不是在當前任務棧中查詢是否存在,實際過程如下:

  1. 查詢該Activity所需的任務棧是否存在(由taskAffinity控制,或者預設為包名)。
  2. 在任務棧當中查詢該Activity是否存在。
    這裡面存在任務棧的切換,也就是當開啟的singtask型別的Activity不屬於當前任務棧時,則會切換到其任務棧。

singleInstance:單例項模式。
包含了singleTask的所有特性,另外加上:設定為該模式的Activity,只能單獨存在於一個任務棧中。當有兩個singleInstace的Activity設定成同樣的任務棧時,會出現兩個同名的任務棧,分別用來存放同名的Activity。
注:在任何跳轉的時候,首先呼叫本Activity的onPause,然後跳轉。如果被跳轉的activity由於啟動方式而沒建立新的例項,則會先呼叫onNewIntent,然後按照正常的生命週期呼叫。

1:A→B,A:onPause;B:onCreate,onStart,onResume。
2:A(singleTop)→A,A:onPause;A:onSaveInstanceState;A:onResume。

3、View的繪製

推薦郭霖大神的部落格:
http://blog.csdn.net/guolin_blog/article/details/16330267

4、canvas的使用

推薦以下部落格:
http://blog.csdn.net/qinjuning/article/details/6936783

5、ActivityManagerService的相關知識點

推薦以下部落格:
http://wiki.jikexueyuan.com/project/deep-android-v2/activity.html

6、Activity切換時生命週期交集

Activity之間的協作當一個activity A啟動了另外一個activity B,它們的生命週期是有交叉的;
首先A的onPause()被呼叫;
之後B的onCrate(), onStart()及onResume() 方法會被呼叫(此時B擁有使用者焦點);
最後,如果A在螢幕上不可見,onStop()方法被呼叫;
因此,我們在兩個activities中傳遞資料,或者共享資源時(如資料庫連線),需要在前一個activity的onPause()方法而不是onStop()方法中進行;

7、Hybrid(重要加分項)

  1. java和JS的互動
    http://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/
    http://rensanning.iteye.com/blog/2043049
  2. WebView開啟JavaScript指令碼執行
  3. WebView設定供JavaScript呼叫的互動介面。

8、網路程式設計

  1. volley
    https://bxbxbai.github.io/2014/09/14/android-working-with-volley/
    http://blog.csdn.net/guolin_blog/article/details/17656437
  2. 如何控制TCP連線時的擁塞
    http://blog.csdn.net/yechaodechuntian/article/details/25429143
  3. 三次握手
    http://blog.csdn.net/whuslei/article/details/6667471
  4. Android客戶端和服務端如何使用Token和Session
    http://wyong.blog.51cto.com/1115465/1553352
  5. 移動端獲取網路資料優化的幾個點
    1. 連線複用 :
      節省連線建立時間,如開啟 keep-alive。
      對於 Android 來說預設情況下 HttpURLConnection 和 HttpClient 都開啟了 keep-alive。只是 2.2 之前 HttpURLConnection 存在影響連線池的 Bug,具體可見:Android HttpURLConnection 及 HttpClient 選擇
    2. 請求合併:
      即將多個請求合併為一個進行請求,比較常見的就是網頁中的 CSS Image Sprites。如果某個頁面內請求過多,也可以考慮做一定的請求合併。
    3. 減少請求資料的大小:
      對於post請求,body可以做gzip壓縮的,header也可以作資料壓縮(不過只支援http 2.0)。
    4. 返回的資料的body也可以作gzip壓縮,body資料體積可以縮小到原來的30%左右。(也可以考慮壓縮返回的json資料的key資料的體積,尤其是針對返回資料格式變化不大的情況,支付寶聊天返回的資料用到了)
    5. 根據使用者的當前的網路質量來判斷下載什麼質量的圖片(電商用的比較多)。

9、android開發中,可能會導致記憶體洩露的問題

  1. 不要讓生命週期長於Activity的物件持有到Activity的引用
  2. 儘量使用Application的Context而不是Activity的Context
  3. 儘量不要在Activity中使用非靜態內部類,因為非靜態內部類會隱式持有外部類例項的引用(具體可以檢視細話Java:”失效”的private修飾符瞭解)。如果使用靜態內部類,將外部例項引用作為弱引用持有。
  4. 垃圾回收不能解決記憶體洩露,瞭解Android中垃圾回收機制
    **更多內容可以參考以下部落格:
    http://spencer-dev.lofter.com/post/d7b9e_6faf120

10、activity的啟動過程:

http://www.cloudchou.com/android/post-788.html

以上是我遇到和蒐集到的各類題目以及相應的解答,接下來一段時間也會持續更新,大家遇到什麼經典或者不會的問題也可以給我留言,在此統一分享給大家。祝大家能夠找到自己心儀的工作,前途一片光明!

相關文章