本文列舉了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

  1. 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.事件分發機制

android 事件分發機制

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畫出來。

具體可參考:

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也罷,成長之路都很痛苦,但最終還是苦盡甘來,如願轉正華為。如果堅持下來,那你一定能讓你的女朋友坐在寶馬車上哭,你也能更“輕松”的討一口飯恰!

發布於 2020-10-23
Android
性能優化
Activity
 

推薦閱讀

史上最全的Android面試題集錦

Android基本知識點1、常規知識點1、 Android類加載器在Android開發中,不管是插件化還是組件化,都是基於Android系統的類加載器ClassLoader來設計的。只不過Android平台上虛擬機運行的是Dex…

Android面試匯總(持續更新)

作為一個2年經驗用了5年的android開發,最近面試受了不少打擊,在這漫漫整理一些面試題,和相應的學習。 1.JVM(Android開發為什么要學這個,好吧,反正有人問這類相關的,就一起准備了) …

Android面試筆試總結(Android精心整理篇)

Android面試筆試總結(Android精心整理篇)

Android中高級面試題持續助攻:圖解Android Binder機制

Android中高級面試題持續助攻:圖解Android Binder機制

1 條評論

  • cwwei
    cwwei2020-11-17

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