月薪20+的Android面試都問這些問題系列一(含答案)
金三銀四跳槽季,相信大家肯定急需一套Android面試寶典,今天給大家準備了我珍藏已久的Android高階面試寶典,供大家學習 !【文末有乾貨】

一、面試題:
1.自定義Handler時如何避免記憶體洩漏
2.onNewIntent的呼叫時機
3.RecyclerView相比ListView有哪些優勢
4.談一談Proguard混淆技術
5.ANR出現的場景及解決方案
二、詳細解析:
1.自定義Handler時如何避免記憶體洩漏
一般非靜態內部類持有外部類的引用的情況下,造成外部類在使用完成後不能被系統回收記憶體,從而造成記憶體洩漏。為了避免這個問題,我們可以自定義的Handler宣告為靜態內部類形式,然後通過弱引用的方式,讓Handler持有外部類的引用,從而可避免記憶體洩漏問題。
以下是程式碼實現
private WeakReference<MainActivity> activityWeakReference; private MyHandler myHandler; static class MyHandler extends Handler { private MainActivity activity; MyHandler(WeakReference<MainActivity> ref) { this.activity = ref.get; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //需要做判空操作 if (activity != ) { activity.mTextView.setText("new Value"); } break; default: Log.i(TAG, "handleMessage: default "); break; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //在onCreate中初始化 activityWeakReference = new WeakReference<MainActivity>(this); myHandler = new MyHandler(activityWeakReference); myHandler.sendEmptyMessage(1); mTextView = (TextView) findViewById(R.id.tv_test); }
2.onNewIntent的呼叫時機
在Android應用程式開發的時候,從一個Activity啟動另一個Activity並傳遞一些資料到新的Activity上非常簡單,但是當您需要讓後臺執行的Activity回到前臺並傳遞一些資料可能就會存在一點點小問題。
首先,在預設情況下,當您通過Intent啟到一個Activity的時候,就算已經存在一個相同的正在執行的Activity,系統都會建立一個新的Activity例項並顯示出來。為了不讓Activity例項化多次,我們需要通過在AndroidManifest.xml配置activity的載入方式(launchMode)以實現單任務模式,如下所示:
<activity android:label="@string/app_name" android:launchmode="singleTask"android:name="Activity1"> </activity>
launchMode為singleTask的時候,通過Intent啟到一個Activity,如果系統已經存在一個例項,系統就會將請求傳送到這個例項上,但這個時候,系統就不會再呼叫通常情況下我們處理請求資料的onCreate方法,而是呼叫onNewIntent方法
前提:ActivityA已經啟動過,處於當前應用的Activity堆疊中;當ActivityA的LaunchMode為SingleTop時,如果ActivityA在棧頂,且現在要再啟動ActivityA,這時會呼叫onNewIntent方法
當ActivityA的LaunchMode為SingleInstance,SingleTask時,如果已經ActivityA已經在堆疊中,那麼此時會呼叫onNewIntent方法
當ActivityA的LaunchMode為Standard時,由於每次啟動ActivityA都是啟動新的例項,和原來啟動的沒關係,所以不會呼叫原來ActivityA的onNewIntent方法,仍然呼叫的是onCreate方法
以下是程式碼例項
- 設定MainActivity的啟動模式為SingleTask(棧內複用)
<activity android:name=".MainActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
- MainActivity中重寫onNewIntent方法
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.forward_btn); mButton.setOnClickListener(new View.OnClickListener { @Override public void onClick(View view) { startActivity(new Intent(MainActivity.this, Main2Activity.class)); } }); @Override protected void onNewIntent(Intent intent) { Toast.makeText(this, "onnewIntent", Toast.LENGTH_SHORT).show; Log.i(TAG, "onNewIntent: i done...."); }
- Main2Actvity執行點選跳轉,MainActivity被複用,執行onNewIntent方法
public class Main2Activity extends AppCompatActivity { private Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); mButton = (Button)findViewById(R.id.btn); mButton.setOnClickListener(new View.OnClickListener { @Override public void onClick(View view) { startActivity(new Intent(Main2Activity.this,MainActivity.class)); finish; } });
3.RecyclerView相比ListView有哪些優勢
首先需要解釋下RecyclerView的這個名字了,從它類名上看,RecyclerView代表的意義是,我只管Recycler View,也就是說RecyclerView只管回收與複用View,其他的你可以自己去設定。可以看出其高度的解耦,給予你充分的定製自由(所以你才可以輕鬆的通過這個控制元件實現ListView,GirdView,瀑布流等效果)
其次RecyclerView提供了新增、刪除item的動畫 效果,而且可以自定義
RecyclerView相比ListView優勢在於可以輕鬆實現:
- ListView的功能
- GridView的功能
- 橫向ListView的功能
- 橫向ScrollView的功能
- 瀑布流效果
- 便於新增Item增加和移除動畫
不過一個挺鬱悶的地方就是,系統沒有提供ClickListener和LongClickListener。
不過我們也可以自己去新增,只是會多了些程式碼而已。
實現的方式比較多,你可以通過mRecyclerView.addOnItemTouchListener去監聽然後去判斷手勢,
當然你也可以通過adapter中自己去提供回撥

Proguard技術有如下功能:
- 壓縮 --檢查並移除程式碼中無用的類
- 優化--對位元組碼的優化,移除無用的位元組碼
- 混淆--混淆定義的名稱,避免反編譯
- 預監測--在java平臺對處理後的程式碼再次進行檢測
程式碼混淆只在上線時才會用到,debug模式下會關閉,是一種可選的技術。
那麼為什麼要使用程式碼混淆呢?
因為Java是一種跨平臺的解釋性開發語言,而java的原始碼會被編譯成位元組碼檔案,儲存在.class檔案中,由於跨平臺的需要,java的位元組碼中包含了很多原始碼資訊,諸如變數名、方法名等等。並且通過這些名稱來訪問變數和方法,這些變數很多是無意義的,但是又很容易反編譯成java原始碼,為了防止這種現象,我們就需要通過proguard來對java的位元組碼進行混淆,混淆就是對釋出的程式進行重新組織和處理,使得處理後的程式碼與處理前的程式碼有相同的功能,和不同的程式碼展示,即使被反編譯也很難讀懂程式碼的含義,哪些混淆過的程式碼仍能按照之前的邏輯執行得到一樣的結果。
但是,某些java類是不能被混淆的,比如實現了序列化的java類是不能被混淆的,否則反序列化時會出問題。
下面這類程式碼混淆的時候要注意保留,不能混淆。
- Android系統元件,系統元件有固定的方法被系統呼叫。
- 被Android Resource 檔案引用到的。名字已經固定,也不能混淆,比如自定義的View 。
- Android Parcelable ,需要使用android 序列化的。
其他Anroid 官方建議 不混淆的,如
- android.app.backup.BackupAgentHelper
- android.preference.Preference
- com.android.vending.licensing.ILicensingService
- Java序列化方法,系統序列化需要固定的方法。
- 列舉 ,系統需要處理列舉的固定方法。
- 本地方法,不能修改本地方法名
- annotations 註釋
- 資料庫驅動
- 有些resource 檔案
5.ANR出現的場景及解決方案
在Android中,應用的響應性被活動管理器(Activity Manager)和視窗管理器(Window Manager)這兩個系統服務所監視。當用戶觸發了輸入事件(如鍵盤輸入,點選按鈕等),如果應用5秒內沒有響應使用者的輸入事件,那麼,Android會認為該應用無響應,便彈出ANR對話方塊。而彈出ANR異常,也主要是為了提升使用者體驗。
解決方案是對於耗時的操作,比如訪問網路、訪問資料庫等操作,需要開闢子執行緒,在子執行緒處理耗時的操作,主執行緒主要實現UI的操作

這些是小編根據上面的高階工程師技術大綱整理的一套系統全面而且非常深入的Android進階資料

高階進階技術大綱

Android系統進階資料
這些資料都可以免費分享給大家!QQ群:【Android技術開發交流②】979045005: https://jq.qq.com/?_wv=1027&k=5gc0B9E
歡迎大家進群,領取資料,一起學習交流!
命運永遠會眷顧那些努力付出的人。如果你還沒達到你的目標,那是因為你努力的程度還不夠!
希望看到最後的朋友們,通過一年到兩年的努力,都能實現追求的目標。