本文列舉了Android常見高級面試題和答案解析。希望能夠幫助到即將准備面試的Android開發朋友!
1.如何對 Android 應用進行性能分析
android 性能主要之響應速度 和UI刷新速度。
可以參考博客:Android系統性能調優工具介紹
首先從函數的耗時來說,有一個工具TraceView 這是androidsdk自帶的工作,用於測量函數耗時的。
UI布局的分析,可以有2塊,一塊就是Hierarchy Viewer 可以看到View的布局層次,以及每個View刷新加載的時間。
這樣可以很快定位到那塊layout & View 耗時最長。
還有就是通過自定義View來減少view的層次。
2.什么情況下會導致內存泄露
內存泄露是個折騰的問題。
什么時候會發生內存泄露?內存泄露的根本原因:長生命周期的對象持有短生命周期的對象。短周期對象就無法及時釋放。
I. 靜態集合類引起內存泄露
主要是hashmap,Vector等,如果是靜態集合 這些集合沒有及時setnull的話,就會一直持有這些對象。
II.remove 方法無法刪除set集 Objects.hash(firstName, lastName);
經過測試,hashcode修改后,就沒有辦法remove了。
III. observer 我們在使用監聽器的時候,往往是addxxxlistener,但是當我們不需要的時候,忘記removexxxlistener,就容易內存leak。
廣播沒有unregisterrecevier
IV.各種數據鏈接沒有關閉,數據庫contentprovider,io,sokect等。cursor
V.內部類:
java中的內部類(匿名內部類),會持有宿主類的強引用this。
所以如果是new Thread這種,后台線程的操作,當線程沒有執行結束時,activity不會被回收。
Context的引用,當TextView 等等都會持有上下文的引用。如果有static drawable,就會導致該內存無法釋放。
VI.單例
單例 是一個全局的靜態對象,當持有某個復制的類A是,A無法被釋放,內存leak。
3.如何避免 OOM 異常
首先OOM是什么?
當程序需要申請一段“大”內存,但是虛擬機沒有辦法及時的給到,即使做了GC操作以后
這就會拋出 OutOfMemoryException 也就是OOM
Android的OOM怎么樣?
為了減少單個APP對整個系統的影響,android為每個app設置了一個內存上限。
public void getMemoryLimited(Activity context)
{
ActivityManager activityManager =(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
System.out.println(activityManager.getMemoryClass());
System.out.println(activityManager.getLargeMemoryClass());
System.out.println(Runtime.getRuntime().maxMemory()/(1024*1024));
}
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 192
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 512
09-10 10:20:00.477 4153-4153/com.joyfulmath.samples I/System.out: 192
HTC M7實測,192M上限。512M 一般情況下,192M就是上限,但是由於某些特殊情況,android允許使用一個更大的RAM。
如何避免OOM
減少內存對象的占用
I.ArrayMap/SparseArray代替hashmap
II.避免在android里面使用Enum
III.減少bitmap的內存占用
- inSampleSize:縮放比例,在把圖片載入內存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。
- decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異。
IV.減少資源圖片的大小,過大的圖片可以考慮分段加載
內存對象的重復利用
大多數對象的復用,都是利用對象池的技術。
I.listview/gridview/recycleview contentview的復用
II.inBitmap 屬性對於內存對象的復用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8
這個方法在某些條件下非常有用,比如要加載上千張圖片的時候。
III.避免在ondraw方法里面 new對象
IV.StringBuilder 代替+
4.Android 中如何捕獲未捕獲的異常
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static CrashHandler instance = null;
public static synchronized CrashHandler getInstance()
{
if(instance == null)
{
instance = new CrashHandler();
}
return instance;
}
public void init(Context context)
{
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Thread:");
stringBuilder.append(thread.toString());
stringBuilder.append("\t");
stringBuilder.append(ex);
TraceLog.i(stringBuilder.toString());
TraceLog.printCallStatck(ex);
}
}
關鍵是實現Thread.UncaughtExceptionHandler
然后是在application的oncreate里面注冊。
5.ANR 是什么?怎樣避免和解決 ANR(重要)
ANR->Application Not Responding
也就是在規定的時間內,沒有響應。
三種類型:
1). KeyDispatchTimeout(5 seconds) --主要類型按鍵或觸摸事件在特定時間內無響應
2). BroadcastTimeout(10 seconds) --BroadcastReceiver在特定時間內無法處理完成
3). ServiceTimeout(20 seconds) --小概率類型 Service在特定的時間內無法處理完成
為什么會超時:事件沒有機會處理 & 事件處理超時
怎么避免ANR
ANR的關鍵
是處理超時,所以應該避免在UI線程,BroadcastReceiver 還有service主線程中,處理復雜的邏輯和計算
而交給work thread操作。
1)避免在activity里面做耗時操作,oncreate & onresume
2)避免在onReceiver里面做過多操作
3)避免在Intent Receiver里啟動一個Activity,因為它會創建一個新的畫面,並從當前用戶正在運行的程序上搶奪焦點。
4)盡量使用handler來處理UI thread & workthread的交互。
如何解決ANR
首先定位ANR發生的log:
<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;">04-01 13:12:11.572 I/InputDispatcher( 220): Application i****s not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}. 5009.8ms since event, 5009.5ms since waitstarted</pre>
<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;">CPUusage from 4361ms to 699ms ago ----CPU在ANR發生前的使用情況 04-0113:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait 04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量</pre>
從log可以看出,cpu在做大量的io操作。
所以可以查看io操作的地方。
當然,也有可能cpu占用不高,那就是 主線程被block住了。
6.Android 線程間通信有哪幾種方式
1)共享變量(內存)
2)管道
3)handle機制
runOnUiThread(Runnable)
view.post(Runnable)
7.Devik 進程,linux 進程,線程的區別
Dalvik進程。
每一個android app都會獨立占用一個dvm虛擬機,運行在linux系統中。
所以dalvik進程和linux進程是可以理解為一個概念。
8.描述一下 android 的系統架構
從小到上就是:
linux kernel,lib dalvik vm ,application framework, app
9.android 應用對內存是如何限制的?我們應該如何合理使用內存?
activitymanager.getMemoryClass() 獲取內存限制。
關於合理使用內存,其實就是避免OOM & 內存泄露中已經說明。
10. 簡述 android 應用程序結構是哪些
1)main code
- unit test
3)mianifest
4)res->drawable,drawable-xxhdpi,layout,value,mipmap
mipmap 是一種很早就有的技術了,翻譯過來就是紋理映射技術.
google建議只把啟動圖片放入。
5)lib
6)color
11.請解釋下 Android 程序運行時權限與文件系統權限的區別
文件的系統權限是由linux系統規定的,只讀,讀寫等。
運行時權限,是對於某個系統上的app的訪問權限,允許,拒絕,詢問。該功能可以防止非法的程序訪問敏感的信息。
12.Framework 工作方式及原理,Activity 是如何生成一個 view 的,機制是什么
Framework是android 系統對 linux kernel,lib庫等封裝,提供WMS,AMS,bind機制,handler-message機制等方式,供app使用。
簡單來說framework就是提供app生存的環境。
1)Activity在attch方法的時候,會創建一個phonewindow(window的子類)
2)onCreate中的setContentView方法,會創建DecorView
3)DecorView 的addview方法,會把layout中的布局加載進來。
13.多線程間通信和多進程之間通信有什么不同,分別怎么實現
線程間的通信可以參考第6點。
進程間的通信:bind機制(IPC->AIDL),linux級共享內存,boradcast,
Activity 之間,activity & serview之間的通信,無論他們是否在一個進程內。
14.Android 屏幕適配
屏幕適配的方式:xxxdpi, wrap_content,match_parent. 獲取屏幕大小,做處理。
dp來適配屏幕,sp來確定字體大小
drawable-xxdpi, values-1280*1920等 這些就是資源的適配。
wrap_content,match_parent, 這些是view的自適應
weight,這是權重的適配。
15.什么是 AIDL 以及如何使用
Android Interface Definition Language
AIDL是使用bind機制來工作。
參數:
java原生參數
String
parcelable
list & map 元素 需要支持AIDL
16.Handler 機制
參考:android 進程/線程管理(一)----消息機制的框架 這個系類。
17.事件分發機制
18.子線程發消息到主線程進行更新 UI,除了 handler 和 AsyncTask,還有什么
EventBus,廣播,view.post, runinUiThread
但是無論各種花樣,本質上就2種:handler機制 + 廣播
19.子線程中能不能 new handler?為什么
必須可以。子線程 可以new 一個mainHandler,然后發送消息到UI Thread。
20.Android 中的動畫有哪幾類,它們的特點和區別是什么
視圖動畫,或者說補間動畫。只是視覺上的一個效果,實際view屬性沒有變化,性能好,但是支持方式少。
屬性動畫,通過變化屬性來達到動畫的效果,性能略差,支持點擊等事件。android 3.0
幀動畫,通過drawable一幀幀畫出來。
Gif動畫,原理同上,canvas畫出來。
具體可參考:https://i.cnblogs.com/posts?categoryid=672052
21. ThreadLocal的理解
可以保證線程的安全。在多個線程共享相同的數據的時候,會為每個線程創建單獨的副本,在單獨的副本上進行數據的操作,不會對其它線程的數據產生影響,保證了線程安全。
22. HashMap HashSet HashTable的區別?
都是集合,底層都是Hash算法實現的。HashMap是Hashtable的替代品,這兩個都是雙列集合,而HashSet是單列集合。HashMap線程不安全、效率高、可以存儲null鍵和null值;Hashtable線程安全,效率低,不可以存儲null鍵和null值。
23. 如何讓HashMap可以線程安全?
HashMap 在並發執行 put 操作時會引起死循環,導致 CPU 利用率接近100%。因為多線程會導致 HashMap 的 Node 鏈表形成環形數據結構,一旦形成環形數據結構,Node 的 next 節點永遠不為空,就會在獲取 Node 時產生死循環。
使用下面三種替換方式:
Hashtable
ConcurrentHashMap
Synchronized Map
24. Android對HashMap做了優化后推出的新的容器類是什么?
SparseArray
它要比 HashMap 節省內存,某些情況下比HashMap性能更好,按照官方問答的解釋,主要是因為SparseArray不需要對key和value進行auto-boxing(將原始類型封裝為對象類型,比如把int類型封裝成Integer類型),結構比HashMap簡單(SparseArray內部主要使用兩個一維數組來保存數據,一個用來存key,一個用來存value)不需要額外的額外的數據結構(主要是針對HashMap中的HashMapEntry而言的)。
25. Java多線程之間如何通信
等待喚醒機制
26. 線程池的實現機制
向線程池提交任務,會依次啟動核心線程,如果提交的任務數超過了核心線程數,會將任務保存到阻塞隊列中,如果阻塞隊列也滿了,且繼續提交任務,則會創建新線程執行任務,直到任務數達到最大線程數。此時如果再提交任務的話會拋出異常或者直接丟棄任務。通過Executor.execute()無法得到返回值,通過ExecutorService.submit()可以得到返回值。
27. RxJava中map和flatmap操作符的區別及底層實現
Map返回的是結果集,flatmap返回的是包含結果集的Observable。Map只能一對一,flatmap可以一對多、多對多。
RxJava是通過觀察者模式實現的。
28. 對消息機制中Looper的理解
Looper在消息機制中扮演的角色是創造無限循環從Messagequeue中取得消息然后分發。
29. 單例模式有哪些實現方式
餓漢模式(線程安全,調用效率高,但是不能延時加載)
懶漢模式(線程安全,調用效率不高,但是能延時加載)
雙重檢測鎖模式(由於JVM底層模型原因,偶爾會出問題,不建議使用)
靜態內部類式(線程安全,調用效率高,可以延時加載)
枚舉類(線程安全,調用效率高,不能延時加載,可以天然的防止反射和反序列化調用)
30. 通過靜態內部類實現單例模式有哪些優點
線程安全,調用效率高,可以延時加載
31. synchronized volatile關鍵字有什么區別?以及還有哪些同樣功能的關鍵字
(1) volatile是變量修飾符,而synchronized則作用於一段代碼或者方法。
(2) volatile只是在線程內存和main memory(主內存)間同步某個變量的值;而synchronized通過鎖定和解鎖某個監視器同步所有變量的值。顯然synchronized要比volatile消耗更多資源。
const、final、lock
32. 界面卡頓的原因有哪些?
UI線程(main)有耗時操作
視圖渲染時間過長,導致卡頓
33. 造成OOM/ANR 的原因?
OOM: (1)不恰當地使用static關鍵字 (2)內部類對Activity的引用 (3)大量Bitmap的使用會導致程序包運行時的內存消耗變大 (4)游標Cursor對象用完應該及時關閉 (5)加載對象過大 (6)相應資源過多,來不及釋放。
ANR: (1)在5秒內沒有響應輸入的事件(IO操作耗時、數據庫操作復雜耗時、主線程非主線程產生死鎖等待、網絡加載/圖片操作耗時、硬件操作耗時) (2)BroadcastReceiver在10秒內沒有執行完畢(Service binder數量達到上限、Service忙導致超時無響應)
34. Activity與Fragment生命周期有何聯系
在創建的過程中,是Activity帶領着Fragment,在銷毀的過程中,是Fragment帶領着Activity。
2
35. Glide三級緩存
內存緩存,磁盤緩存、網絡緩存(由於網絡緩存嚴格來說不算是緩存的一種,故也稱為二級緩存)。緩存的資源分為兩種:原圖(SOURCE)、處理圖(RESULT)(默認)。
內存緩存:默認開啟的,可以通過調用skipMemoryCache(true)來設置跳過內存緩存,緩存最大空間:每個進程可用的最大內存*0.4。(低配手機0.33)
磁盤緩存:分為四種:ALL(緩存原圖)、NONE(什么都不緩存)、SOURCE(只緩存原圖)、RESULT(之后處理圖),通過diskCacheStrategy(DiskCacheStrategy.ALL)來設置,緩存大小250M。
36. MVC、MVP、MVVM的原理
(1) MVC,Model View Controller,是軟件架構中最常見的一種框架,簡單來說就是通過controller的控制去操作model層的數據,並且返回給view層展示。當用戶發出事件的時候,view層會發送指令到controller層,接着controller去通知model層更新數據,model層更新完數據以后直接顯示在view層上,這就是MVC的工作原理。
[圖片上傳失敗...(image-57b724-1597645043702)]
(2) MVP是MVC的演化。MVP的model層相對於MVC是一樣的,而activity和fragment不再是controller層,而是純粹的view層,所有關於用戶事件的轉發全部交由presenter層處理。presenter層充當了橋梁的作用,用於操作view層發出的事件傳遞到presenter層中,presenter層去操作model層,並且將數據返回給view層。
[圖片上傳失敗...(image-65a59e-1597645043702)]
(3) MVVM和MVP的區別貌似不大,只不過是presenter層換成了viewmodel層,還有一點就是view層和viewmodel層是相互綁定的關系,這意味着當你更新viewmodel層的數據的時候,view層會相應的變動ui。
這里寫圖片描述
37. 數據庫的操作類型有哪些,如何導入外部數據庫?
(1) 增刪改查
(2) 將外部數據庫放在項目的res/raw目錄下。因為安卓系統下數據庫要放在data/data/packagename/databases的目錄下,然后要做的就是將外部數據庫導入到該目錄下,操作方法是通過FileInputStream讀取外部數據庫,再用FileOutputStrean把讀取到的東西寫入到該目錄下。
38. 是否使用過 IntentService,作用是什么, AIDL 解決了什么問題?
(1) IntentService繼承自Service。由於Service運行在主線程,無法進行耗時操作。所以你需要在Service中開啟一個子線程,並且在子線程中運行。為了簡化這一操作,Android中提供了IntentService來進行這一處理。通過查看IntentService的源碼可以看到,在onCreate中,我們開啟了一個HandlerThread線程,之后獲取HandlerThread線程中的Looper,並通過這個Looper創建了一個Handler。然后在onStart方法中通過這個Handler將intent與startId作為Message的參數進行發送到消息隊列中,然后交由Handler中的handleMessage中進行處理。由於在onStart方法是在主線程內運行的,而Handler是通過工作者線程HandlerThread中的Looper創建的。所以也就是在主線程中發送消息,在工作者接收到消息后便可以進行一些耗時的操作。
(2) 進程間通信
39. 是否使用過本地廣播,和全局廣播有什么差別?
本地廣播的數據在本應用范圍內傳播,不用擔心隱私數據泄露的問題。不用擔心別的應用偽造廣播,造成安全隱患。相比在系統內發送全局廣播,它更高效。
40. Activity、 Window、 View 三者的差別, fragment 的特點?
(1) Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示視圖) LayoutInflater像剪刀,Xml配置像窗花圖紙。
(2) a. Fragment可以作為Activity界面的一部分組成出現;
b. 可以在一個Activity中同時出現多個Fragment,並且一個Fragment也可以在多個Activity中使用;
c. 在Activity運行過程中,可以添加、移除或者替換Fragment;
d. Fragment可以響應自己的輸入事件,並且有自己的生命周期,它們的生命周期會受宿主Activity的生命周期影響。
41. Handler、 Thread 和 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。
42. 低版本 SDK 實現高版本 api
自己實現或使用注解@TargetApi annotation
43. launch mode 應用場景
(1) standard:標准的啟動模式。
這里寫圖片描述
(2) singleTop:單一頂部模式
如果Activity已經被開啟,並且處於任務棧的棧頂,就不會創建新的Activity,而是復用這個已經開啟的Activity。
為了防止出現一些奇怪的用戶體驗,推薦使用單一頂部模式,整個任務棧可以有多個實例存在.
應用場景:短信發送界面.
這里寫圖片描述
(3)singletask:單一任務棧
在整個任務棧里面只允許有一個當前Activity的實例存在
如果要開啟的Activity在任務棧中已經存在,直接復用這個已經存在的Activity,並且把這個Activity上面的所有的其他Activity給清空
應用場景:如果一個Activity非常消耗內存和cpu資源,建議把這個Activity做成singletask的模式。瀏覽器的browserActivity
這里寫圖片描述
(4)singleinstance:單一實例.
整個手機操作系統只有一個實例存在,並且是運行在自己單獨的任務棧里面.
應用場景:通話界面的Activity
這里寫圖片描述
44. touch 事件傳遞流程
事件處理包括三種情況,分別為:傳遞—-dispatchTouchEvent()函數、攔截——onInterceptTouchEvent()函數、消費—-onTouchEvent()函數和OnTouchListener。
Android事件傳遞流程:
(1) 事件都是從Activity.dispatchTouchEvent()開始傳遞
(2) 事件由父View傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()方法對事件攔截,停止其向子view傳遞
(3) 如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最后會到Activity的onTouchEvent()函數。
(4) 如果View沒有對ACTION_DOWN進行消費,之后的其他事件不會傳遞過來,也就是說ACTION_DOWN必須返回true,之后的事件才會傳遞進來
(5) OnTouchListener優先於onTouchEvent()對事件進行消費
View不處理事件流程圖
View不處理事件流程圖
View處理事件流程圖
View處理事件流程圖
事件攔截
事件攔截
45.Android性能優化
一、代碼優化
1.使用AndroidLint分析結果進行相應優化
2.不使用枚舉及IOC框架,反射性能低
3.常量加static
4.靜態方法
5.減少不必要的對象、成員變量
6.盡量使用線程池
7.適當使用軟引用和弱引用
8.盡量使用靜態內部類,避免潛在的內存泄露
9.圖片緩存,采用內存緩存LRUCache和硬盤緩存DiskLRUCache
10.Bitmap優化,采用適當分辨率大小並及時回收
二、布局優化
避免OverDraw過渡繪制
優化布局層級
避免嵌套過多無用布局
當我們在畫布局的時候,如果能實現相同的功能,優先考慮相對布局,然后在考慮別的布局,不要用絕對布局。
使用標簽把復雜的界面需要抽取出來
使用標簽,因為它在優化UI結構時起到很重要的作用。目的是通過刪減多余或者額外的層級,從而優化整個Android Layout的結構。核心功能就是減少冗余的層次從而達到優化UI的目的!
ViewStub 是一個隱藏的,不占用內存空間的視圖對象,它可以在運行時延遲加載布局資源文件。
三、ListView和GridView優化
1.采用ViewHolder復用convertView
2.避免在getView中執行耗時操作
3.列表在滑動狀態時不加載圖片
4.開啟硬件加速
由於文章內容比較多,篇幅不允許,面試題僅展示一小部分,筆者還搜集整理了華為、騰訊、字節跳動、百度、阿里巴巴、美團等今年最新面試題以及19年大廠面試題都已經整理好做成了16份精美的PDF 。如有需要獲取完整面試文檔的朋友可以直接點擊我的 GitHub免費獲取。
1、華為面試題
image
2、騰訊面試題
總結
世上沒有舒舒服服的進步,無論我們定義成功的方式怎樣,升職漲薪獲得offer也罷,成長之路都很痛苦,但最終還是苦盡甘來,如願轉正華為。如果堅持下來,那你一定能讓你的女朋友坐在寶馬車上哭,你也能更“輕松”的討一口飯恰!
推薦閱讀
史上最全的Android面試題集錦
Android基本知識點1、常規知識點1、 Android類加載器在Android開發中,不管是插件化還是組件化,都是基於Android系統的類加載器ClassLoader來設計的。只不過Android平台上虛擬機運行的是Dex…
Android面試匯總(持續更新)
作為一個2年經驗用了5年的android開發,最近面試受了不少打擊,在這漫漫整理一些面試題,和相應的學習。 1.JVM(Android開發為什么要學這個,好吧,反正有人問這類相關的,就一起准備了) …
Android面試筆試總結(Android精心整理篇)

1 條評論
總結歸納的不錯,為啥沒人評論,😄