下面是啊最近幾次面試總結(jié):
面試分類為三個(gè)方面
- android相關(guān)
- java相關(guān)
- 其他
Android相關(guān)
1.四大組件及其生命周期?
2.Activity個(gè)情況下的生命周期及之間的通信?
1.a啟動(dòng)b,后退鍵再到a的生命周期流程:a.create→a.start→a.resume→a.pause→b.create→b.start→b.resume→b界面繪制→a.stop→b.pause→b.stop→b.destroy→a.restart→a.start→a.resume
2.意外銷毀會(huì)調(diào)用saveInstance,重新恢復(fù)的時(shí)候回調(diào)用restoreInstance。儲(chǔ)存數(shù)據(jù)的時(shí)候使用了委托機(jī)制,從activity→window→viewGroup→view 會(huì)遞歸調(diào)用save來保持本view的數(shù)據(jù),restore則是遞歸恢復(fù)本view數(shù)據(jù)。我們可以在里面做一些自己需要的數(shù)據(jù)操作。
3.各種操作下Activity的生命周期變化?
`下拉狀態(tài)欄是不是影響activity的生命周期?
4.Activity的啟動(dòng)模式?
1.standard:默認(rèn)標(biāo)準(zhǔn)模式,每啟動(dòng)一個(gè)都會(huì)創(chuàng)建一個(gè)實(shí)例,
2.singleTop:棧頂復(fù)用,如果在棧頂就調(diào)用onNewIntent復(fù)用,從onResume()開始
3.singleTask:棧內(nèi)復(fù)用,本棧內(nèi)只要用該類型Activity就會(huì)將其頂部的activity出棧
4.singleInstance:單例模式,除了3中特性,系統(tǒng)會(huì)單獨(dú)給該Activity創(chuàng)建一個(gè)棧。
A、B、C、D分別是四種Activity的啟動(dòng)模式,那么A->B->C->D->A->B->C->D分別啟動(dòng),最后的activity棧是怎么樣的?
答案是:兩個(gè)棧,前臺(tái)棧是只有D,后臺(tái)棧從底至上是A、B、C
5.Fragment的生命周期及個(gè)情況下的變化?
6.Fragment之間的通信?
7.Fragment與Activity生命周期對(duì)比?
8.如何實(shí)現(xiàn)Fragment的滑動(dòng)?
9.Activity怎么和Service綁定?
10.Service的啟動(dòng)方式及生命周期?
Q1.IntentService原理及作用是什么?
Q2.說說Activity、Intent、Service 是什么關(guān)系?
Q3.ApplicationContext和ActivityContext的區(qū)別?
Q4.AndroidService與Activity之間通信的幾種方式?
1.context.startService() ->onCreate()- >onStart()->Service running→(如果調(diào)用context.stopService() )->onDestroy() ->Service shut down
1.如果Service還沒有運(yùn)行,則調(diào)用onCreate()然后調(diào)用onStart();
2.如果Service已經(jīng)運(yùn)行,則只調(diào)用onStart(),所以一個(gè)Service的onStart方法可能會(huì)重復(fù)調(diào)用多次。
3.調(diào)用stopService的時(shí)候直接onDestroy,
4.如果是調(diào)用者自己直接退出而沒有調(diào)用stopService的話,Service會(huì)一直在后臺(tái)運(yùn)行。該Service的調(diào)用者再啟動(dòng)起來后可以通過stopService關(guān)閉Service。
2.context.bindService()->onCreate()->onBind()->Service running→onUnbind() -> onDestroy() ->Service stop
1.onBind將返回給客戶端一個(gè)IBind接口實(shí)例,IBind允許客戶端回調(diào)服務(wù)的方法,比如得到Service運(yùn)行的狀態(tài)或其他操作。
2.這個(gè)時(shí)候會(huì)把調(diào)用者和Service綁定在一起,Context退出了,Service就會(huì)調(diào)用onUnbind->onDestroy相應(yīng)退出。
3.所以調(diào)用bindService的生命周期為:onCreate → onBind(只一次,不可多次綁定) → onUnbind → onDestory。
怎么保證service不被殺死?
1.提升service優(yōu)先級(jí)
2.提升service進(jìn)程優(yōu)先級(jí)
3.onDestroy方法里重啟service
IntentService是什么?
含有HandlerThread的Service,可以多次startService()來多次在子線程中進(jìn)行 onHandlerIntent()的調(diào)用。
11.廣播分類,使用方式及場(chǎng)景?
1.在manifest 和代碼中如何注冊(cè)和使用BroadcastReceiver?
2.本地廣播和全局廣播有什么差別?
3.BroadcastReceiver,LocalBroadcastReceiver 區(qū)別?
靜態(tài)的Broadcast 和動(dòng)態(tài)的有什么區(qū)別?
1.動(dòng)態(tài)的比靜態(tài)的安全
2.靜態(tài)在app啟動(dòng)的時(shí)候就初始化了 動(dòng)態(tài)使用代碼初始化
3.靜態(tài)需要配置 動(dòng)態(tài)不需要
4.生存期,靜態(tài)廣播的生存期可以比動(dòng)態(tài)廣播的長很多
5.優(yōu)先級(jí)動(dòng)態(tài)廣播的優(yōu)先級(jí)比靜態(tài)廣播高
12.ContentProvider的理解,說說ContentProvider、ContentResolver、ContentObserver 之間的關(guān)系?
13.Handler機(jī)制和底層實(shí)現(xiàn),對(duì)比Handler、Thread和HandlerThread的差別
1.MessageQueue:讀取會(huì)自動(dòng)刪除消息,單鏈表維護(hù),在插入和刪除上有優(yōu)勢(shì)。在其next()中會(huì)無限循環(huán),不斷判斷是否有消息,有就返回這條消息并移除。
2.Looper:Looper創(chuàng)建的時(shí)候會(huì)創(chuàng)建一個(gè)MessageQueue,調(diào)用loop()方法的時(shí)候消息循環(huán)開始,loop()也是一個(gè)死循環(huán),會(huì)不斷調(diào)用messageQueue的next(),當(dāng)有消息就處理,否則阻塞在messageQueue的next()中。當(dāng)Looper的quit()被調(diào)用的時(shí)候會(huì)調(diào)用messageQueue的quit(),此時(shí)next()會(huì)返回null,然后loop()方法也跟著退出。
3.Handler:在主線程構(gòu)造一個(gè)Handler,然后在其他線程調(diào)用sendMessage(),此時(shí)主線程的MessageQueue中會(huì)插入一條message,然后被Looper使用。
4.系統(tǒng)的主線程在ActivityThread的main()為入口開啟主線程,其中定義了內(nèi)部類Activity.H定義了一系列消息類型,包含四大組件的啟動(dòng)停止。
5.MessageQueue和Looper是一對(duì)一關(guān)系,Handler和Looper是多對(duì)一
java的線程如何實(shí)現(xiàn)
1.Thread繼承
2.Runnale
3.Future
4.線程池
@Looper架構(gòu)及ActivityTrhead,AMS,WMS的工作區(qū)別?
HandlerThread是:MessageQueue + Looper + Handler
14.View的繪制過程,刷新機(jī)制,自定義控件原理?
@自定義view的機(jī)型適配
@Requestlayout,onlayout,onDraw,DrawChild區(qū)別與聯(lián)系
@invalidate和postInvalidate的區(qū)別及使用
1.ViewRootImpl會(huì)調(diào)用performTraversals(),其內(nèi)部會(huì)調(diào)用performMeasure()、performLayout、performDraw()。
2.performMeasure()會(huì)調(diào)用最外層的ViewGroup的measure()→onMeasure(),ViewGroup的onMeasure()是抽象方法,但其提供了measureChildren(),這之中會(huì)遍歷子View然后循環(huán)調(diào)用measureChild()這之中會(huì)用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一起獲取本View的MeasureSpec,然后調(diào)用子View的measure()到View的onMeasure()→setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默認(rèn)返回measureSpec的測(cè)量數(shù)值,所以繼承View進(jìn)行自定義的wrap_content需要重寫。
3.performLayout()會(huì)調(diào)用最外層的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()設(shè)置本View的四個(gè)頂點(diǎn)位置。在onLayout(抽象方法)中確定子View的位置,如LinearLayout會(huì)遍歷子View,循環(huán)調(diào)用setChildFrame()→子View.layout()。
4.performDraw()會(huì)調(diào)用最外層ViewGroup的draw():其中會(huì)先后調(diào)用background.draw()(繪制背景)、onDraw()(繪制自己)、dispatchDraw()(繪制子View)、onDrawScrollBars()(繪制裝飾)。
5.MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(對(duì)應(yīng)精確值和match_parent)、AT_MOST(對(duì)應(yīng)warp_content))和30位SpecSize組成一個(gè)int,DecorView的MeasureSpec由窗口大小和其LayoutParams決定,其他View由父View的MeasureSpec和本View的LayoutParams決定。ViewGroup中有g(shù)etChildMeasureSpec()來獲取子View的MeasureSpec。
6.三種方式獲取measure()后的寬高:
1.Activity#onWindowFocusChange()中調(diào)用獲取
2.view.post(Runnable)將獲取的代碼投遞到消息隊(duì)列的尾部。
3.ViewTreeObservable.
15.Android Touch事件分發(fā)機(jī)制 流程?

16.AsyncTask機(jī)制,AsyncTask原理及不足,如何取消AsyncTask?
17.為什么不能在子線程更新UI?ANR產(chǎn)生的原因是什么?
過度繪制、卡頓優(yōu)化:
1.過度繪制:
1.移除Window默認(rèn)的Background:getWidow.setBackgroundDrawable(null);
2.移除XML布局文件中非必需的Background
3.減少布局嵌套(扁平化的一個(gè)體現(xiàn),減少View數(shù)的深度,也就減少了View樹的遍歷時(shí)間,渲染的時(shí)候,前后期的工作,總是按View樹結(jié)點(diǎn)來)
4.在引入布局文件里面,最外層可以用merge替代LinearLayout,RelativeLayout,這樣把子UI元素直接銜接在include位置
5.工具:HierarchyViewer 查看視圖層級(jí)
2.卡頓優(yōu)化:16ms數(shù)據(jù)更新
ANR產(chǎn)生的原因是什么?
1.只要是主線程耗時(shí)的操作就會(huì)ARN 如io
2.broadcast超時(shí)時(shí)間為10秒 按鍵無響應(yīng)的超時(shí)時(shí)間為5秒 前臺(tái)service無響應(yīng)的超時(shí)時(shí)間為20秒,后臺(tái)service為200秒
18.OOM是什么?什么情況導(dǎo)致OOM?有什么解決避免OOM?
Oom 是否可以try catch?為什么?
1.其他線程持有一個(gè)Listener,Listener操作activity。那么在線程么有完畢的時(shí)候,activity關(guān)閉了,原本是要被回收的但是,不能被回收。
2.例如Handler導(dǎo)致的內(nèi)存泄漏,Handler就相當(dāng)于Listener。
3.在activity關(guān)閉的時(shí)候注意停止線程,或者將Listener的注冊(cè)取消
3.使用弱引用,這樣即使Listener持有了activity,在GC的時(shí)候還是會(huì)被回收
4.工具:LeakCanary
19.動(dòng)態(tài)布局的理解?
20.Android動(dòng)畫?
1.動(dòng)畫的基本原理:其實(shí)就是利用插值器和估值器,來計(jì)算出各個(gè)時(shí)刻View的屬性,然后通過改變View的屬性來,實(shí)現(xiàn)View的動(dòng)畫效果。
2.View動(dòng)畫:只是影像變化,view的實(shí)際位置還在原來的地方。
3.幀動(dòng)畫是在xml中定義好一系列圖片之后,使用AnimationDrawable來播放的動(dòng)畫。
4.View的屬性動(dòng)畫:
1.插值器:作用是根據(jù)時(shí)間的流逝的百分比來計(jì)算屬性改變的百分比
2.估值器:在1的基礎(chǔ)上由這個(gè)東西來計(jì)算出屬性到底變化了多少數(shù)值的類
21.Android個(gè)版本之間的差異,低版本SDK如何使用高版本的API?
22.描述一次網(wǎng)絡(luò)請(qǐng)求的流程,HttpUrlConnection 和 okhttp關(guān)系?
實(shí)現(xiàn)一個(gè)網(wǎng)絡(luò)框架(參考Volley)?
1.緩存隊(duì)列,以u(píng)rl為key緩存內(nèi)容可以參考Bitmap的處理方式,這里單獨(dú)開啟一個(gè)線程。
2.網(wǎng)絡(luò)請(qǐng)求隊(duì)列,使用線程池進(jìn)行請(qǐng)求。
3.提供各種不同類型的返回值的解析如String,Json,圖片等等。
Q1 AstncTask+HttpClient 與 AsyncHttpClient有什么區(qū)別?
Q2 談?wù)剬?duì)Volley的理解
23.Intente與Bundle
bundle
1.鍵值對(duì)儲(chǔ)存
2.傳遞的數(shù)據(jù)可以是boolean、byte、int、long、float、double、string等基本類型或它們對(duì)應(yīng)的數(shù)組,也可以是對(duì)象或?qū)ο髷?shù)組。
3.當(dāng)Bundle傳遞的是對(duì)象或?qū)ο髷?shù)組時(shí),必須實(shí)現(xiàn)Serializable 或Parcelable接口
23.TCP與UDP的區(qū)別?TCP與UDP的應(yīng)用?
如何設(shè)計(jì)在 UDP 上層保證 UDP 的可靠性傳輸?
1.簡單來講,要使用UDP來構(gòu)建可靠的面向連接的數(shù)據(jù)傳輸,就要實(shí)現(xiàn)類似于TCP協(xié)議的超時(shí)重傳,有序接受,應(yīng)答確認(rèn),滑動(dòng)窗口流量控制等機(jī)制,等于說要在傳輸層的上一層(或者直接在應(yīng)用層)實(shí)現(xiàn)TCP協(xié)議的可靠數(shù)據(jù)傳輸機(jī)制。
2.比如使用UDP數(shù)據(jù)包+序列號(hào),UDP數(shù)據(jù)包+時(shí)間戳等方法,在服務(wù)器端進(jìn)行應(yīng)答確認(rèn)機(jī)制,這樣就會(huì)保證不可靠的UDP協(xié)議進(jìn)行可靠的數(shù)據(jù)傳輸。
3.基于udp的可靠傳輸協(xié)議有:RUDP、RTP、UDT
24.對(duì)Bitmap的理解,針對(duì)圖片的優(yōu)化?
1.當(dāng)使用ImageView的時(shí)候,可能圖片的像素大于ImageView,此時(shí)就可以通過BitmapFactory.Option來對(duì)圖片進(jìn)行壓縮,inSampleSize表示縮小2^(inSampleSize-1)倍。
2.BitMap的緩存:
1.使用LruCache進(jìn)行內(nèi)存緩存。
2.使用DiskLruCache進(jìn)行硬盤緩存。
3.實(shí)現(xiàn)一個(gè)ImageLoader的流程:同步異步加載、圖片壓縮、內(nèi)存硬盤緩存、網(wǎng)絡(luò)拉取
1.同步加載只創(chuàng)建一個(gè)線程然后按照順序進(jìn)行圖片加載
2.異步加載使用線程池,讓存在的加載任務(wù)都處于不同線程
3.為了不開啟過多的異步任務(wù),只在列表靜止的時(shí)候開啟圖片加載
25.Activity-Window-View三者的差別?
Q0.LaunchMode應(yīng)用場(chǎng)景?
Q1.Activity棧?
···
Activity緩存方法
1.配置改變導(dǎo)致Activity被殺死,橫屏變豎屏:在onStop之前會(huì)調(diào)用onSaveInstanceState()保存數(shù)據(jù)在重建Activity之后,會(huì)在onStart()之后調(diào)用onRestoreInstanceState(),并把保存下來的Bundle傳給onCreate()和它會(huì)默認(rèn)重建Activity當(dāng)前的視圖,我們可以在onCreate()中,回復(fù)自己的數(shù)據(jù)。
2.內(nèi)存不足殺掉Activity,優(yōu)先級(jí)分別是:前臺(tái)可見,可見非前臺(tái),后臺(tái)。
怎樣退出終止App?
1.自己設(shè)置一個(gè)Activity的棧,然后一個(gè)個(gè)finish()
···
Q0.SP是進(jìn)程同步的嗎?有什么方法做到同步?
Q2.AndroidManifest的作用與理解?
Q2.Android重要術(shù)語解釋
1.ActivityManagerServices,簡稱AMS,服務(wù)端對(duì)象,負(fù)責(zé)系統(tǒng)中所有Activity的生命周期
2.ActivityThread,App的真正入口。當(dāng)開啟App之后,會(huì)調(diào)用main()開始運(yùn)行,開啟消息循環(huán)隊(duì)列,這就是傳說中的UI線程或者叫主線程。與ActivityManagerServices配合,一起完成Activity的管理工作
3.ApplicationThread,用來實(shí)現(xiàn)ActivityManagerService與ActivityThread之間的交互。在ActivityManagerService需要管理相關(guān)Application中的Activity的生命周期時(shí),通過ApplicationThread的代理對(duì)象與ActivityThread通訊。
4.ApplicationThreadProxy,是ApplicationThread在服務(wù)器端的代理,負(fù)責(zé)和客戶端的ApplicationThread通訊。AMS就是通過該代理與ActivityThread進(jìn)行通信的。
5.Instrumentation,每一個(gè)應(yīng)用程序只有一個(gè)Instrumentation對(duì)象,每個(gè)Activity內(nèi)都有一個(gè)對(duì)該對(duì)象的引用。Instrumentation可以理解為應(yīng)用進(jìn)程的管家,ActivityThread要?jiǎng)?chuàng)建或暫停某個(gè)Activity時(shí),都需要通過Instrumentation來進(jìn)行具體的操作。
6.ActivityStack,Activity在AMS的棧管理,用來記錄已經(jīng)啟動(dòng)的Activity的先后關(guān)系,狀態(tài)信息等。通過ActivityStack決定是否需要啟動(dòng)新的進(jìn)程。
7.ActivityRecord,ActivityStack的管理對(duì)象,每個(gè)Activity在AMS對(duì)應(yīng)一個(gè)ActivityRecord,來記錄Activity的狀態(tài)以及其他的管理信息。其實(shí)就是服務(wù)器端的Activity對(duì)象的映像。
8.TaskRecord,AMS抽象出來的一個(gè)“任務(wù)”的概念,是記錄ActivityRecord的棧,一個(gè)“Task”包含若干個(gè)ActivityRecord。AMS用TaskRecord確保Activity啟動(dòng)和退出的順序。如果你清楚Activity的4種launchMode,那么對(duì)這個(gè)概念應(yīng)該不陌生。
Q2.簡述IPC?
1.ipc通信方式:binder、contentprovider、socket
2.操作系統(tǒng)進(jìn)程通訊方式:共享內(nèi)存、socket、管道
1.在Activity和Service進(jìn)行通訊的時(shí)候,用到了Binder。
1.當(dāng)屬于同個(gè)進(jìn)程我們可以繼承Binder然后在Activity中對(duì)Service進(jìn)行操作
2.當(dāng)不屬于同個(gè)進(jìn)程,那么要用到AIDL讓系統(tǒng)給我們創(chuàng)建一個(gè)Binder,然后在Activity中對(duì)遠(yuǎn)端的Service進(jìn)行操作。
2.系統(tǒng)給我們生成的Binder:
1.Stub類中有:接口方法的id,有該Binder的標(biāo)識(shí),有asInterface(IBinder)(讓我們?cè)贏ctivity中獲取實(shí)現(xiàn)了Binder的接口,接口的實(shí)現(xiàn)在Service里,同進(jìn)程時(shí)候返回Stub否則返回Proxy),有onTransact()這個(gè)方法是在不同進(jìn)程的時(shí)候讓Proxy在Activity進(jìn)行遠(yuǎn)端調(diào)用實(shí)現(xiàn)Activity操作Service
2.Proxy類是代理,在Activity端,其中有:IBinder mRemote(這就是遠(yuǎn)端的Binder),兩個(gè)接口的實(shí)現(xiàn)方法不過是代理最終還是要在遠(yuǎn)端的onTransact()中進(jìn)行實(shí)際操作。
3.哪一端的Binder是副本,該端就可以被另一端進(jìn)行操作,因?yàn)锽inder本體在定義的時(shí)候可以操作本端的東西。所以可以在Activity端傳入本端的Binder,讓Service端對(duì)其進(jìn)行操作稱為Listener,可以用RemoteCallbackList這個(gè)容器來裝Listener,防止Listener因?yàn)榻?jīng)歷過序列化而產(chǎn)生的問題。
4.當(dāng)Activity端向遠(yuǎn)端進(jìn)行調(diào)用的時(shí)候,當(dāng)前線程會(huì)掛起,當(dāng)方法處理完畢才會(huì)喚醒。
5.如果一個(gè)AIDL就用一個(gè)Service太奢侈,所以可以使用Binder池的方式,建立一個(gè)AIDL其中的方法是返回IBinder,然后根據(jù)方法中傳入的參數(shù)返回具體的AIDL。
6.IPC的方式有:Bundle(在Intent啟動(dòng)的時(shí)候傳入,不過是一次性的),文件共享(對(duì)于SharedPreference是特例,因?yàn)槠湓趦?nèi)存中會(huì)有緩存),使用Messenger(其底層用的也是AIDL,同理要操作哪端,就在哪端定義Messenger),AIDL,ContentProvider(在本進(jìn)程中繼承實(shí)現(xiàn)一個(gè)ContentProvider,在增刪改查方法中調(diào)用本進(jìn)程的SQLite,在其他進(jìn)程中查詢),Socket
Q3.描述一次跨進(jìn)程通訊
1.client、proxy、serviceManager、BinderDriver、impl、service
2.client發(fā)起一個(gè)請(qǐng)求service信息的Binder請(qǐng)求到BinderDriver中,serviceManager發(fā)現(xiàn)BinderDiriver中有自己的請(qǐng)求 然后將clinet請(qǐng)求的service的數(shù)據(jù)返回給client這樣完成了一次Binder通訊
3.clinet獲取的service信息就是該service的proxy,此時(shí)調(diào)用proxy的方法,proxy將請(qǐng)求發(fā)送到BinderDriver中,此時(shí)service的 Binder線程池循環(huán)發(fā)現(xiàn)有自己的請(qǐng)求,然后用impl就處理這個(gè)請(qǐng)求最后返回,這樣完成了第二次Binder通訊
4.中間client可掛起,也可以不掛起,有一個(gè)關(guān)鍵字oneway可以解決這個(gè)
Q3.什么是AIDL?
Q4.AIDL解決了什么問題?
Q5.AIDL如何使用?
Q6.線程池?Android線程有沒有上限?線程池有沒有上限?
1.Asynctask:異步任務(wù)類,單線程線程池+Handler
2.線程池:
1.ThreadPoolExecutor:通過Executors可以構(gòu)造單線程池、固定數(shù)目線程池、不固定數(shù)目線程池。
2.ScheduledThreadPoolExecutor:可以延時(shí)調(diào)用線程或者延時(shí)重復(fù)調(diào)度線程。
Q6.線程同步的問題,常用的線程同步?
1.sycn:保證了原子性、可見性、有序性
2.鎖:保證了原子性、可見性、有序性
1.自旋鎖:可以使線程在沒有取得鎖的時(shí)候,不被掛起,而轉(zhuǎn)去執(zhí)行一個(gè)空循環(huán)。
1.優(yōu)點(diǎn):線程被掛起的幾率減少,線程執(zhí)行的連貫性加強(qiáng)。用于對(duì)于鎖競(jìng)爭(zhēng)不是很激烈,鎖占用時(shí)間很短的并發(fā)線程。
2.缺點(diǎn):過多浪費(fèi)CPU時(shí)間,有一個(gè)線程連續(xù)兩次試圖獲得自旋鎖引起死鎖
2.阻塞鎖:沒得到鎖的線程等待或者掛起,Sycn、Lock
3.可重入鎖:一個(gè)線程可多次獲取該鎖,Sycn、Lock
4.悲觀鎖:每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以會(huì)阻塞全部其他線程 Sycn、Lock
5.樂觀鎖:每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。cas
6.顯示鎖和內(nèi)置鎖:顯示鎖用Lock來定義、內(nèi)置鎖用synchronized。
7.讀-寫鎖:為了提高性能,Java提供了讀
3.volatile
1.只能保證可見性,不能保證原子性
2.自增操作有三步,此時(shí)多線程寫會(huì)出現(xiàn)問題
4.cas
1.操作:內(nèi)存值V、舊的預(yù)期值A(chǔ)、要修改的值B,當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值修改為B并返回true,否則什么都不做并返回false。
2.解釋:本地副本為A,共享內(nèi)存為V,線程A要把V修改成B。某個(gè)時(shí)刻線程A要把V修改成B,如果A和V不同那么就表示有其他線程在修改V,此時(shí)就表示修改失敗,否則表示沒有其他線程修改,那么把V改成B。
3.局限:如果V被修改成V1然后又被改成V,此時(shí)cas識(shí)別不出變化,還是認(rèn)為沒有其他線程在修改V,此時(shí)就會(huì)有問題
4.局限解決:將V帶上版本。
5.線程不安全到底是怎么回事:
1.一個(gè)線程寫,多個(gè)線程讀的時(shí)候,會(huì)造成寫了一半就去讀
2.多線程寫,會(huì)造成臟數(shù)據(jù)
Q7.多進(jìn)程場(chǎng)景遇見過么?
Q8.Android進(jìn)程分類?
Q9.進(jìn)程和 Application 的生命周期?
Q10進(jìn)程調(diào)度?
Q11.談?wù)剬?duì)進(jìn)程共享和線程安全的認(rèn)識(shí)
Q12.談?wù)剬?duì)多進(jìn)程開發(fā)的理解以及多進(jìn)程應(yīng)用場(chǎng)景
Q13.什么是協(xié)程?
Q13.操作系統(tǒng)進(jìn)程和線程的區(qū)別?
1.簡而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.
2.線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。
3.另外,進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。
4.多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用,來實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配
Q14.自定義View如何提供獲取View屬性的接口?
Q15.介紹下SurfView?
Q15.RecycleView的使用及與ListView的區(qū)別?
Q15.LruCache默認(rèn)緩存大小?
Q16.ContentProvider的權(quán)限管理(解答:讀寫分離,權(quán)限控制-精確到表級(jí),URL控制)
Q17.Android為什么引入Parcelable?
Q18.ListView 中圖片錯(cuò)位的問題是如何產(chǎn)生的?
Q19.屏幕適配的處理技巧都有哪些?
Q20.怎么去除重復(fù)代碼?
Q21.Android中開啟攝像頭的主要步驟?
Q22.HTTP1.0與2.0的區(qū)別?HTTP與HTTPS的區(qū)別以及如何實(shí)現(xiàn)安全性?
1.ARP協(xié)議:在IP以太網(wǎng)中,當(dāng)一個(gè)上層協(xié)議要發(fā)包時(shí),有了該節(jié)點(diǎn)的IP地址,ARP就能提供該節(jié)點(diǎn)的MAC地址。
HTTP HTTPS的區(qū)別:
1.HTTPS使用TLS(SSL)進(jìn)行加密
2.HTTPS缺省工作在TCP協(xié)議443端口
3.它的工作流程一般如以下方式:
1.完成TCP三次同步握手
2.客戶端驗(yàn)證服務(wù)器數(shù)字證書,通過,進(jìn)入步驟3
3.DH算法協(xié)商對(duì)稱加密算法的密鑰、hash算法的密鑰
4.SSL安全加密隧道協(xié)商完成
5.網(wǎng)頁以加密的方式傳輸,用協(xié)商的對(duì)稱加密算法和密鑰加密,保證數(shù)據(jù)機(jī)密性;用協(xié)商的hash算法進(jìn)行數(shù)據(jù)完整性保護(hù),保證數(shù)據(jù)不被篡改
3.http請(qǐng)求包結(jié)構(gòu),http返回碼的分類,400和500的區(qū)別
1.請(qǐng)求:請(qǐng)求行、頭部、數(shù)據(jù)
2.返回:狀態(tài)行、頭部、數(shù)據(jù)
1.包結(jié)構(gòu):
2.http返回碼分類:1到5分別是,消息、成功、重定向、客戶端錯(cuò)誤、服務(wù)端錯(cuò)誤
4.Tcp
1.fin-c = x , 表示現(xiàn)在需要關(guān)閉c到s了。ack-c = y,表示上一條s的消息已經(jīng)接收完畢
2.ack-s = x + 1,表示需要關(guān)閉的fin-c消息已經(jīng)接收到了,同意關(guān)閉
3.fin-s = y + 1,表示s已經(jīng)準(zhǔn)備好關(guān)閉了,就等c的最后一條命令
4.ack-c = y + 1,表示c已經(jīng)關(guān)閉,讓s也關(guān)閉
1.三次握手:防止了服務(wù)器端的一直等待而浪費(fèi)資源,例如只是兩次握手,如果s確認(rèn)之后c就掉線了,那么s就會(huì)浪費(fèi)資源
1.syn-c = x,表示這消息是x序號(hào)
2.ack-s = x + 1,表示syn-c這個(gè)消息接收成功。syn-s = y,表示這消息是y序號(hào)。
3.ack-c = y + 1,表示syn-s這條消息接收成功
1.可靠連接,三次握手,四次揮手
2.四次揮手:TCP是全雙工模式
3.滑動(dòng)窗口,停止等待、后退N、選擇重傳
4.擁塞控制,慢啟動(dòng)、擁塞避免、加速遞減、快重傳快恢復(fù)
TCP與UDP區(qū)別總結(jié):
1、TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接
2、TCP提供可靠的服務(wù)。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付,即不保 證可靠交付
3、TCP面向字節(jié)流,實(shí)際上是TCP把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流;UDP是面向報(bào)文的
UDP沒有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會(huì)使源主機(jī)的發(fā)送速率降低(對(duì)實(shí)時(shí)應(yīng)用很有用,如IP電話,實(shí)時(shí)視頻會(huì)議等)
4、每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信
5、TCP首部開銷20字節(jié);UDP的首部開銷小,只有8個(gè)字節(jié)
6、TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道
Q23.談?wù)勀銓?duì)WebSocket的理解?WebSocket與socket的區(qū)別?
Q24.談?wù)勀銓?duì)安卓簽名的理解。請(qǐng)解釋安卓為啥要加簽名機(jī)制?
Q25.App 是如何沙箱化,為什么要這么做?
Q26.談?wù)剬?duì)java狀態(tài)機(jī)理解
Q27.Fragment如果在Adapter中使用應(yīng)該如何解耦?
Q28.Binder機(jī)制及底層實(shí)現(xiàn)
Q29.對(duì)于應(yīng)用更新這塊是如何做的?(解答:灰度,強(qiáng)制更新,分區(qū)域更新)?
Q30.AlertDialog,popupWindow,Activity區(qū)別?
1.Window用于顯示View和接收各種事件,Window有三種類型:應(yīng)用Window(每個(gè)Activity對(duì)應(yīng)一個(gè)Window)、子Window(不能單獨(dú)存在,附屬于特定Window)、系統(tǒng)window(Toast和狀態(tài)欄)
2.Window分層級(jí),應(yīng)用Window在1-99、子Window在1000-1999、系統(tǒng)Window在2000-2999.WindowManager提供了增刪改View三個(gè)功能。
3.Window是個(gè)抽象概念:每一個(gè)Window對(duì)應(yīng)著一個(gè)View和ViewRootImpl,Window通過ViewRootImpl來和View建立聯(lián)系,View是Window存在的實(shí)體,只能通過WindowManager來訪問Window。
4.WindowManager的實(shí)現(xiàn)是WindowManagerImpl其再委托給WindowManagerGlobal來對(duì)Window進(jìn)行操作,其中有四個(gè)List分別儲(chǔ)存對(duì)應(yīng)的View、ViewRootImpl、WindowManger.LayoutParams和正在被刪除的View
5.Window的實(shí)體是存在于遠(yuǎn)端的WindowMangerService中,所以增刪改Window在本端是修改上面的幾個(gè)List然后通過ViewRootImpl重繪View,通過WindowSession(每個(gè)應(yīng)用一個(gè))在遠(yuǎn)端修改Window。
6.Activity創(chuàng)建Window:Activity會(huì)在attach()中創(chuàng)建Window并設(shè)置其回調(diào)(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy類創(chuàng)建PhoneWindow實(shí)現(xiàn)的。然后通過Activity#setContentView()調(diào)用PhoneWindow的setContentView。
Q31.Application 和 Activity 的 Context 對(duì)象的區(qū)別?
Q32.如何導(dǎo)入外部數(shù)據(jù)庫?
Q33.LinearLayout、RelativeLayout、FrameLayout的特性及對(duì)比,并介紹使用場(chǎng)景。?
Q34.回調(diào)的原理并談?wù)剬?duì)接口與回調(diào)的理解?
序列化的作用,以及Android兩種序列化的區(qū)別?
差值器
估值器
Android中數(shù)據(jù)存儲(chǔ)方式?
(三)數(shù)據(jù)庫
sqlite升級(jí),增加字段的語句
數(shù)據(jù)庫框架對(duì)比和源碼分析
數(shù)據(jù)庫的優(yōu)化
數(shù)據(jù)庫數(shù)據(jù)遷移問題
(四)算法
排序算法有哪些?
最快的排序算法是哪個(gè)?
手寫一個(gè)冒泡排序
手寫快速排序代碼
快速排序的過程、時(shí)間復(fù)雜度、空間復(fù)雜度
堆排序過程、時(shí)間復(fù)雜度及空間復(fù)雜度
寫出你所知道的排序算法及時(shí)空復(fù)雜度,穩(wěn)定性
二叉樹給出根節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn),找出從根節(jié)點(diǎn)到目標(biāo)節(jié)點(diǎn)的路徑
給阿里2萬多名員工按年齡排序應(yīng)該選擇哪個(gè)算法?
GC算法(各種算法的優(yōu)缺點(diǎn)以及應(yīng)用場(chǎng)景)?
1.搜索算法:
1.引用計(jì)數(shù)
2.圖搜索,可達(dá)性分析
2.回收算法:
1.標(biāo)記清除復(fù)制:用于青年代
2.標(biāo)記整理:用于老年代
3.堆分區(qū):
1.青年區(qū)eden 80%、survivor1 10%、survivor2 10%
2.老年區(qū)
4.虛擬機(jī)棧分區(qū):
1.局部變量表
2.操作數(shù)棧
3.動(dòng)態(tài)鏈接
4.方法返回地址
5.GC Roots:
1.虛擬機(jī)棧(棧楨中的本地變量表)中的引用的對(duì)象
2.方法區(qū)中的類靜態(tài)屬性引用的對(duì)象
3.方法區(qū)中的常量引用的對(duì)象
4.本地方法棧中JNI的引用的對(duì)象
蟻群算法與蒙特卡洛算法
子串包含問題(KMP 算法)寫代碼實(shí)現(xiàn)
一個(gè)無序,不重復(fù)數(shù)組,輸出N個(gè)元素,使得N個(gè)元素的和相加為M,給出時(shí)間復(fù)雜度、空間復(fù)雜度。手寫算法
(五)插件化、模塊化、組件化、熱修復(fù)、增量更新、Gradle
對(duì)熱修復(fù)和插件化的理解
插件化原理分析
模塊化實(shí)現(xiàn)(好處,原因)
熱修復(fù),插件化?
熱修復(fù):Andfix為例子
1.大致原理:apkpatch將兩個(gè)apk做一次對(duì)比,然后找出不同的部分。可以看到生成的apatch了文件,后綴改成zip再解壓開,里面有一個(gè)dex文件。通過jadx查看一下源碼,里面就是被修復(fù)的代碼所在的類文件,這些更改過的類都加上了一個(gè)_CF的后綴,并且變動(dòng)的方法都被加上了一個(gè)叫@MethodReplace的annotation,通過clazz和method指定了需要替換的方法。然后客戶端sdk得到補(bǔ)丁文件后就會(huì)根據(jù)annotation來尋找需要替換的方法。最后由JNI層完成方法的替換。
2.無法添加新類和新的字段、補(bǔ)丁文件很容易被反編譯、加固平臺(tái)可能會(huì)使熱補(bǔ)丁功能失效
插件化框架描述:dynamicLoadApk為例子
1.可以通過DexClassLoader來對(duì)apk中的dex包進(jìn)行加載訪問
2.如何加載資源是個(gè)很大的問題,因?yàn)樗拗鞒绦蛑胁]有apk中的資源,所以調(diào)用R資源會(huì)報(bào)錯(cuò),所以這里使用了Activity中的實(shí)現(xiàn)ContextImpl的getAssets()和getResources()再加上反射來實(shí)現(xiàn)。
3.由于系統(tǒng)啟動(dòng)Activity有很多初始化動(dòng)作要做,而我們手動(dòng)反射很難完成,所以可以采用接口機(jī)制,將Activity的大部分生命周期提取成接口,然后通過代理Activity去調(diào)用插件Activity的生命周期。同時(shí)如果像增加一個(gè)新生命周期方法的時(shí)候,只需要在接口中和代理中聲明一下就行。
4.缺點(diǎn):
1.慎用this,因?yàn)樵赼pk中使用this并不代表宿主中的activity,當(dāng)然如果this只是表示自己的接口還是可以的。除此之外可以使用that代替this。
2.不支持Service和靜態(tài)注冊(cè)的Broadcast
3.不支持LaunchMode和Apk中Activity的隱式調(diào)用。
項(xiàng)目組件化的理解
描述清點(diǎn)擊 Android Studio 的 build 按鈕后發(fā)生了什么
(六)架構(gòu)設(shè)計(jì)和設(shè)計(jì)模式
談?wù)勀銓?duì)Android設(shè)計(jì)模式的理解
MVC MVP MVVM原理和區(qū)別
你所知道的設(shè)計(jì)模式有哪些?
談?wù)剬?duì)RxJava的理解
RxJava的功能與原理實(shí)現(xiàn)
RxJava的作用,與平時(shí)使用的異步操作來比的優(yōu)缺點(diǎn)
說說EventBus作用,實(shí)現(xiàn)方式,代替EventBus的方式
Retrofit的了解?
1.動(dòng)態(tài)代理創(chuàng)建一個(gè)接口的代理類
2.通過反射解析每個(gè)接口的注解、入?yún)?gòu)造http請(qǐng)求
3.獲取到返回的http請(qǐng)求,使用Adapter解析成需要的返回值。
從0設(shè)計(jì)一款A(yù)pp整體架構(gòu),如何去做?
(七)性能優(yōu)化
如何對(duì)Android 應(yīng)用進(jìn)行性能分析以及優(yōu)化?
ddms 和 traceView
性能優(yōu)化如何分析systrace?
用IDE如何分析內(nèi)存泄漏?
Java多線程引發(fā)的性能問題,怎么解決?
啟動(dòng)頁白屏及黑屏解決?
啟動(dòng)太慢怎么解決?
(八)NDK、jni、Binder、AIDL、進(jìn)程通信有關(guān)
請(qǐng)介紹一下NDK
什么是NDK庫?
jni用過嗎?
如何在jni中注冊(cè)native函數(shù),有幾種注冊(cè)方式?
Java如何調(diào)用c、c++語言?
jni如何調(diào)用java層代碼?
(九)framework層、ROM定制、Ubuntu、Linux之類的問題
java虛擬機(jī)的特性
談?wù)剬?duì)jvm的理解
JVM內(nèi)存區(qū)域,開線程影響哪塊內(nèi)存
對(duì)Dalvik、ART虛擬機(jī)有什么了解?
Art和Dalvik對(duì)比
虛擬機(jī)原理,如何自己設(shè)計(jì)一個(gè)虛擬機(jī)(內(nèi)存管理,類加載,雙親委派)
談?wù)勀銓?duì)雙親委派模型理解
JVM內(nèi)存模型,內(nèi)存區(qū)域
Java類加載機(jī)制?
1.加載時(shí)機(jī):創(chuàng)建實(shí)例、訪問靜態(tài)變量或方法、反射、加載子類之前
2.驗(yàn)證:驗(yàn)證文件格式、元數(shù)據(jù)、字節(jié)碼、符號(hào)引用的正確性
3.加載:根據(jù)全類名獲取文件字節(jié)流、將字節(jié)流轉(zhuǎn)化為靜態(tài)儲(chǔ)存結(jié)構(gòu)放入方法區(qū)、生成class對(duì)象
4.準(zhǔn)備:在堆上為靜態(tài)變量劃分內(nèi)存
5.解析:將常量池中的符號(hào)引用轉(zhuǎn)換為直接引用
6.初始化:初始化靜態(tài)變量
7.書籍推薦:深入理解java虛擬機(jī),博客推薦:Java/Android阿里面試JVM部分理解
談?wù)剬?duì)ClassLoader(類加載器)的理解?
1.雙親委托:一個(gè)ClassLoader類負(fù)責(zé)加載這個(gè)類所涉及的所有類,在加載的時(shí)候會(huì)判斷該類是否已經(jīng)被加載過,然后會(huì)遞歸去他父ClassLoader中找。
2.可以動(dòng)態(tài)加載Jar通過URLClassLoader
3.ClassLoader 隔離問題 JVM識(shí)別一個(gè)類是由:ClassLoader id+PackageName+ClassName。
4.加載不同Jar包中的公共類:
1.讓父ClassLoader加載公共的Jar,子ClassLoader加載包含公共Jar的Jar,此時(shí)子ClassLoader在加載公共Jar的時(shí)候會(huì)先去父ClassLoader中找。(只適用Java)
2.重寫加載包含公共Jar的Jar的ClassLoader,在loadClass中找到已經(jīng)加載過公共Jar的ClassLoader,也就是把父ClassLoader替換掉。(只適用Java)
3.在生成包含公共Jar的Jar時(shí)候把公共Jar去掉。
談?wù)剬?duì)動(dòng)態(tài)加載(OSGI)的理解
內(nèi)存對(duì)象的循環(huán)引用及避免
內(nèi)存回收機(jī)制、GC回收策略、GC原理時(shí)機(jī)以及GC對(duì)象
垃圾回收機(jī)制與調(diào)用System.gc()區(qū)別
系統(tǒng)啟動(dòng)流程是什么?(提示:Zygote進(jìn)程 –> SystemServer進(jìn)程 –> 各種系統(tǒng)服務(wù) –> 應(yīng)用進(jìn)程)
大體說清一個(gè)應(yīng)用程序安裝到手機(jī)上時(shí)發(fā)生了什么
簡述Activity啟動(dòng)全部過程
App啟動(dòng)流程,從點(diǎn)擊桌面開始
邏輯地址與物理地址,為什么使用邏輯地址?
Android為每個(gè)應(yīng)用程序分配的內(nèi)存大小是多少?
Android中進(jìn)程內(nèi)存的分配,能不能自己分配定額內(nèi)存?
進(jìn)程?;畹姆绞?br>
如何保證一個(gè)后臺(tái)服務(wù)不被殺死?(相同問題:如何保證service在后臺(tái)不被kill?)比較省電的方式是什么?
App中喚醒其他進(jìn)程的實(shí)現(xiàn)方式
Q29.APK打包流程和其內(nèi)容
1.流程
1.aapt生成R文件
2.aidl生成java文件
3.將全部java文件編譯成class文件
4.將全部class文件和第三方包合并成dex文件
5.將資源、so文件、dex文件整合成apk
6.apk簽名
7.apk字節(jié)對(duì)齊
2.內(nèi)容:so、dex、asset、資源文件
apk瘦身:
1.classes.dex:通過代碼混淆,刪掉不必要的jar包和代碼實(shí)現(xiàn)該文件的優(yōu)化
2.資源文件:通過Lint工具掃描代碼中沒有使用到的靜態(tài)資源
3.圖片資源:使用tinypng和webP,下面詳細(xì)介紹圖片資源優(yōu)化的方案,矢量圖
4.SO文件將不用的去掉,目前主流app一般只放一個(gè)arm的so包
@.Sharedpreferences源碼簡述
1.儲(chǔ)存于硬盤上的xml鍵值對(duì),數(shù)據(jù)多了會(huì)有性能問題
2.ContextImpl記錄著SharedPreferences的重要數(shù)據(jù),文件路徑和實(shí)例的鍵值對(duì)
3.在xml文件全部內(nèi)加載到內(nèi)存中之前,讀取操作是阻塞的,在xml文件全部內(nèi)加載到內(nèi)存中之后,是直接讀取內(nèi)存中的數(shù)據(jù)
4.apply因?yàn)槭钱惒降臎]有返回值, commit是同步的有返回值能知道修改是否提交成功
5.多并發(fā)的提交commit時(shí),需等待正在處理的commit數(shù)據(jù)更新到磁盤文件后才會(huì)繼續(xù)往下執(zhí)行,從而降低效率; 而apply只是原子更新到內(nèi)存,后調(diào)用apply函數(shù)會(huì)直接覆蓋前面內(nèi)存數(shù)據(jù),從一定程度上提高很多效率。 3.edit()每次都是創(chuàng)建新的EditorImpl對(duì)象.
58.瀏覽器輸入地址到返回結(jié)果發(fā)生了什么
1.DNS解析
2.TCP連接
3.發(fā)送HTTP請(qǐng)求
4.服務(wù)器處理請(qǐng)求并返回HTTP報(bào)文
5.瀏覽器解析渲染頁面
6.連接結(jié)束
59.java泛型類型擦除發(fā)生在什么時(shí)候,通配符有什么需要注意的。
1.發(fā)生在編譯的時(shí)候
2.PECS,extends善于提供精確的對(duì)象 A是B的子集,Super善于插入精確的對(duì)象 A是B的超集
3.博客推薦:Effective Java筆記(不含反序列化、并發(fā)、注解和枚舉)、android阿里面試java基礎(chǔ)錦集
61.面試??嫉乃惴?/p>
1.快排、堆排序?yàn)槭椎母鞣N排序算法
2.鏈表的各種操作:判斷成環(huán)、判斷相交、合并鏈表、倒數(shù)K個(gè)節(jié)點(diǎn)、尋找成環(huán)節(jié)點(diǎn)
3.二叉樹、紅黑樹、B樹定義以及時(shí)間復(fù)雜度計(jì)算方式
4.動(dòng)態(tài)規(guī)劃、貪心算法、簡單的圖論
5.推薦書籍:算法導(dǎo)論,將圖論之前的例子寫一遍
62.Launcher進(jìn)程啟動(dòng)另外一個(gè)進(jìn)程的過程:啟動(dòng)一個(gè)app
63.開源框架源碼
1.Fresco
1.mvc框架:
1.Controller控制數(shù)據(jù)顯示在Hierarchy中的Drawable的顯隱
2.ImagePipeline在Controller中負(fù)責(zé)進(jìn)行數(shù)據(jù)獲取,返回的數(shù)據(jù)是CloseableImage
3.Drawee把除了初始化之外的操作全部交給Holder去做,Holder持有Controller和Hierarchy
2.Drawable層次以及繪制:
1.如果要繪制一次Drawable就調(diào)用invalidateSelf()來觸發(fā)onDraw()
2.Drawable分為:容器類(保存一些Drawable)、自我繪制類(進(jìn)度條)、圖形變換類(scale、rotate、矩陣變換)、動(dòng)畫類(內(nèi)部不斷刷新,進(jìn)行webp和gif的幀繪制)
3.ImagePipeline返回的CloseableImage是由一個(gè)個(gè)DrawableFactory解析成Drawable的
4.webp和gif動(dòng)畫是由jni代碼解析的,然后其他靜態(tài)圖片是根據(jù)不同的android平臺(tái)使用BitmapFactory來解析的
3.職責(zé)鏈模式:producer不做操作標(biāo)n,表示只是提供一個(gè)consumer。獲取圖片—》解碼圖片緩存Producer—》后臺(tái)線程Producer—》client圖片處理producer(n)—》解碼producer(n)—》旋轉(zhuǎn)或剪裁producer(n)—》編碼圖片內(nèi)存緩存producer—》讀硬盤緩存producer—》寫硬盤緩存producer(n)—》網(wǎng)絡(luò)producer提供CloseableImage《—解碼圖片緩存consumer《—client圖片處理consumer《—解碼consumer《—旋轉(zhuǎn)或剪裁consumer《—編碼圖片內(nèi)存緩存consumer《—寫硬盤緩存consumer《—圖片數(shù)據(jù)
4.內(nèi)存緩存:
1.一個(gè)CountingLruMap保存已經(jīng)沒有被引用的緩存條目,一個(gè)CountingLruMap保存所有的條目包括沒有引用的條目。每當(dāng)緩存策略改變和一定時(shí)間緩存配置的更新的時(shí)候,就會(huì)將 待銷毀條目Map中的條目一個(gè)個(gè)移除,直到緩存大小符合配置。
2.這里的引用計(jì)數(shù)是用Fresco組件實(shí)現(xiàn)的引用計(jì)數(shù)器。
3.緩存有一個(gè)代理類,用來追蹤緩存的存取。
4.CountingLruMap是使用LinkedHashMap來儲(chǔ)存數(shù)據(jù)的。
5.硬盤緩存:
1.DefaultDiskStorage使用Lru策略。
2.為了不讓所有的文件集中在一個(gè)文件中,創(chuàng)建很多命名不同的文件夾,然后使用hash算法把緩存文件分散
3.DiskStorageCache封裝了DefaultDiskStorage,不僅進(jìn)行緩存存取追蹤,并且其在內(nèi)存里面維持著一個(gè)
的鍵值對(duì),因?yàn)槲募薷念l繁,所有只是定時(shí)刷新,因此如果在內(nèi)存中找不到,還要去硬盤中找一次。
4.刪除硬盤的緩存只出現(xiàn)在硬盤數(shù)據(jù)大小超限的時(shí)候,此時(shí)同時(shí)也會(huì)刪除緩存中的key,所以不會(huì)出現(xiàn)內(nèi)存中有key,但是硬盤上沒有的情況。
5.在插入硬盤數(shù)據(jù)的時(shí)候,采用的是插入器的形式。返回一個(gè)Inserter,在Inserter.writeData()中傳入一個(gè)CallBack(里面封裝了客戶端插入數(shù)據(jù)的邏輯和文件引用),讓內(nèi)部實(shí)現(xiàn)調(diào)用CallBack的邏輯來插入文件數(shù)據(jù),前面寫的文件后綴是.temp,只有調(diào)用commit()之后才會(huì)修改后綴,讓文件對(duì)客戶端可見。
6.使用了java提供的FileTreeVisitor來遍歷文件
6.對(duì)象池:
1.使用數(shù)組來存儲(chǔ)一個(gè)桶,桶內(nèi)部是一個(gè)Queue。數(shù)組下標(biāo)是數(shù)據(jù)申請(qǐng)內(nèi)存的byte大小,桶內(nèi)部的Queue存的是內(nèi)存塊的。所以數(shù)組使用的是稀疏數(shù)組
2.申請(qǐng)內(nèi)存的方式有兩種 1.java堆上開辟的內(nèi)存 2.ashme 的本地內(nèi)存中開辟的內(nèi)存
7.設(shè)計(jì)模式:Builder、職責(zé)鏈、觀察者、代理、組合、享元、適配器、裝飾者、策略、生產(chǎn)者消費(fèi)者、提供者
8.自定義計(jì)數(shù)引用:類似c++智能指針
1.使用一個(gè)靜態(tài)IdentityHashMap <儲(chǔ)存需要被計(jì)數(shù)引用的對(duì)象,其被引用的次數(shù)>
2.用SharedReference分裝需要被計(jì)數(shù)引用的對(duì)象,提供一個(gè)銷毀資源的銷毀器,提供一個(gè)靜態(tài)工廠方法來復(fù)制自己,復(fù)制一個(gè)引用計(jì)數(shù)加一。提供一個(gè)方法銷毀自己,表示自己需要變成無人引用的對(duì)象了,此時(shí)引用計(jì)數(shù)減一。
3.引用計(jì)數(shù)歸零,銷毀器將銷毀資源,如bitmap的recycle或者是jni內(nèi)存調(diào)用jni方法歸還內(nèi)存。
9.博客推薦:Android Fresco源碼文檔翻譯、從零開始擼一個(gè)Fresco之硬盤緩存、從零開始擼一個(gè)Fresco之gif和Webp動(dòng)畫、從零開始擼一個(gè)Fresco之內(nèi)存緩存、從零開始擼一個(gè)Fresco之總結(jié)
2.oKhttp:
1.同步和異步:
1.異步使用了Dispatcher來將存儲(chǔ)在 Deque 中的請(qǐng)求分派給線程池中各個(gè)線程執(zhí)行。
2.當(dāng)任務(wù)執(zhí)行完成后,無論是否有異常,finally代碼段總會(huì)被執(zhí)行,也就是會(huì)調(diào)用Dispatcher的finished函數(shù),它將正在運(yùn)行的任務(wù)Call從隊(duì)列runningAsyncCalls中移除后,主動(dòng)的把緩存隊(duì)列向前走了一步。
2.連接池:
1.一個(gè)Connection封裝了一個(gè)socket,ConnectionPool中儲(chǔ)存s著所有的Connection,StreamAllocation是引用計(jì)數(shù)的一個(gè)單位
2.當(dāng)一個(gè)請(qǐng)求獲取一個(gè)Connection的時(shí)候要傳入一個(gè)StreamAllocation,Connection中存著一個(gè)弱引用的StreamAllocation列表,每當(dāng)上層應(yīng)用引用一次Connection,StreamAllocation就會(huì)加一個(gè)。反之如果上層應(yīng)用不使用了,就會(huì)刪除一個(gè)。
3.ConnectionPool中會(huì)有一個(gè)后臺(tái)任務(wù)定時(shí)清理StreamAllocation列表為空的Connection。5分鐘時(shí)間,維持5個(gè)socket
3.選擇路線與建立連接
1.連接池中已經(jīng)存在連接,就從中取出(get)RealConnection,如果沒有命中就進(jìn)入下一步
2.根據(jù)選擇的路線(Route),調(diào)用Platform.get().connectSocket選擇當(dāng)前平臺(tái)Runtime下最好的socket庫進(jìn)行握手
3.將建立成功的RealConnection放入(put)連接池緩存
4.如果存在TLS,就根據(jù)SSL版本與證書進(jìn)行安全握手
5.構(gòu)造HttpStream并維護(hù)剛剛的socket連接,管道建立完成
1.無代理,那么在本地使用DNS查找到ip,注意結(jié)果是數(shù)組,即一個(gè)域名有多個(gè)IP,這就是自動(dòng)重連的來源
2.有代理HTTP:設(shè)置socket的ip為代理地址的ip,設(shè)置socket的端口為代理地址的端口
3.代理好處:HTTP代理會(huì)幫你在遠(yuǎn)程服務(wù)器進(jìn)行DNS查詢,可以減少DNS劫持。
1.選擇路線有兩種方式:
2.建立連接
4.職責(zé)鏈模式:緩存、重試、建立連接等功能存在于攔截器中網(wǎng)絡(luò)請(qǐng)求相關(guān),主要是網(wǎng)絡(luò)請(qǐng)求優(yōu)化。網(wǎng)絡(luò)請(qǐng)求的時(shí)候遇到的問題
5.博客推薦:Android數(shù)據(jù)層架構(gòu)的實(shí)現(xiàn) 上篇、Android數(shù)據(jù)層架構(gòu)的實(shí)現(xiàn) 下篇
3.okio
1.簡介;
1.sink:自己—》別人
2.source:別人—》自己
3.BufferSink:有緩存區(qū)域的sink
4.BufferSource:有緩存區(qū)域的source
5.Buffer:實(shí)現(xiàn)了3、4的緩存區(qū)域,內(nèi)部有Segment的雙向鏈表,在在轉(zhuǎn)移數(shù)據(jù)的時(shí)候,只需要將指針轉(zhuǎn)移指向就行
2.比java io的好處:
1.減少內(nèi)存申請(qǐng)和數(shù)據(jù)拷貝
2.類少,功能齊全,開發(fā)效率高
3.內(nèi)部實(shí)現(xiàn):
1.Buffer的Segment雙向鏈表,減少數(shù)據(jù)拷貝
2.Segment的內(nèi)部byte數(shù)組的共享,減少數(shù)據(jù)拷貝
3.SegmentPool的共享和回收Segment
4.sink和source中被實(shí)際操作的其實(shí)是Buffer,Buffer可以充當(dāng)sink和source
5.最終okio只是對(duì)java io的封裝,所有操作都是基于java io 的