1. 程式人生 > >2018年Android面試題彙總四(持續更新中)

2018年Android面試題彙總四(持續更新中)

面試系列,推薦先讀我的心得:

十二、ThreadLocal

12.1、四大方法:set、get、remove和initialValue。

   1、initialValue在第一次呼叫get或set時執行,只執行一次,初始化內部類Values中Oject陣列。

   2、JDK5.0開始支援泛型

   3、內部ThreadLocal.ThreadLocalMap用來儲存key鍵ThreadLocal和Value值變數副本

12.2、如何為每個執行緒維護一個變數副本:

  a、ThreadLocal有個靜態類ThreadLocalMap,鍵key為當前ThreadLocal物件、值value為對應執行緒的變數副本。一個執行緒可能含有多個ThreadLocal

  b、ThreadLocal為不同的執行緒建立對應的ThreadLocalMap。在initialValue中createMap(t, value)

 c、使用ThreadLocal作為Key的原因,ThreadLocal相比Thread要少,提供效能

12.3、與執行緒同步機制比較

  1、同步機制僅提供有一個變數,不同執行緒排隊訪問;ThreadLocal為每個執行緒提供一個變數副本,可以同時訪問。

  2、ThreadLocal不是解決多執行緒變數問題,

  3、ThreadLocal一般宣告為static變數

12.4、存在的記憶體洩漏問題

   1、使用執行緒池,執行緒結束後不會銷燬而會被再次使用,就可能出現記憶體洩漏

   2、如果ThreadLocal置為null,則存在ThreadLocalMap

Object>,記憶體洩漏。執行緒被gc,執行緒中的ThreadMap也被銷燬,不會記憶體洩漏

12.5、適用場景

   資料庫連結、Session管理。多執行緒需要獲得初始狀態

十二、Android版ThreadLocal

  1、ThreadLocal的內部類Values中Oject陣列偶數位存ThreadLocal的弱引用,下一位存值

  2、採用斐波拉契雜湊定址

  3、Thread自身有個ThreadLocal.Values成員變數,在ThreadLocal中初始化

6、典型應用

           一個執行緒只允許一個Looper。為保證只有一個Looper採用ThreadLocal原理,在Looper的prepare函式中

if sThreadLocal.get() != null

     throw一個執行緒只能有一個Looper

sThreadLocal.set(new Looper(quitAllowed));

十四、記憶體洩漏

1、靜態變數(比如單例類)持有Activity的引用,例如Context或者介面。

   解決方案:介面在OnDestroy時remove掉,Context傳遞ApplicationContext

2、a、Activity內部類Handler、Runnable和AsyncTask對Activity的隱式引用,Activity銷燬之後,任務沒完成。

           解決方案:a、在onDestroy中用Handler.removeAllCallbackAndMessage

                                b、Handler定義為靜態內部類,靜態內部類不會持有外部類的引用。配合使用WeakReference解決

                                  c、典型的:Volley在Activity中使用,Response回撥Listener採用靜態內部類和WeakReference使用Activity

3、資源未關閉:BroadcastReceiver、ContentObserver、File、Cursor、Stream和Bitmap;Bitmap.recylce()並置為null

4、靜態內部類中引用外部類變數(如Context、View)時採用弱引用

5、不需要的物件,賦值為null

6、持久化Drawable,定義成static,4.0之前持有View,View持有Activity

十五、AsyncTask

           15.1、使用準則:

                     1、必須在UI執行緒建立,execute必須在UI執行緒中執行

                     2、不能手動呼叫onPreExecute、doInBackground、onPostExecute、onProgressUpdate

                     3、只能執行一次;因為多個子執行緒同時執行造成執行緒不同步,狀態不一致

           15.2、存在的問題

             1、AsyncTask所在的Activity終止,AsyncTask不會終止;

                    2、在沒有不可中斷操作比如BitmapFactory.decodeStream的,重寫onCancel對socket、file進行關閉。並在Activity的onDestroy可呼叫AsyncTask.cancel終止

             3、AsyncTask如果是非靜態內部類,依照非靜態內部類會持有外部類的引用,由於宣告週期問題,可能會造成洩漏;

             4、1.6之前序列;1.6到2.3並行;2.3以後execute序列,executeOnExecutor執行並行自定義的執行器

             5、AsyncTask內部用弱引用持有Activity

             6、橫豎屏切換,Activity重建,Activity引用失效,onPostExecute重新整理介面會失效。解決方法:在Activity的onRetainNonConfigurationInstance中重新傳一個物件給AsyncTask

   15.3、Android 3.0之後

   1、execute只有一個執行緒執行排隊任務,對應執行緒池Executors.newSingleThreadPool。也就是AsyncTask預定義的SERIAL_EXECUTOR

2、executeOnExecutor可以自定義執行緒池執行任務。執行無數個就用java執行緒池的Executors.newCachedThreadPool。AsyncTask預設定義了THREAD_POOL_EXECUTOR,就是Executors.newFixedThreadPool(5),最多隻能5個執行緒。

十四、效能優化

14.1、佈局優化

  1、使用ViewStub、merge和include

  2、overdraw,GPU選項觀察overdraw的情況

  3、ondraw不要new物件,不能耗時,60fps, 16ms繪製幀,GPU加速

  4、避免記憶體洩漏

  5、ListView:a、使用Holder;b、分頁載入;c、滑動停止後在載入圖片、

  6、Bitmap載入:用LRUBitmap,記憶體加硬碟快取

  7、必要的時候使用SurfaceView

 14.2、效能優化

           1、上述佈局優化

           2、使用ArrayMap和SparseArray替代HashMap

           3、少用列舉,多用static訪問塊

十四、ListView非同步載入圖片錯位原理與解決方法

14.1、  非同步載入圖片錯位原因

1、 同步載入不會出現圖片錯位

2、非同步載入圖片出現錯位

ListView一整屏顯示7個item,當向下滑動時,顯示出item8.由於RecycleBin機制,item8重用item1。如果非同步網路請求item8的圖片比item1慢,item8會顯示item1的圖片,當item8圖片下載完成,此時向上滑動顯示item1,item1會顯示item8的圖片。

14.2、 解決方案:對ImageView設定tag為圖片URL,並設定預設圖。等非同步請求載入完比較Image的tag與請求的URL是否匹配

十四、ListView和RecyclerView

  14.1、使用的對比

     1、ListView使用時:

      a、要繼承重寫BaseAdapter

      b、自定義類ViewHolder,配合convertView一起完成複用優化

     2、RecyclerView使用時

      a、要繼承RecyclerView.Adapter

      b、繼承RecyclerView.ViewHolder

      c、設定佈局管理器

        LinearLayoutManager linearLayoutManager= new LinearLayout(activity);

        mRecyclerView.setLayoutManager(linearLayoutManager);

   14.2、區域性重新整理

      1、ListView呼叫Adapter.notifyDataSetChanged會重繪每個item

      2、RecyclerView.Adapter提供notifyItemChanged(int

postion)重新整理單個item

   14.3、HeaderView和FooterView對position的影響

      1、ListView會將HeaderView和FooterView計算到position中,對setOnItemClickListener會有影響

    2、RecyclerView只有addOnItemTouchListener

十五、OOM情景和解決方案

1、原因:a、載入物件過大;b、相應資源過多,來不及釋放;c、Adapter沒有使用快取的convertView。e、Android虛擬機器Dalvik,最大堆大小為16M,有的機器為24M。

2、解決方案:關閉資源;引用方面處理;載入圖片預壓縮;堆記憶體自定義大小和優化Dalvik虛擬機器對記憶體分配

PS:Dalvik虛擬機器堆記憶體分配優化setTargetHeapUtilization;自定義堆記憶體大小setMinimumHeapSize

十五、效能分析新方法

利用Looper的setMessageLogging方法,Looper.getMainLooper

十六、AndroidManifest中對Android:process屬性設定的兩種形式:

1、以冒號開頭,android:process

= ":remote",該程序是私有程序,其他應用的元件不可以和它跑在同一個程序中。

2、以.或者以包名.remote開頭,全域性程序,其他應用可以設定相同的ShareUID和它泡在同一個程序

十七、多程序面臨4個問題

a、Application多次重建;b、靜態成員失效;c、檔案共享問題;d、斷點除錯問題。

十八、java序列化

18.1、序列化:將物件轉換為位元組流序列,目的:a、永久儲存到硬碟上;b、網路上傳送

18.2、序列化的要求:實現Serializable或Externalizable介面的物件;

18.3、用到的api:ObjectOutputStream、ObjecInputStream;writeObject、readObject;

18.4、序列化的使用原則:物件的序列化

           a、序列化不會儲存靜態變數,因為序列化儲存的是物件的狀態,靜態變數屬於類的狀態

           b、父類沒有實現序列化介面Serializable,子類實現了。序列化時基類物件不會序列化,基類的屬性不會序列化,反序列化時通過無參建構函式構建基類物件

          c、父類實現序列化,子類沒有。基類改變,序列化ID不會改變

           e、外部類不序列化,非靜態內部類、匿名內部類、本地類不能序列化,因為這些內部類中有個變數,這個變數指向外部類物件this,序列化要求物件中所有的物件屬性也要序列化。

           f、外部類序列化,內部類必須序列化

           g、靜態內部類不管外部類有沒有實現序列化,都可以序列化

           h、List、Map容器中的泛型型別必須實現序列化介面Serializable,否則會報NotSerializableException錯誤