這裏講的是大公司須要用到的一些高端Android技術,這裏專門整理了一個文檔,但願你們均可以看看。這些題目有點技術含量,須要好點時間去研究一下的。java
爲此我吧這些知識整理成了一個983的PDF,從基礎到進階。含有BATJ.字節跳動面試專題,算法專題,高端技術專題,混合開發專題,java面試專題,Android,Java小知識,到性能優化.線程.View.OpenCV.NDK等應有盡有。還有輔之相關的視頻+學習筆記
android
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
能夠點擊
github.com/xiangjiana/…c++獲取完整PDFgit
LruCache
是個泛型類,主要原理是:把最近使用的對象用強引用存儲在LinkedHashMap
中,當緩存滿時,把最近最少使用的對象從內存中移除,並提供get/put方法完成緩存的獲取和添加。LruCache
是線程安全的,由於使用了synchronized關鍵字。github
當調用put()方法,將元素加到鏈表頭,若是鏈表中沒有該元素,大小不變,若是沒有,需調用trimToSize方法判斷是否超過最大緩存量,trimToSize()方法中有一個while(true)死循環,若是緩存大小大於最大的緩存值,會不斷刪除LinkedHashMap中隊尾的元素,即最少訪問的,直到緩存大小小於最大緩存值。當調用LruCache的get方法時,LinkedHashMap會調用recordAccess方法將此元素加到鏈表頭部。面試
1)Glide.with(context)建立了一個RequestManager
,同時實現加載圖片與組件生命週期綁定:在Activity上建立一個透明的ReuqestManagerFragment
加入到FragmentManager
中,經過添加的Fragment感知Activty
`Fragment的生命週期。由於添加到Activity中的Fragment會跟隨Activity的生命週期。在
RequestManagerFragment中的相應生命週期方法中經過
liftcycle傳遞給在
lifecycle中註冊的
LifecycleListener`算法
2)RequestManager.load(url)
建立了一個RequestBuilder<T>
對象 T能夠是Drawable
對象或是ResourceType
等sql
3 )RequestBuilder.into(view)
-->into(glideContext.buildImageViewTarget(view, transcodeClass))
返回的是一個DrawableImageViewTarget
, Target用來最終展現圖片的,buildImageViewTarget
-->ImageViewTargetFactory.buildTarget()
根據傳入class參數不一樣構建不一樣的Target對象,這個Class是根據構建Glide時是否調用了asBitmap()
方法,若是調用了會構建出BitmapImageViewTarget
,不然構建的是GlideDrawableImageViewTarget
對象。數據庫
-->GenericRequestBuilder.into(Target)
,該方法進行了構建Request,並用RequestTracker.runRequest()
編程
Request request = buildRequest(target);//構建Request對象,Request是用來發出加載圖片的,它調用了buildRequestRecursive()方法以,內部調用了GenericRequest.obtain()方法
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);//判斷Glide當前是否是處於暫停狀態,若不是則調用Request.begin()方法來執行Request,不然將Request添加到待執行隊列裏,等暫停態解除了後再執行
複製代碼
-->GenericRequest.begin()
4)onSizeReady()·--> Engine.load(signature
, width
,height
, dataFetcher
, loadProvider
, transformation
, transcoder
,
priority, isMemoryCacheable
,diskCacheStrategy
, this) --> a)先構建EngineKey
; b)loadFromCache
從緩存中獲取EngineResource
,若是緩存中獲取到cache就調用cb.onResourceReady(cached)
; c)若是緩存中不存在調用loadFromActiveResources
從active中獲取,若是獲取到就調用cb.onResourceReady(cached)
;d)若是active中也不存在,調用EngineJob.start(EngineRunnable)
, 從而調用decodeFromSource()
/decodeFromCache()
-->若是是調用decodeFromSource()
-->ImageVideoFetcher.loadData()
-->HttpUrlFetcher()
調用HttpUrlConnection
進行網絡請求資源-->得於InputStream()
後,調用decodeFromSourceData()
-->loadProvider.getSourceDecoder().decode()
方法解碼-->GifBitmapWrapperResourceDecoder.decode()
-->decodeStream()
先從流中讀取2個字節判斷是GIF仍是普通圖,如果GIF調用decodeGifWrapper()
來解碼,如果普通靜圖則調用decodeBitmapWrapper()
來解碼-->bitmapDecoder.decode()
1) 內存緩存:LruResourceCache(memory)+
弱引用activeResources
Map<Key, WeakReference
<EngineResource
<?>>> activeResources
正在使用的資源,當acquired變量大於0,說明圖片正在使用,放到activeResources
弱引用緩存中,通過release()後,acquired=0,說明圖片再也不使用,會把它放進LruResourceCache
中
2)磁盤緩存:DiskLruCache
,這裏分爲Source(原始圖片)和Result(轉換後的圖片)
第一次獲取圖片,確定網絡取,而後存active\disk中,再把圖片顯示出來,第二次讀取相同的圖片,並加載到相同大小的imageview
中,會先從memory中取,沒有再去active中獲取。若是activity執行到onStop
時,圖片被回收,active中的資源會被保存到memory中,active中的資源被回收。當再次加載圖片時,會從memory中取,再放入active中,並將memory中對應的資源回收。
之因此須要activeResources
,它是一個隨時可能被回收的資源,memory的強引用頻繁讀寫可能形成內存激增頻繁GC
,而形成內存抖動。資源在使用過程當中保存在activeResources
中,而activeResources
是弱引用,隨時被系統回收,不會形成內存過多使用和泄漏。
Glide內存緩存最大空間(maxSize)=每一個進程可用最大內存
磁盤緩存大小是250MB int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
(1)網絡緩存優先考慮強制緩存,再考慮對比緩存
(2)okhttp緩存
開啓使用Okhttp的緩存其實很簡單,只須要給OkHttpClient
對象設置一個Cache對象便可,建立一個Cache時指定緩存保存的目錄和緩存最大的大小便可。
//新建一個cache,指定目錄爲外部目錄下的okhttp_cache目錄,大小爲100M
Cache cache = new Cache(new File(Environment.getExternalStorageDirectory() + "/okhttp_cache/"), 100 * 1024 * 1024);
//將cache設置到OkHttpClient中,這樣緩存就開始生效了。
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
複製代碼
相關的類有:
1)CacheControl( HTTP中的Cache-Control和Pragma緩存控制):指定緩存規則
2)Cache(緩存類)
3)DiskLruCache(文件化的LRU緩存類)
(1)讀取緩存:先獲限OkHttpClient
的Cache緩存對象,就是上面建立OkHttpClient
設置的Cahce
; 傳Request請求到Cache的get方法查找緩存響應數據Response;構造一個緩存策略,再調用它的get去決策使用網絡請求仍是緩存響應。若使用緩存,它的cacheResponse
不爲空,networkRequest
爲空,用緩存構造響應直接返回。若使用請求,則cacheResponse
爲空,networkRequest
不爲空,開始網絡請求流程。
Cache的get獲取緩存方法,計算request的key值(請求url進行md5加密),根據key值去DisLruCache查找是否存在緩存內容,存則則建立繪存Entry實體。ENTRY_METADATA表明響應頭信息,ENTRY_BODY表明響應體信息。若是緩存存在,在指定目錄下會有兩個文件****.0 *****.1分別存儲某個請求緩存響應頭和響應體信息。
CacheStrategy的get方法:
(2)存儲緩存流程:從HttpEngine
的readResponse()
發送請求開始,判斷hasBody(userResponse)
,若是緩存的話,maybeCache()
緩存響應頭信息,unzip(cacheWritingResponse(storeRequest, userResponse))
緩存響應體。
一張圖片(bitmap)佔用的內存影響因素:圖片原始長、寬,手機屏幕密度,圖片存放路徑下的密度,單位像素佔用字節數
bitmapSize=圖片長度
1)圖片長寬單位是像素:單位像素字節數由其參數BitmapFactory.Options.inPreferredConfig
變量決定,它是Bitmap.Config類型,包括如下幾種值:ALPHA_8圖片只有alpha值,佔用一個字節;ARGB_4444
一個像素佔用2個字節,A\R\G\B各佔4bits
;ARGB_8888
一個像素佔用4個字節,A\R\G\B各佔8bits
(高質量圖片格式,bitmap默認格式);ARGB_565
一個像素佔用2字節,不支持透明和半透明,R佔5bit
, Green佔6bit
, Blue佔用5bit
. 從Android4.0
開始該項無效。
2)inTargetDensity
手機的屏幕密度(跟手機分辨率有關係)
inDensity
原始資源密度(mdpi:160
; hdpi:240
; xhdpi:320
; xxhdpi:480
; xxxhdpi:640
)
當Bitmap對象在不使用時,應該先調用recycle(),再將它設置爲null,雖然Bitmap在被回收時可經過BitmapFinalizer
來回收內存。但只有系統垃圾回收時纔會回收。Android4.0
以前,Bitmap內存分配在Native堆中,Android4.0
開始,Bitmap的內存分配在dalvik
堆中,即Java堆中,調用recycle()並不能當即釋放Native內存。
RxJava
是基於響應式編程,基於事件流、實現異步操(相似於Android中的AsyncTask
、Handler
做用)做的庫,基於事件流的鏈式調用,使得RxJava
邏輯簡潔、使用簡單。RxJava
原理是基於一種擴展的觀察者模式,有四種角色:被觀察者Observable 觀察者Observer 訂閱subscribe 事件Event。RxJava
原理可總結爲:被觀察者Observable經過訂閱(subscribe)按順序發送事件(Emitter)給觀察者(Observer), 觀察者按順序接收事件&做出相應的響應動做。
RxJava
中的操做符:
1)defer():直到有觀察者(Observer)訂閱時,纔會動態建立被觀察者對象(Observer)&發送事件,經過Observer工廠方法建立被觀察者對象,每次訂閱後,都會獲得一個剛建立的最新的Observer對象,能夠確保Observer對象裏的數據是最新的。defer()方法只會定義Observable對象,只有訂閱操做纔會建立對象。
Observable<T> observable = Observable.defer(new Callable<ObservableSource<? extends T>>() {
@Override
public ObservableSource<? extends T> call() throws Exception {
return Observable.just();
}
}
複製代碼
2)timer() 快速建立一個被觀察者(Observable),延遲指定時間後,再發送事件
Observable.timer(2, TimeUnit.SECONDS)//也能夠自定義線程timer(long, TimeUnit, Scheduler)
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(Disposable d) {
}
...
});
複製代碼
3) interval() intervalRange() 快速建立一個被觀察者對象(Observable),每隔指定時間就發送事件
//interval三個參數,參數1:第一次延遲時間 參數2:間隔時間數字 參數3:時間單位
Observable.interval(3, 1, TimeUnit.SECONDS).subscribe();
//intervalRange五個參數,參數1:事件序列起始點 參數2:事件數量 參數3:第一次延遲時間 參數4:間隔時間數字 參數5:時間單位
Observable.intervalRange(3, 10, 2, 1, TimeUnit.SECONDS).subscribe();
RxJava的功能與原理實現
複製代碼
1)建立被觀察者對象Observable&定義須要發送的事件
Observable.create(new ObservableOnSubscribe<T>(){
@Override
public void subscribe(ObservableEmitter<T> emitter) throws Exception {
//定義發送事件的行爲
}
});
複製代碼
Observable.create()方法實際建立了一個ObservableCreate
對象,它是Observable的子類,傳入一個ObservableOnSubscrib
e對象,複寫了發送事件行爲的subscribe()方法。
2)建立觀察者對象Observer&定義響應事件的行爲
Observer observer = new Observer<T>() {
@Override
public void onSubscribe(Disposable d){//Disposable對象可用於結束事件
//默認最早調用
}
@Override
public void onNext(T t){
}
@Override
public void onError(Throwable d){
}
@Override
public void onComplete(){
}
}
複製代碼
3)經過subscribe()方法使觀察者訂閱被觀察者
Observable.subscribe(Observer observer);//實際調用的是ObservableCreate.subscribeActual()方法,具體實現以下
protected void subscribeActual(Observer<? super T> observer) {
// 1. 建立1個CreateEmitter對象用於發射事件(封裝成1個Disposable對象)
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
// 2. 調用觀察者(Observer)的onSubscribe()
observer.onSubscribe(parent);
try {
// 3. 調用source對象的(ObservableOnSubscribe對象)subscribe()
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
複製代碼
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
能夠點擊
github.com/xiangjiana/…獲取完整PDF