O(∩_∩)O~今天又給大家?guī)砹耍?1到Android高級(jí)面試題,搞懂了這些相信你去面試的時(shí)候一定可以鎮(zhèn)住面試官
為城廂等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及城廂網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、城廂網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

為此我吧這些知識(shí)整理成了一個(gè)983的PDF,從基礎(chǔ)到進(jìn)階。含有BATJ.字節(jié)跳動(dòng)面試專題,算法專題,高端技術(shù)專題,混合開發(fā)專題,java面試專題,Android,Java小知識(shí),到性能優(yōu)化.線程.View.OpenCV.NDK等應(yīng)有盡有。還有輔之相關(guān)的視頻+學(xué)習(xí)筆記
(更多完整項(xiàng)目下載。未完待續(xù)。源碼。圖文知識(shí)后續(xù)上傳github。)
可以點(diǎn)擊關(guān)于我聯(lián)系我獲取完整PDF
(VX:×××)
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
使用場(chǎng)景比如最常見的AlertDialog,拿我們開發(fā)過程中舉例,比如Camera開發(fā)過程中,可能需要設(shè)置一個(gè)初始化的相機(jī)配置,設(shè)置攝像頭方向,閃光燈開閉,成像質(zhì)量等等,這種場(chǎng)景下就可以使用建造者模式
動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的職責(zé),就增加功能來說,裝飾模式比生成子類更為靈活。裝飾者模式可以在不改變?cè)蓄惤Y(jié)構(gòu)的情況下曾強(qiáng)類的功能,比如Java中的BufferedInputStream 包裝FileInputStream,舉個(gè)開發(fā)中的例子,比如在我們現(xiàn)有網(wǎng)絡(luò)框架上需要增加新的功能,那么再包裝一層即可,裝飾者模式解決了繼承存在的一些問題,比如多層繼承代碼的臃腫,使代碼邏輯更清晰
這個(gè)通過對(duì)比來描述,比如面向?qū)ο蠛兔嫦蜻^程的對(duì)比,針對(duì)這兩種思想的對(duì)比,還可以舉個(gè)開發(fā)中的例子,比如播放器的實(shí)現(xiàn),面向過程的實(shí)現(xiàn)方式就是將播放視頻的這個(gè)功能分解成多個(gè)過程,比如,加載視頻地址,獲取視頻信息,初始化解碼器,選擇合適的解碼器進(jìn)行解碼,讀取解碼后的幀進(jìn)行視頻格式轉(zhuǎn)換和音頻重采樣,然后讀取幀進(jìn)行播放,這是一個(gè)完整的過程,這個(gè)過程中不涉及類的概念,而面向?qū)ο蟠蟮奶攸c(diǎn)就是類,封裝繼承和多態(tài)是核心,同樣的以播放器為例,一面向?qū)ο蟮姆绞絹韺?shí)現(xiàn),將會(huì)針對(duì)每一個(gè)功能封裝出一個(gè)對(duì)象,吧如說Muxer,獲取視頻信息,Decoder,解碼,格式轉(zhuǎn)換器,視頻播放器,音頻播放器等,每一個(gè)功能對(duì)應(yīng)一個(gè)對(duì)象,由這個(gè)對(duì)象來完成對(duì)應(yīng)的功能,并且遵循單一職責(zé)原則,一個(gè)對(duì)象只做它相關(guān)的事情
java中有三種創(chuàng)建線程的方式,或者說四種
線程池的工作原理:線程池可以減少創(chuàng)建和銷毀線程的次數(shù),從而減少系統(tǒng)資源的消耗,當(dāng)一個(gè)任務(wù)提交到線程池時(shí)
a. 首先判斷核心線程池中的線程是否已經(jīng)滿了,如果沒滿,則創(chuàng)建一個(gè)核心線程執(zhí)行任務(wù),否則進(jìn)入下一步
b. 判斷工作隊(duì)列是否已滿,沒有滿則加入工作隊(duì)列,否則執(zhí)行下一步
c. 判斷線程數(shù)是否達(dá)到了大值,如果不是,則創(chuàng)建非核心線程執(zhí)行任務(wù),否則執(zhí)行飽和策略,默認(rèn)拋出異常
Handler,Message,looper和MessageQueue構(gòu)成了安卓的消息機(jī)制,handler創(chuàng)建后可以通過sendMessage將消息加入消息隊(duì)列,然后looper不斷的將消息從MessageQueue中取出來,回調(diào)到Hander的handleMessage方法,從而實(shí)現(xiàn)線程的通信。
從兩種情況來說,第一在UI線程創(chuàng)建Handler,此時(shí)我們不需要手動(dòng)開啟looper,因?yàn)樵趹?yīng)用啟動(dòng)時(shí),在ActivityThread的main方法中就創(chuàng)建了一個(gè)當(dāng)前主線程的looper,并開啟了消息隊(duì)列,消息隊(duì)列是一個(gè)無限循環(huán),為什么無限循環(huán)不會(huì)ANR?因?yàn)榭梢哉f,應(yīng)用的整個(gè)生命周期就是運(yùn)行在這個(gè)消息循環(huán)中的,安卓是由事件驅(qū)動(dòng)的,Looper.loop不斷的接收處理事件,每一個(gè)點(diǎn)擊觸摸或者Activity每一個(gè)生命周期都是在Looper.loop的控制之下的,looper.loop一旦結(jié)束,應(yīng)用程序的生命周期也就結(jié)束了。我們可以想想什么情況下會(huì)發(fā)生ANR,第一,事件沒有得到處理,第二,事件正在處理,但是沒有及時(shí)完成,而對(duì)事件進(jìn)行處理的就是looper,所以只能說事件的處理如果阻塞會(huì)導(dǎo)致ANR,而不能說looper的無限循環(huán)會(huì)ANR
另一種情況就是在子線程創(chuàng)建Handler,此時(shí)由于這個(gè)線程中沒有默認(rèn)開啟的消息隊(duì)列,所以我們需要手動(dòng)調(diào)用looper.prepare(),并通過looper.loop開啟消息
主線程Looper從消息隊(duì)列讀取消息,當(dāng)讀完所有消息時(shí),主線程阻塞。子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。因此loop的循環(huán)并不會(huì)對(duì)CPU性能有過多的消耗。
非靜態(tài)內(nèi)部類會(huì)持有外部類的引用,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的,就會(huì)長(zhǎng)期的維持著外部類的引用,組織被系統(tǒng)回收,解決辦法是使用靜態(tài)內(nèi)部類
匿名內(nèi)部類同樣會(huì)持有外部類的引用,如果在線程中執(zhí)行耗時(shí)操作就有可能發(fā)生內(nèi)存泄漏,導(dǎo)致外部類無法被回收,直到耗時(shí)任務(wù)結(jié)束,解決辦法是在頁面退出時(shí)結(jié)束線程中的任務(wù)
Handler導(dǎo)致的內(nèi)存泄漏也可以被歸納為非靜態(tài)內(nèi)部類導(dǎo)致的,Handler內(nèi)部message是被存儲(chǔ)在MessageQueue中的,有些message不能馬上被處理,存在的時(shí)間會(huì)很長(zhǎng),導(dǎo)致handler無法被回收,如果handler是非靜態(tài)的,就會(huì)導(dǎo)致它的外部類無法被回收,解決辦法是1.使用靜態(tài)handler,外部類引用使用弱引用處理2.在退出頁面時(shí)移除消息隊(duì)列中的消息
根據(jù)場(chǎng)景確定使用Activity的Context還是Application的Context,因?yàn)槎呱芷诓煌瑢?duì)于不必須使用Activity的Context的場(chǎng)景(Dialog),一律采用Application的Context,單例模式是最常見的發(fā)生此泄漏的場(chǎng)景,比如傳入一個(gè)Activity的Context被靜態(tài)類引用,導(dǎo)致無法回收
使用靜態(tài)View可以避免每次啟動(dòng)Activity都去讀取并渲染View,但是靜態(tài)View會(huì)持有Activity的引用,導(dǎo)致無法回收,解決辦法是在Activity銷毀的時(shí)候?qū)㈧o態(tài)View設(shè)置為null(View一旦被加載到界面中將會(huì)持有一個(gè)Context對(duì)象的引用,在這個(gè)例子中,這個(gè)context對(duì)象是我們的Activity,聲明一個(gè)靜態(tài)變量引用這個(gè)View,也就引用了activity)
WebView導(dǎo)致的內(nèi)存泄漏WebView只要使用一次,內(nèi)存就不會(huì)被釋放,所以WebView都存在內(nèi)存泄漏的問題,通常的解決辦法是為WebView單開一個(gè)進(jìn)程,使用AIDL進(jìn)行通信,根據(jù)業(yè)務(wù)需求在合適的時(shí)機(jī)釋放掉
如Cursor,F(xiàn)ile等,內(nèi)部往往都使用了緩沖,會(huì)造成內(nèi)存泄漏,一定要確保關(guān)閉它并將引用置為null
集合用于保存對(duì)象,如果集合越來越大,不進(jìn)行合理的清理,尤其是入股集合是靜態(tài)的
bitmap是比較占內(nèi)存的,所以一定要在不使用的時(shí)候及時(shí)進(jìn)行清理,避免靜態(tài)變量持有大的bitmap對(duì)象
很多需要register和unregister的系統(tǒng)服務(wù)要在合適的時(shí)候進(jìn)行unregister,手動(dòng)添加的listener也需要及時(shí)移除
1).使用更加輕量的數(shù)據(jù)結(jié)構(gòu):
如使用ArrayMap/SparseArray替代HashMap,HashMap更耗內(nèi)存,因?yàn)樗枰~外的實(shí)例對(duì)象來記錄Mapping操作,SparseArray更加高效,因?yàn)樗苊饬薑ey Value的自動(dòng)裝箱,和裝箱后的解箱操作
2.便面枚舉的使用,可以用靜態(tài)常量或者注解@IntDef替代
3.Bitmap優(yōu)化:
inBitmap :使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經(jīng)存在的內(nèi)存區(qū)域,新解碼的Bitmap會(huì)嘗試去使用之前那張Bitmap在Heap中所占據(jù)的pixel data內(nèi)存區(qū)域,而不是去問內(nèi)存重新申請(qǐng)一塊區(qū)域來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會(huì)僅僅只需要占用屏幕所能夠顯示的圖片數(shù)量的內(nèi)存大小,但復(fù)用存在一些限制,具體體現(xiàn)在:在Android 4.4之前只能重用相同大小的Bitmap的內(nèi)存,而Android 4.4及以后版本則只要后來的Bitmap比之前的小即可。使用inBitmap參數(shù)前,每創(chuàng)建一個(gè)Bitmap對(duì)象都會(huì)分配一塊內(nèi)存供其使用,而使用了inBitmap參數(shù)后,多個(gè)Bitmap可以復(fù)用一塊內(nèi)存,這樣可以提高性能4.StringBuilder替代String:
在有些時(shí)候,代碼中會(huì)需要使用到大量的字符串拼接的操作,這種時(shí)候有必要考慮使用StringBuilder來替代頻繁的“+”
5.避免在類似onDraw這樣的方法中創(chuàng)建對(duì)象,因?yàn)樗鼤?huì)迅速占用大量?jī)?nèi)存,引起頻繁的GC甚至內(nèi)存抖動(dòng)
6.減少內(nèi)存泄漏也是一種避免OOM的方法
Standard模式: Activity可以有多個(gè)實(shí)例,每次啟動(dòng)Activity,無論任務(wù)棧中是否已經(jīng)有這個(gè)Activity的實(shí)例,系統(tǒng)都會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例
SingleTop模式: 當(dāng)一個(gè)singleTop模式的Activity已經(jīng)位于任務(wù)棧的棧頂,再去啟動(dòng)它時(shí),不會(huì)再創(chuàng)建新的實(shí)例,如果不位于棧頂,就會(huì)創(chuàng)建新的實(shí)例SingleTask模式: 如果Activity已經(jīng)位于棧頂,系統(tǒng)不會(huì)創(chuàng)建新的Activity實(shí)例,和singleTop模式一樣。但Activity已經(jīng)存在但不位于棧頂時(shí),系統(tǒng)就會(huì)把該Activity移到棧頂,并把它上面的activity出棧SingleInstance模式: singleInstance模式也是單例的,但和singleTask不同,singleTask只是任務(wù)棧內(nèi)單例,系統(tǒng)里是可以有多個(gè)singleTaskActivity實(shí)例的,而singleInstance Activity在整個(gè)系統(tǒng)里只有一個(gè)實(shí)例,啟動(dòng)一singleInstanceActivity時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)新的任務(wù)棧,并且這個(gè)任務(wù)棧只有他一個(gè)Activity生命周期
onCreate onStart onResume onPause onStop onDestroy
1.啟動(dòng)AonCreate - onStart - onResume
2.在A中啟動(dòng)BActivityA onPauseActivityB onCreateActivityB onStartActivityB onResumeActivityA onStop
3.從B中返回A(按物理硬件返回鍵)ActivityB onPauseActivityA onRestartActivityA onStartActivityA onResumeActivityB onStopActivityB onDestroy
4.繼續(xù)返回ActivityA onPauseActivityA onStopActivityA onDestroy
onRestart的調(diào)用場(chǎng)景(1) 按下home鍵之后,然后切換回來,會(huì)調(diào)用
onRestart()。
(2) 從本Activity跳轉(zhuǎn)到另一個(gè)Activity之后,按back鍵返回原來Activity,會(huì)調(diào)用onRestart();
(3) 從本Activity切換到其他的應(yīng)用,然后再?gòu)钠渌麘?yīng)用切換回來,會(huì)調(diào)用onRestart();
說下Activity的橫豎屏的切換的生命周期,用那個(gè)方法來保存數(shù)據(jù),兩者的區(qū)別。觸發(fā)在什么時(shí)候在那個(gè)方法里可以獲取數(shù)據(jù)等。
SurfaceView,它是什么?他的繼承方式是什么?他與View的區(qū)別(從源碼角度,如加載,繪制等)。SurfaceView中采用了雙緩沖機(jī)制,保證了UI界面的流暢性,同時(shí)SurfaceView不在主線程中繪制,而是另開辟一個(gè)線程去繪制,所以它不妨礙UI線程;
SurfaceView繼承于View,他和View主要有以下三點(diǎn)區(qū)別:
SurfaceView有;SurfaceView適用與被動(dòng)的更新,如頻繁的刷新SurfaceView則在子線程中刷新;SurfaceView的內(nèi)容不在應(yīng)用窗口上,所以不能使用變換(平移、縮放、旋轉(zhuǎn)等)。也難以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha()View:顯示視圖,內(nèi)置畫布,提供圖形繪制函數(shù)、觸屏事件、按鍵事件函數(shù)等;必須在UI主線程內(nèi)更新畫面,速度較慢。
SurfaceView:基于view視圖進(jìn)行拓展的視圖類,更適合2Dgame的開發(fā);是view的子類,類似使用雙緩機(jī)制,在新的線程中更新畫面所以刷新界面速度比view快,Camera預(yù)覽界面使用SurfaceView。
GLSurfaceView:基于SurfaceView視圖再次進(jìn)行拓展的視圖類,專用于3Dgame開發(fā)的視圖;是SurfaceView的子類,openGL專用。
a: Service設(shè)置成START_STICKY kill 后會(huì)被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣
b: 通過startForeground將進(jìn)程設(shè)置為前臺(tái)進(jìn)程, 做前臺(tái)服務(wù),優(yōu)先級(jí)和前臺(tái)應(yīng)用一個(gè)級(jí)別,除非在系統(tǒng)內(nèi)存非常缺,否則此進(jìn)程不會(huì)被 kill
c: 雙進(jìn)程Service: 讓2個(gè)進(jìn)程互相保護(hù)對(duì)方,其中一個(gè)Service被清理后,另外沒被清理的進(jìn)程可以立即重啟進(jìn)程
d: 用C編寫守護(hù)進(jìn)程(即子進(jìn)程) : Android系統(tǒng)中當(dāng)前進(jìn)程(Process)fork出來的子進(jìn)程,被系統(tǒng)認(rèn)為是兩個(gè)不同的進(jìn)程。當(dāng)父進(jìn)程被殺死的時(shí)候,子進(jìn)程仍然可以存活,并不受影響(Android5.0以上的版本不可行)聯(lián)系廠商,加入白名單
e. 鎖屏狀態(tài)下,開啟一個(gè)一像素Activity
app冷啟動(dòng): 當(dāng)應(yīng)用啟動(dòng)時(shí),后臺(tái)沒有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用, 這個(gè)啟動(dòng)方式就叫做冷啟動(dòng)(后臺(tái)不存在該應(yīng)用進(jìn)程)。冷啟動(dòng)因?yàn)橄到y(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給它,所以會(huì)先創(chuàng)建和初始化Application類,再創(chuàng)建和初始化MainActivity類(包括一系列的測(cè)量、布局、繪制),最后顯示在界面上。
app熱啟動(dòng): 當(dāng)應(yīng)用已經(jīng)被打開, 但是被按下返回鍵、Home鍵等按鍵時(shí)回到桌面或者是其他程序的時(shí)候,再重新打開該app時(shí), 這個(gè)方式叫做熱啟動(dòng)(后臺(tái)已經(jīng)存在該應(yīng)用進(jìn)程)。熱啟動(dòng)因?yàn)闀?huì)從已有的進(jìn)程中來啟動(dòng),所以熱啟動(dòng)就不會(huì)走Application這步了,而是直接走MainActivity(包括一系列的測(cè)量、布局、繪制),所以熱啟動(dòng)的過程只需要?jiǎng)?chuàng)建和初始化一個(gè)MainActivity就行了,而不必創(chuàng)建和初始化Application
冷啟動(dòng)的流程
當(dāng)點(diǎn)擊app的啟動(dòng)圖標(biāo)時(shí),安卓系統(tǒng)會(huì)從Zygote進(jìn)程中fork創(chuàng)建出一個(gè)新的進(jìn)程分配給該應(yīng)用,之后會(huì)依次創(chuàng)建和初始化Application類、創(chuàng)建MainActivity類、加載主題樣式Theme中的windowBackground等屬性設(shè)置給MainActivity以及配置Activity層級(jí)上的一些屬性、再inflate布局、當(dāng)onCreate/onStart/onResume方法都走完了后最后才進(jìn)行contentView的measure/layout/draw顯示在界面上冷啟動(dòng)的生命周期簡(jiǎn)要流程:
Application構(gòu)造方法 –> attachBaseContext()–>onCreate –>Activity構(gòu)造方法 –> onCreate() –> 配置主體中的背景等操作 –>onStart() –> onResume() –> 測(cè)量、布局、繪制顯示
冷啟動(dòng)的優(yōu)化主要是視覺上的優(yōu)化,解決白屏問題,提高用戶體驗(yàn),所以通過上面冷啟動(dòng)的過程。能做的優(yōu)化如下:
1、減少onCreate()方法的工作量
2、不要讓Application參與業(yè)務(wù)的操作
3、不要在Application進(jìn)行耗時(shí)操作
4、不要以靜態(tài)變量的方式在Application保存數(shù)據(jù)
5、減少布局的復(fù)雜度和層級(jí)
6、減少主線程耗時(shí)
當(dāng)Android端需要獲得數(shù)據(jù)時(shí)比如獲取網(wǎng)絡(luò)中的圖片,首先從內(nèi)存中查找(按鍵查找),內(nèi)存中沒有的再?gòu)拇疟P文件或sqlite中去查找,若磁盤中也沒有才通過網(wǎng)絡(luò)獲取
LruCache中Lru算法的實(shí)現(xiàn)就是通過LinkedHashMap來實(shí)現(xiàn)的。LinkedHashMap繼承于HashMap,它使用了一個(gè)雙向鏈表來存儲(chǔ)Map中的Entry順序關(guān)系,
對(duì)于get、put、remove等操作,LinkedHashMap除了要做HashMap做的事情,還做些調(diào)整Entry順序鏈表的工作。
LruCache中將LinkedHashMap的順序設(shè)置為L(zhǎng)RU順序來實(shí)現(xiàn)LRU緩存,每次調(diào)用get(也就是從內(nèi)存緩存中取圖片),則將該對(duì)象移到鏈表的尾端。
調(diào)用put插入新的對(duì)象也是存儲(chǔ)在鏈表尾端,這樣當(dāng)內(nèi)存緩存達(dá)到設(shè)定的大值時(shí),將鏈表頭部的對(duì)象(近期最少用到的)移除。

所有的答案,請(qǐng)查看完整的PDF版
(更多完整項(xiàng)目下載。未完待續(xù)。源碼。圖文知識(shí)后續(xù)上傳github。)
可以點(diǎn)擊關(guān)于我聯(lián)系我獲取完整PDF
(VX:×××)

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
網(wǎng)頁名稱:21道Android高級(jí)面試題,面試官都被搞愣了-創(chuàng)新互聯(lián)
標(biāo)題來源:http://chinadenli.net/article22/cogpcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、外貿(mào)建站、網(wǎng)頁設(shè)計(jì)公司、營(yíng)銷型網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容