為面試積累經(jīng)驗赴精,很多都是平時用不到佩捞,但面試考人的知識點
目錄
- 數(shù)據(jù)結(jié)構(gòu)和算法
- Java 相關(guān)
- Android 相關(guān)
- Android Jetpack
- Kotlin 相關(guān)
- 其他
數(shù)據(jù)結(jié)構(gòu)和算法
數(shù)組:
一組相同的數(shù)據(jù)組成,存儲在連續(xù)的空間內(nèi)蕾哟,用索引可以找到元素地址一忱,包含一維數(shù)組和多維數(shù)組莲蜘,也最常用。
鏈表:
使用一組節(jié)點來表示一個數(shù)列帘营,包含頭和尾節(jié)點票渠,不是循環(huán)結(jié)構(gòu),所以尾就是終止芬迄。
雙向鏈表:
鏈表的每個節(jié)點有一組前后指針问顷,前后指針分別指向前驅(qū)結(jié)點和后繼節(jié)點,最后一個節(jié)點的后繼節(jié)點即指向第一個節(jié)點禀梳。
堆棧:
后進先出杜窄,最后一個入棧的第一個出棧,一個下壓結(jié)構(gòu)
隊列:
先進先出算途,最后一個入棧的最后一個出棧塞耕,一個線性結(jié)構(gòu)
Java相關(guān)
抽象:
一個類沒有包含足夠的信息,不是一個具體的類嘴瓤,就是抽象類
繼承:
用TextView舉例荷科,他是繼承自View,擁有View的特征纱注,但也實現(xiàn)了自己獨特的方法,簡而言之就是繼承并擁有自己獨特的部分
封裝:
降低耦合胆胰,良好的封裝可以更好的維護代碼
多態(tài):
相同的父類實現(xiàn)不同的狀態(tài)狞贱,繼承、重寫蜀涨、向上轉(zhuǎn)型
接口:
一個藍圖(契約)所有實現(xiàn)接口的類的共同模板
序列化:
將對象轉(zhuǎn)化為字節(jié)流瞎嬉,目的是將對象存儲到內(nèi)存里,等后面再構(gòu)建的時候就能獲取到之前的對象信息了厚柳,在Java里使用Serializable接口氧枣,而在Android中應(yīng)該使用Parcelable,因為Serializable使用反射機制别垮,會頻繁觸發(fā)垃圾回收便监,相比而言Parcelable更高效
單例:
一個類只初始化一次,只有一個實例
==和equals對比字符串:
==比較字符串地址碳想,String的equals是對比字符串內(nèi)容
Java內(nèi)存泄露:
1. 靜態(tài)集合類引起的烧董;
2. 監(jiān)聽器;
3. 各種數(shù)據(jù)連接胧奔;
4. 單例逊移;
Integer和int的區(qū)別:
integer是int的封裝類,而int是java的基礎(chǔ)類型龙填,Integer是對象默認為null胳泉,int是基本數(shù)據(jù)類型默認為0
Java中強引用拐叉,軟引用,弱引用:
1. 強引用:不會被GC輕易回收扇商,只要引用存在就永遠不會回收凤瘦;
2. 軟引用:非必要引用,內(nèi)存溢出前會回收钳吟;
3. 弱引用:第二次垃圾回收時回收
synchronized的作用:
通過synchronized設(shè)置同步鎖廷粒,每當(dāng)有線程需要訪問時,線程會首先獲取這個對象的鎖红且,并在成功獲取到對象鎖后才能正常訪問坝茎,訪問過程中其他線程無法獲得該鎖,也就是會優(yōu)先保證持有鎖的代碼執(zhí)行完畢
Android相關(guān)
Activity生命周期:
- onCreate Activity初始化工作
- onStart將Activity展現(xiàn)給用戶
- onResume Activity與用戶交互的時候觸發(fā)
- onPause Activity轉(zhuǎn)換到后臺時觸發(fā)暇番,在這里可以進行狀態(tài)持久化
- onStop Activity終止嗤放,但沒有銷毀
- onRestart Activity重新展示給用戶時觸發(fā)
- onDestroy Activity銷毀時觸發(fā)毯欣,如果內(nèi)存緊張時會直接結(jié)束而不會觸發(fā)
簡單說說四大組件:
Activity:
所有程序流程都運行在Activity上悔叽,整個Android程序中最基本的模塊之一悉罕,一般一個程序有多個Activity組成黍氮,概念和網(wǎng)頁類似Service:
級別和Activity差不多宵荒,但不能自主運行羽氮,只能待在后臺矿筝,Service是沒有界面的長維持代碼BroadcastReceiver:
廣播接收器吆视,可以用來接收其他應(yīng)用程序或應(yīng)用程序本身發(fā)出的廣播希俩,相對的發(fā)送廣播可以使用sendBroadcast進行吊宋,既可以在manifest注冊,也可以在registerReceiver注冊Content Provider:
第三方數(shù)據(jù)訪問方案颜武,使用uri作為訪問標識璃搜,提供訪問接口
Activity的LaunchMode的特點
standard:默認啟動模式,啟動新activity時會創(chuàng)建新的實例
singleTop:棧頂復(fù)用模式鳞上,如果該Activity存在棧頂这吻,則不會創(chuàng)建新的而是會調(diào)用onNewIntent方法,避免重復(fù)創(chuàng)建篙议,如果不在棧頂還是會被創(chuàng)建唾糯,一般常見于社交應(yīng)用中的通知欄行為功能。
singleTask:棧內(nèi)復(fù)用模式鬼贱,棧中僅存在一個實例趾断,只要存在棧里就不會創(chuàng)建新的,而是復(fù)用已經(jīng)存在的吩愧,并且調(diào)用onNewIntent芋酌,一般用作應(yīng)用的首頁,例如瀏覽器主頁
singleInstance:設(shè)置了這個后只能存在這一個Activity雁佳,可以用來不影響用戶行為的應(yīng)用脐帝,比如鬧鐘
LaunchMode特點補充(根據(jù)扔物線大佬的視頻學(xué)習(xí)而來):
Task的概念非常重要同云,他的結(jié)構(gòu)是一個典型的棧結(jié)構(gòu),遵循先進后出原則堵腹,一個應(yīng)用通常只有一個棧炸站,但也可以通過在清單文件中指定activity運行的棧,默認的棧即應(yīng)用的包名疚顷。
如果設(shè)置standard和singleTop本質(zhì)上是在一個應(yīng)用棧上操作的旱易,設(shè)置standard時新啟動的activity會堆疊在這個棧上,回退依次出棧腿堤,singleTop本質(zhì)上也是這個原理阀坏,但設(shè)置后他會清空該棧目標以上的activity,保證其位于棧頂笆檀,并回調(diào)onNewIntent方法刷新頁面數(shù)據(jù)忌堂。
singleTask和singleInstance這兩個略有不同,他們即可以運行在當(dāng)前應(yīng)用棧也可以運行在其他應(yīng)用棧中酗洒,來保證其全局的Activity唯一性士修。
這里還需要了解到前臺棧和后臺棧的概念,當(dāng)切換到應(yīng)用抽屜或點擊home鍵回到桌面時樱衷,前臺棧會轉(zhuǎn)換為后臺棧棋嘲,當(dāng)兩個棧位于前臺時,前一個結(jié)束會自動切換到下一個棧矩桂,但如果下一個是后臺棧沸移,則會直接回到首頁。
設(shè)置singleTask后耍鬓,棧中僅存在一個實例,只要存在棧里就不會創(chuàng)建新的流妻,而是復(fù)用已經(jīng)存在的牲蜀,并且調(diào)用onNewIntent,而設(shè)置singleInstance后绅这,該棧中僅有一個Activity涣达,Activity結(jié)束棧即關(guān)閉,要根據(jù)不同的業(yè)務(wù)需求選擇不同的啟動模式证薇。
闡述一下Activity和Fragment的區(qū)別:
生命周期不同
Activity的生命周期
onCreate→onStart→onResume→onPause→onStop→onDestroy
Fragment的生命周期
onAttach→onCreate→onCreateView→onActivityCreated→onStart→onResume→onPause→onStop→onDestoryView→onDestory→onDetach相比而言fragment更輕度苔,他依賴與Activity可以直接通過fragment標簽定義在xml文件里,也支持通過fragment事務(wù)動態(tài)更換浑度。
Activity總是一個一個的單獨存在寇窑,數(shù)個Fragment依附于一個Activity,如果Activity銷毀所屬的Fragment也將銷毀
Android中的內(nèi)存泄漏是怎么引起的:
內(nèi)存泄漏的本質(zhì)是本該被回收的對象因為某些原因箩张,沒有被回收還停留在堆內(nèi)存里甩骏。
- 如果持有該對象的強引用窗市,該對象是不會被回收的,最常見的就是Context饮笛,比如Activity的Context就包含了大量的引用咨察,萬不可把Context或View設(shè)為static;
- 內(nèi)部類持有Activity引用福青,導(dǎo)致Activity摄狱;
- 監(jiān)聽器綁定后沒有及時注銷,引起泄露无午;
- Bitmap對象沒有及時釋放媒役,在使用完后需要及時釋放
Service類型和啟動方式:
- Service類型
Service分為前臺和后臺,前臺會通過通知的形式讓用戶感知指厌,如音樂播放通知刊愚、消息通知,讓用戶知道有這么個東西在踩验,在Android8.0鸥诽,Google要求如果程序在后臺,那么就不能創(chuàng)建后臺服務(wù)箕憾,已經(jīng)開啟的后臺服務(wù)會在一定時間后被停止牡借。后臺服務(wù)使用JobScheduler,他僅在一個特定條件下去完成任務(wù)袭异。 - Service啟動方式
啟動方式分為startService和bindService钠龙,通過startService啟動后即在后臺無限期運行,即使啟動組件被銷毀也不會影響他御铃;通過bindService啟動時碴里,當(dāng)與其綁定的組件取消綁定,service將停止上真。在Android8.0后推薦使用startForeground啟動前臺Service咬腋。
Android 觸摸事件如何傳遞:
由Activity向下傳遞,經(jīng)過ViewGroup到View睡互,如果onInterceptorTouchEvent為true則表示攔截事件根竿,進行處理,如果onTouchEvent事件為true則表示事件消費就珠,如果到最后都不處理就會返回到Activity的onTouchEvent處理寇壳,整體是向下傳遞的過程。
View繪制流程:
- OnMeasure:先測量出視圖大小妻怎,從頂層父View到子View遞歸調(diào)用measure方法壳炎,measure方法又回調(diào)OnMeasure
- OnLayout:確定View的位置,進行頁面的布局逼侦,從頂層父View向子View的遞歸調(diào)用View.Layout方法的過程
- OnDraw: ViewGroup創(chuàng)建一個Canvas對象冕广,調(diào)用OnDraw()方法進行繪制
Android同/跨進程通信方式:
同進程
intent疏日、broadcast、事件總線撒汉、接口沟优、存儲機制等
跨進程
跨進程調(diào)用其他activity睬辐、ContentProvider、broadcast
app冷啟動優(yōu)化:
檢查冷啟動時間:在logcat中搜索Displayed溯饵,此值表示啟動過程和完成在屏幕上繪制相應(yīng)活動之間所經(jīng)過的時間量
優(yōu)化方案:
- 優(yōu)化閃屏頁,通過設(shè)置windowBackground圖片丰刊,將白屏/黑屏抹去隘谣,用戶點擊App的圖標就展示啟動圖啄巧,讓用戶先產(chǎn)生啟動很快的“錯覺”
- Application優(yōu)化寻歧,一些不用在主線程里初始化的SDK秩仆,放到子線程去初始化码泛,一些能放到啟動頁生命周期中初始化的可以延遲,一些用的時候再初始化的
- 優(yōu)化啟動頁
- layout層級優(yōu)化澄耍,避免多層級布局,針對特定業(yè)務(wù)初始化組件
- 避免IO操作阻塞主線程
- 注意Bitmap和圖片加載齐莲,避免因圖片過大而引起啟動緩慢
- 啟動圖可以使用VectorDrawable矢量圖,利用矢量圖省時間空間的特點
- 注意Activity的生命周期回調(diào)阵难,可以將網(wǎng)絡(luò)請求放到onWindowFocusChanged回調(diào)中星掰,這是真正的所有組件初始化完成回調(diào)
handler線程切換原理:
Handler的主要作用就是將一個任務(wù)切換到指定的線程中去執(zhí)行嫩舟。
首先主線程和子線程共用一個looper氢烘,在主線程中創(chuàng)建Handler時在構(gòu)造方法里傳入了當(dāng)前線程的looper家厌,所以子線程獲得了主線程的looper,進而獲得消息隊列蜀踏,并可以插入消息,最后主線程就可以從消息隊列中獲取到子線程傳來的Message了果覆。
onSaveInstanceState調(diào)式時機和恢復(fù)數(shù)據(jù)方法
避免系統(tǒng)回收activity導(dǎo)致數(shù)據(jù)丟失,用來保存和恢復(fù)數(shù)據(jù)時回調(diào)
調(diào)用時機
- 用戶按下Home鍵時斑响;
- 長按Home鍵或菜單鍵時钳榨;
- 手機息屏;
- 打開新Activity時营罢;
- 橫豎屏切換時饼齿;
恢復(fù)數(shù)據(jù)
onRestoreInstanceState只有在activity確實是被系統(tǒng)回收饲漾,重新創(chuàng)建activity的情況下才會被調(diào)用能颁,如果被調(diào)用了倒淫,則說明activity被回收。
onCreate中也有bundle參數(shù)敌土,但onSaveInstanceState不一定被調(diào)用,所以在恢復(fù)數(shù)據(jù)的時候需要非空判斷返干,而onRestoreInstanceState回調(diào)時其bundle值一定不為空。
應(yīng)用log捕捉
- 定義CrashHandler處理線程拋出的異常矩欠,并保存在本地
Android Jetpack
Lifecycle
實現(xiàn)和activity、fragment生命周期感知的框架躺坟,實現(xiàn)數(shù)據(jù)層和view層銷毀的時候解綁乳蓄。原理是Lifecycler為每個活動組件添加了一個沒有界面的Fragment,利用Fragment周期會根據(jù)活動聲明周期變化的特性實現(xiàn)的特性,從而實現(xiàn)生命周期的感知产舞,然后根據(jù)注解的Event查找執(zhí)行相應(yīng)的方法菠剩。
LiveData
提供了一種數(shù)據(jù)改變的同時,主動去告訴ui擦囊,讓ui層做出相應(yīng)的邏輯判斷嘴办。原理是內(nèi)部保存了LifecycleOwner和Observer,利用LifecycleOwner感知并處理聲明中期的變化涧郊,Observer在數(shù)據(jù)改變時遍歷所有觀察者并回調(diào)方法。
ViewModel
它是我們view層和model層的橋梁彤灶,是數(shù)據(jù)驅(qū)動界面的關(guān)鍵地方批旺,只有在Activity或Fragment真正銷毀的時候數(shù)據(jù)才會消失,不會因為橫豎屏切換等狀態(tài)丟失數(shù)據(jù)搏熄。
Room
Google官方提供的基于SQLite的ORM數(shù)據(jù)庫方案暇赤,通過將數(shù)據(jù)實體映射到數(shù)據(jù)庫進行操作,相較于GreenDAO他的特點是通過SQL語句操控CRUD鞋囊,相比而言我更喜歡使用GreenDAO那樣通過函數(shù)控制的溜腐。
DataBinding
數(shù)據(jù)綁定避免頻繁的findViewById,大大簡化代碼結(jié)構(gòu)和模板代碼編寫挺益,并且可以通過他實現(xiàn)雙向數(shù)據(jù)綁定還挺不錯的,只是只能改變組件的值而不能改變其本身现恼。
Navigation
谷歌后來推出的管理Fragment跳轉(zhuǎn)的框架黍檩,可以在xml中配置fragment間的關(guān)系,也可以引入SafeArgs來安全傳值刽酱,相比操作fragment事務(wù)他的中心思想更像activity跳轉(zhuǎn)棵里。
Hilt
Google官方推出的基于Dagger的依賴注入框架润文,減少我們創(chuàng)建對象的次數(shù)殿怜,降低耦合,采用@Inject头谜、@Bind、@Providers注解添加依賴截驮,類似Spring中的@Autowire际度。
Kotlin 相關(guān)
說說協(xié)程:
- 協(xié)程:切線程,通過withContext(Dispatchs.XX)指定運行的線程
- 掛起:自動切回來的切線程坡锡,可以通過suspand指定掛起函數(shù)窒所,suspand本身只作為提示作用,提示該函數(shù)是掛起函數(shù)墩新,一般用在CPU耗時操作和IO耗時操作上
- 非阻塞式:協(xié)程可以用看起來阻塞的辦法來寫出非阻塞式的方法,java中的線程本質(zhì)上也是非阻塞式的绵疲,只是在單線程中他阻塞臣疑,而kotlin的協(xié)程因為會自動切回來所以是非阻塞式的。
什么是 const? 和val有什么區(qū)別讯沈?
Val是在運行時被 設(shè)置, 加一個const 修飾符在val上將會變成編譯時常量问慎。 Const不能修飾var,不能用于局部變量
Lazy和lateinit的區(qū)別
兩者都延遲屬性的初始化 lateinit 是用于var的修飾符冰木, 可以用于 晚點來進行賦值笼恰。 Lazy更像一個方法或者一個lambda表達式。只用于val逼龟。 在需要時被創(chuàng)建追葡。
文章參考:
stormzhang/android-interview-questions-cn: 最全面的高質(zhì)量 Android 面試指南。 (github.com)