1.Activity生命週期(這個是必問的)
onCreate():表示Activity正在被創建,常用來初始化工作,比如調用setContentView加載界面佈局資源,初始化Activity所需數據等;
onStart():表示Activity正在被啓動,此時Activity可見但不在前臺,還處於後臺,無法與用戶交互;
onResume():表示Activity獲得焦點,此時Activity可見且在前臺並開始活動,這是與onStart的區別所在;
onPause():表示Activity正在停止,此時可做一些存儲數據、停止動畫等工作,但是不能太耗時,因爲這會影響到新Activity的顯示,onPause必須先執行完,新Activity的onResume纔會執行;
onStop():表示Activity即將停止,可以做一些稍微重量級的回收工作,比如註銷廣播接收器、關閉網絡連接等,同樣不能太耗時;
onRestart():表示Activity正在重新啓動,一般情況下,當前Acitivty從不可見重新變爲可見時,OnRestart就會被調用;
onDestroy():表示Activity即將被銷燬,這是Activity生命週期中的最後一個回調,常做回收工作、資源釋放;
2.說下 Activity的四種啓動模式、應用場景 ?
standard標準模式:每次啓動一個Activity都會重新創建一個新的實例,不管這個實例是否已經存在,此模式的Activity默認會進入啓動它的Activity所屬的任務棧中;
singleTop棧頂複用模式:如果新Activity已經位於任務棧的棧頂,那麼此Activity不會被重新創建,同時會回調onNewIntent方法,如果新Activity實例已經存在但不在棧頂,那麼Activity依然會被重新創建;
singleTask棧內複用模式:只要Activity在一個任務棧中存在,那麼多次啓動此Activity都不會重新創建實例,並回調onNewIntent方法,此模式啓動Activity A,系統首先會尋找是否存在A想要的任務棧,如果不存在,就會重新創建一個任務棧,然後把創建好A的實例放到棧中;
singleInstance單實例模式:這是一種加強的singleTask模式,具有此種模式的Activity只能單獨地位於一個任務棧中,且此任務棧中只有唯一一個實例;
3.隊列和棧的區別
隊列(Queue):是限定只能在表的一端進行插入和在另一端進行刪除操作的線性表;
棧(Stack):是限定只能在表的一端進行插入和刪除操作的線性表。
區別如下:
一、規則不同
1. 隊列:先進先出(First In First Out)FIFO
2. 棧:先進後出(First In Last Out )FILO
二、對插入和刪除操作的限定不同
1. 隊列:只能在表的一端進行插入,並在表的另一端進行刪除;
2. 棧:只能在表的一端插入和刪除。
三、遍歷數據速度不同
1. 隊列:基於地址指針進行遍歷,而且可以從頭部或者尾部進行遍歷,但不能同時遍歷,無需開闢空間,因爲在遍歷的過程中不影響數據結構,所以遍歷速度要快;
2. 棧:只能從頂部取數據,也就是說最先進入棧底的,需要遍歷整個棧才能取出來,而且在遍歷數據的同時需要爲數據開闢臨時空間,保持數據在遍歷前的一致性。
4,設備橫豎屏切換的時候,生面週期的變化
不設置Activity的android:configChanges時,切屏會重新調用各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次
設置Activity的android:configChanges=”orientation”時,
- 在Android5.1 即API 23級別下,切屏還是會重新調用各個生命週期,切橫、豎屏時只會執行一次
- 在Android9 即API 28級別下,切屏不會重新調用各個生命週期,只會執行onConfigurationChanged方法
設置Activity的android:configChanges=”orientation|keyboardHidden”時,切屏不會重新調用各個生命週期,只會執行
onConfigurationChanged方法
5.談一談Fragment的生命週期?
Fragment從創建到銷燬整個生命週期中涉及到的方法依次爲:
onAttach()→onCreate()→onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→onDestroy()→onDetach()
其中和Activity有不少名稱相同作用相似的方法,而不同的方法有:
- onAttach():當Fragment和Activity建立關聯時調用;
- onCreateView():當fragment創建視圖調用,在onCreate之後;
- onActivityCreated():當與Fragment相關聯的Activity完成onCreate()之後調用;
- onDestroyView():在Fragment中的佈局被移除時調用;
- onDetach():當Fragment和Activity解除關聯時調用;
6.Service生命週期
- onCreate() 首次創建服務時,系統將調用此方法。如果服務已在運行,則不會調用此方法,該方法只調用一次。
- onStartCommand() 當另一個組件通過調用startService()請求啓動服務時,系統將調用此方法。
- onDestroy() 當服務不再使用且將被銷燬時,系統將調用此方法。
- onBind() 當另一個組件通過調用bindService()與服務綁定時,系統將調用此方法。
- onUnbind() 當另一個組件通過調用unbindService()與服務解綁時,系統將調用此方法。
- onRebind() 當舊的組件與服務解綁後,另一個新的組件與服務綁定,onUnbind()返回true時,系統將調用此方法。
7.Service的兩種啓動方式?區別在哪?
- startService():通過這種方式調用startService,onCreate()只會被調用一次,多次調用startSercie會多次執行onStartCommand()和onStart()方法。如果外部沒有調用stopService()或stopSelf()方法,service會一直運行。
- bindService():如果該服務之前還沒創建,系統回調順序爲onCreate()→onBind()。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法不會多次創建服務及綁定。如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,回調順序爲onUnbind()→onDestroy();
8.廣播有幾種形式 ? 都有什麼特點 ?
- 普通廣播:開發者自身定義 intent的廣播(最常用),所有的廣播接收器幾乎會在同一時刻接受到此廣播信息,接受的先後順序隨機;
- 有序廣播:發送出去的廣播被廣播接收者按照先後順序接收,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後,廣播纔會繼續傳遞,且優先級(priority)高的廣播接收器會先收到廣播消息。有序廣播可以被接收器截斷使得後面的接收器無法收到它;
- 本地廣播:僅在自己的應用內發送接收廣播,也就是隻有自己的應用能收到,數據更加安全,效率更高,但只能採用動態註冊的方式;
- 粘性廣播:這種廣播會一直滯留,當有匹配該廣播的接收器被註冊後,該接收器就會收到此條廣播;
9.BroadcastReceiver註冊方式與區別
10.Android中IPC方式、各種方式優缺點,爲什麼選擇Binder?
Binder好在哪呢?
傳輸效率高、可操作性強、實現C/S架構方便、安全性高
11.Binder機制的作用?
Linux系統將一個進程分爲用戶空間和內核空間。對於進程之間來說,用戶空間的數據不可共享,內核空間的數據可共享,爲了保證安全性和獨立性,一個進程不能直接操作或者訪問另一個進程,即Android的進程是相互獨立、隔離的,這就需要跨進程之間的數據通信方式。
12.介紹下實現一個自定義View的基本流程
- View的工作流程主要是指measure、layout、draw這三大流程,即測量、佈局和繪製,其中measure確定View的測量寬/高,layout確定View的最終寬/高和四個頂點的位置,而draw則將View繪製到屏幕上
- View的繪製過程遵循如下幾步:
- 繪製背景 background.draw(canvas)
- 繪製自己(onDraw)
- 繪製 children(dispatchDraw)
- 繪製裝飾(onDrawScollBars)
13.什麼是ANR ? 什麼情況會出現ANR ?如何避免 ? 在不看代碼的情況下如何快速定位出現ANR問題所在 ?
- ANR(Application Not Responding,應用無響應):當操作在一段時間內系統無法處理時,會在系統層面會彈出ANR對話框
- 產生ANR可能是因爲5s內無響應用戶輸入事件、10s內未結束BroadcastReceiver、20s內未結束Service
- 想要避免ANR就不要在主線程做耗時操作,而是通過開子線程,方法比如繼承Thread或實現Runnable接口、使用AsyncTask、IntentService、HandlerThread等
-
Process:anr發生的時間和進程,和生成traces文件的時間 CPUusage ... ago :cpu在anr發生前的使用情況 CPUusage ...later: cpu在anr後的使用情況 ABI: 手機的cpu架構 HEAP: 堆的內存信息 ANR in: 包名,和類名 Reason:原因 TOTAL:總的CPU使用率 prio:線程的優先級 tid:線程鎖id 主線程的id爲1 主要看這個線程的 Sleeping:線程的狀態 sCount:線程被掛起的次數 dsCount:線程是否被調試
-
典型的分析情況
1.如果TOTAL(總的cpu使用頻率)的和接近100,有可能是因爲當前使用的app佔用的cpu太高,導致系統將你的殺死。
2.如果TOTAL很小,則說明線程被阻塞了,主線程在等待下條消息的進入,任務在等待時anr。
3.如果ioWait很高,則說明是io操作導致的
14.線程sleep和wait有什麼區別
功能差不多,都用來進行線程控制,他們最大本質的區別是:sleep()不釋放同步鎖,wait()釋放同步鎖.
還有用法的上的不同是:sleep(milliseconds)可以用時間指定來使他自動醒過來,如果時間不到你只能調用interreput()來強行打斷;wait()可以用notify()直接喚起.
15.如何優化ListView(偶爾會問)
- ①Item佈局,層級越少越好,使用hierarchyview工具查看優化。
- ②複用convertView
- ③使用ViewHolder
- ④item中有圖片時,異步加載
- ⑤快速滑動時,不加載圖片
- ⑥item中有圖片時,應對圖片進行適當壓縮
- ⑦實現數據的分頁加載
16.Android異步消息處理機制(這個也會經常問到)
異步消息處理機制主要是用來解決子線程更新UI的問題
主要有四個部分:
①. Message (消息)
在線程之間傳遞,可在內部攜帶少量信息,用於不同線程之間交換數據
可以使用what、arg1、arg2字段攜帶整型數據
obj字段攜帶Object對象
②. Handler (處理者)
主要用於發送和處理消息,sendMessage()用來發送消息,最終會回到handleMessage()進行處理
③. MessageQueue (消息隊列)
主要存放所有通過Handler發送的消息,它們會一直存在於隊列中等待被處理
每個線程只有一個MessageQueue
④. Looper (循環器)
調用loop()方法後,會不斷從MessageQueue 取出待處理的消息,然後傳遞到handleMessage進行處理.
17.內存泄漏和內存溢出是什麼?一般怎麼處理內存泄漏?
- 內存溢出 out of memory:是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。內存溢出通俗的講就是內存不夠用。
- 內存泄露 memory leak:是指程序在申請內存後,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積後果很嚴重,無論多少內存,遲早會被佔光
內存泄露原因以及解決:
一、Handler 引起的內存泄漏。
解決:將Handler聲明爲靜態內部類,就不會持有外部類SecondActivity的引用,其生命週期就和外部類無關,
如果Handler裏面需要context的話,可以通過弱引用方式引用外部類
二、單例模式引起的內存泄漏。
解決:Context是ApplicationContext,由於ApplicationContext的生命週期是和app一致的,不會導致內存泄漏
三、非靜態內部類創建靜態實例引起的內存泄漏。
解決:把內部類修改爲靜態的就可以避免內存泄漏了
四、非靜態匿名內部類引起的內存泄漏。
解決:將匿名內部類設置爲靜態的。
五、註冊/反註冊未成對使用引起的內存泄漏。
註冊廣播接受器、EventBus等,記得解綁。
六、資源對象沒有關閉引起的內存泄漏。
在這些資源不使用的時候,記得調用相應的類似close()、destroy()、recycler()、release()等方法釋放。
七、集合對象沒有及時清理引起的內存泄漏。
通常會把一些對象裝入到集合中,當不使用的時候一定要記得及時清理集合,讓相關對象不再被引用。