這是啥

rxjava是如何實現(xiàn)線程切換的 glide對比其他圖片加載框架的優(yōu)勢 熱修復原理 kotlin協(xié)程 mvp mvc mvvm

object?.let 可以統(tǒng)一做判空處理,內(nèi)部可以用it代替操作的對象康震,返回值為函數(shù)最后一行或指定return表達式,如果最后一行為空就返回一個Unit類型的默認值

with(parm){} 不能統(tǒng)一做判空處理,方法內(nèi)傳入?yún)?shù)或?qū)ο箴懈叮绻詈笠粋€參數(shù)是個函數(shù),可以移到括號外部,內(nèi)部可以直接調(diào)用該對象的屬性或方法,返回值為最后一行或指定return表達式月褥。

object?.run 可以統(tǒng)一做判空處理栓票,可以說是let和with的結(jié)合,只接受一個lambda表達式挚躯,返回值為最后一行或指定return表達式感挥。

object?.apply{ object }? 可以統(tǒng)一做判空處理硼瓣,返回值是傳入對象的本身。多層判空的優(yōu)化〕曷耍可以函數(shù)鏈式調(diào)用

object.also{} 可以統(tǒng)一做判空處理,返回傳入對象的本身寓涨《⒋可用于擴展函數(shù)鏈式調(diào)用

also和apply的主要區(qū)別在于lambda表達式內(nèi)context表示方式,also的通過傳入的參數(shù)it來表示的戒良,而apply是通過this來表示的


Kotlin @JvmStatic 和@JvmFiled區(qū)別

1.@JvmField消除了變量的getter與setter方法
2.@JvmField修飾的變量不能是private屬性的
3.@JvmStatic只能在object類或者伴生對象companion object中使用体捏,而@JvmField沒有這些限制
4.@JvmStatic一般用于修飾方法,使方法變成真正的靜態(tài)方法韵洋;如果修飾變量不會消除變量的getter與setter方法痹届,但會使getter與setter方法和變量都變成靜態(tài)

不使用@JvmField的成員變量在java中調(diào)用需要
TestClass.INSTANCE.XXX 使用了就直接TestClass.XXX
不使用@JvmStatic修飾的方法在java中調(diào)用需要
TestClass.INSTACNE.xx()或者TestClass.Companion.xx() 使用了就直接TestClass.xx()


協(xié)程是一個輕量級的線程敛熬。GlobalScope.launch(Dispatchers.Default){ }

協(xié)程是一個輕量級的線程。GlobalScope.launch(Dispatchers.Default/Main/IO/Unconfined在調(diào)用的線程直接執(zhí)行){ } 線程是由系統(tǒng)調(diào)度的盐捷,阻塞和切換都會消耗CPU資源,阻塞時相當于一種資源的浪費,無法人為做控制形娇。協(xié)程的掛起不會阻塞線程,幾乎是無代價的焚刺,協(xié)程是由開發(fā)者控制的,一個線程可以創(chuàng)建任意個協(xié)程。協(xié)程代碼程序流是順序執(zhí)行的,不需要一堆回調(diào)函數(shù)诊沪,也可以手動執(zhí)行和結(jié)束盆顾,是可控的

協(xié)程體是一個suspend關(guān)鍵字修飾的一個無參,無返回值的函數(shù)類型厢呵,被suspend修飾的函數(shù)稱為掛起函數(shù)判哥,與之對應(yīng)的關(guān)鍵字是resume(恢復)

suspend 方法只能在協(xié)程里面調(diào)用,不能再協(xié)程外調(diào)用
suspend方法的本質(zhì)是異步返回(不是異步回調(diào))

runBlocking{ } 連接阻塞與非阻塞的世界茅撞。
runBlocking{}都可以在非協(xié)程作用域下創(chuàng)建一個協(xié)程作用域碍脏,在runBlocking作用域里面使用delay()會阻塞他的調(diào)用線程,直到他內(nèi)部都執(zhí)行完畢。runBlocking為協(xié)程的作用域,如果要在非協(xié)程作用域調(diào)用協(xié)程,可以用GlobalScope.launch{}

runBlocking{}和GlobalScope.launch{}的區(qū)別懈词?
GlobalScope.launch會啟動一個top-level的協(xié)程纺涤,他的生命周期將只受到整個應(yīng)用程序生命周期的影響。不會阻塞當前線程荞怒。
runBlocking{}協(xié)程作用域如果銷毀了洒琢,里面的協(xié)程也隨之失效,就好比變量的作用域褐桌。
runBlocking {}是創(chuàng)建一個新的協(xié)程同時阻塞當前線程衰抑,直到協(xié)程結(jié)束。

?withContext {}和async {}
withContext {}不會創(chuàng)建新的協(xié)程荧嵌,在指定協(xié)程上運行掛起代碼塊呛踊,并掛起該協(xié)程直至代碼塊運行完成。
CoroutineScope.async {}可以實現(xiàn)與 launch builder 一樣的效果啦撮,在后臺創(chuàng)建一個新協(xié)程谭网,唯一的區(qū)別是它有返回值,因為CoroutineScope.async {}返回的是 Deferred 類型

runBlocking{
? ? val job = launch{
????????}
? ? val job1? =? async{
? ? ? ? ? ? 10
????????}
? ? job1.await()
}
launch和async都可以在協(xié)程作用域下啟動協(xié)程赃春。

launch啟動一個協(xié)程后愉择,會返回一個job對象,這個job對象不含有任何數(shù)據(jù)织中。它只是表示啟動的協(xié)程本身锥涕,我們可以通過job對協(xié)程進行控制.
async依然返回一個job對象,但是這個對象可以帶上返回值,使用await()來獲取他的返回值狭吼。




okhttp源碼知識點

https://blog.csdn.net/json_it/article/details/78404010

證書問題:http://www.reibang.com/p/8a16ac7ee444

同步基本流程:

1.生成OkHttpClient层坠,可以通過new OkHttpClient.Builder(),也可以直接new OkHttpClient()刁笙。

2.生成Request破花,new Request.Builder().url("").build()。

3.okHttpClient.newCall(request).execute()疲吸;//同步?enqueue//異步

newCall(request) 生成一個Call座每,一個Call只能被執(zhí)行一次,RealCall實現(xiàn)了Call接口摘悴,對同步異步方法進行了實現(xiàn)尺栖,

同步生成的是RealCall對象,異步生成的是AsyncCall對象烦租,AsyncCall是runnable的子類

如果可以執(zhí)行延赌,則對當前請求添加監(jiān)聽操作除盏,然后將Call對象放入調(diào)度器Dispatcher中,最后由攔截器鏈中的各個攔截

器來對該請求進行處理挫以,最終返回Response者蠕。

Dispatcher調(diào)度器。

默認最大支持64個請求掐松,默認單個Host最大支持5個請求踱侣。

Dispatcher使用了一個Deque保存同步任務(wù),使用了兩個Deque保存異步任務(wù)大磺,兩個中一個是準備執(zhí)行的請求抡句,

另一個是正在執(zhí)行的請求。

為啥異步的是倆杠愧?

因為默認最大64個請求待榔,如果超過的話會先放到準備的Deque里,當有空閑線程時流济,再將ready的移到running里

攔截器鏈

各大攔截器:

retryAndFollowUpInterceptor锐锣、BridgeInterceptor、CacheInterceptor绳瘟、ConnectInterceptor雕憔、networkInterceptor、

CallServerInterceptor

將這些攔截器傳給了RealInterceptorChain(攔截器鏈)

retryAndFollowUpInterceptor:主要負責請求的重定向操作糖声,用于網(wǎng)絡(luò)請求中斤彼,請求失敗后的重試機制,如果是

路由或者連接異常蘸泻,則嘗試恢復琉苇,否則根據(jù)responseCode會對request進行再處理得到新的request。如果返回碼是

200就結(jié)束了蟋恬。

BridgeInterceptor:橋攔截器翁潘。主要負責為請求添加請求頭趁冈,為響應(yīng)添加響應(yīng)頭歼争。

CacheInterceptor:緩存攔截器。服務(wù)器收到請求時渗勘,會在200 OK中回送該資源的Last-Modified和ETag頭(前提

服務(wù)器支持緩存的情況下才有這倆)沐绒。客戶端將該資源保存在cache中旺坠,并記錄這兩個屬性乔遮。當客戶端發(fā)送相同請求

時,現(xiàn)根據(jù)Data+Cache Control來判斷緩存是否過期取刃,如果過期了蹋肮,會在請求中攜帶If-Modified-Since和If-None-

Match兩個頭出刷。分別對應(yīng)Last-Modified和ETag。

ConnectInterceptor:核心連接池坯辩,首先排除鏈接不可用的情況馁龟,如果鏈接可用就結(jié)束了。如果鏈接不可用會第一次連接池查找漆魔,如果沒找到會進行二次連接池查找坷檩,會判斷是否找到可用鏈接,如果沒找到會生成Connection對象改抡,連接Server(TCP+TLS handshake)矢炼,再將新的連接放入連接池,然后判斷是否是Http2連接阿纤,然后確認http2的多路復用特性句灌,

ConnectionPool中比較關(guān)鍵的幾個點,線程池(ThreadPoolExecutor)阵赠、隊列(Deque)涯塔、路由記錄表;
線程池:用于支持連接池的cleanup任務(wù)清蚀,清除idle線程匕荸;
隊列:存放待復用的連接;

Connection和Stream的關(guān)系枷邪,Http1.x是1:1的關(guān)系榛搔,而Http2是1對多的關(guān)系,就是說一個Http1.x的連接只能被一個請求使用东揣,而一個http2的連接是對應(yīng)多個Stream的践惑,多個Stream的意思是Http2連接支持并發(fā)請求,即一個連接可以被多個請求同時使用嘶卧。還有尔觉,Http1.1的keep-alive機制的作用是保證連接使用完不關(guān)閉,當下一次請求與連接的Host相同的時候芥吟,連接可以直接使用侦铜,不用再次創(chuàng)建(節(jié)省資源,提高了性能)钟鸵。

StreamAllocation:直譯就是流分配钉稍,流是什么呢?Connection是一個連接遠程服務(wù)器的物理Socket連接棺耍,而Stream則是基于Connection的邏輯Http請求/響應(yīng)對贡未。StreamAllocation會通過ConnectPool獲取或者新生成一個RealConnection來得到一個連接到Server的Connection連接。同時會生成一個HttpCodec用于下一個CallServerInterceptor,以完成最終請求俊卤。
一句話概括就是:分配一個Connection和HttpCodec嫩挤,為最終的請求做準備。

首先會排除連接不可用的情況消恍,判斷連接是否可用俐镐,
然后會第一次在連接池中進行查找(沒有提供路由信息),如果找到了就將連接賦給result
沒找到的話會遍歷路由表哺哼,進行第二次查找佩抹。
如果還沒有找到就只能創(chuàng)建新的連接了。
創(chuàng)建新連接連接到服務(wù)器(Socket連接)取董。
將新連接放入連接池棍苹。
如果是個Http2的連接,則確保多路復用性茵汰。
在目前的版本下枢里,連接池默認是可以保持5個空閑的連接个唧。這些空閑的連接如果超過5分鐘不被使用淳蔼,則將被連接池移除。

networkInterceptor:在非 WebSocket 請求時會添加該攔截器 addNetworkInterceptor窃诉,能夠操作中間過程的響應(yīng)豆胸,如重定向和重試奥洼,當網(wǎng)絡(luò)短路而返回緩存響應(yīng)時不被調(diào)用,只觀察在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)晚胡,攜帶請求來訪問鏈接灵奖。

CallServerInterceptor:利用HttpCodec完成最終請求的發(fā)送,返回最終Response請求估盘。


事件的傳遞中OnTouchListener的優(yōu)先級是高于OnClickListener的瓷患!并且OnClickListener的調(diào)用與OnTouchListener的返回值有關(guān),返回為false時候會調(diào)用遣妥,返回true的時候不調(diào)用擅编!


RequestOptions options = new RequestOptions()

? ? ? ? ? ? .placeholder(R.drawable.ic_launcher_background)

? ? ? ? ? ? .error(R.mipmap.ic_launcher)

? ? ? ? ? ? .diskCacheStrategy(DiskCacheStrategy.NONE)

? ? ? .override(200, 100);


Glide.with(this)

? ? ? ? ? ? .load(imgUrl)

? ? ? ? ? ? .apply(options)

? ? ? ? ? ? .into(mIv2);

Glide緩存分為兩塊 內(nèi)存緩存和硬盤緩存

內(nèi)存緩存:防止應(yīng)用重復將圖片數(shù)據(jù)讀取到內(nèi)存當中。

硬盤數(shù)據(jù):防止應(yīng)用重復從網(wǎng)絡(luò)或其他地方重復下載和讀取數(shù)據(jù)箫踩。

內(nèi)存緩存:

Glide內(nèi)存緩存的實現(xiàn) 使用LruCache算法與弱引用結(jié)合爱态。

如果loadFromCache()方法和loadFromActiveResources()方法都沒有獲取到緩存才會繼續(xù)向下執(zhí)行,從而開啟線程

加載圖片班套。

loadFromCache使用的是lru算法 loadFromActiveResources使用的弱引用的HashMap肢藐。

首先會將緩存圖片從activeResources中移除故河,然后再將它put到LruResourceCache中吱韭。這樣也就實現(xiàn)了正在使用中

的圖片使用弱引用來進行緩存,不在使用中的圖片使用LruCache進行緩存。

硬盤緩存:

DiskCacheStrategy.None 不緩存任何內(nèi)容理盆。

DiskCacheStrategy.SOURCE 只緩存原始圖片痘煤。

DiskCacheStrategy.Result 只緩存轉(zhuǎn)換過后的圖片(默認)。

DiskCacheStrategy.ALL 既緩存原始圖片猿规,也緩存轉(zhuǎn)換過后的圖片衷快。

glide默認不會將原始圖片展示出來,而是會對圖片進行壓縮和轉(zhuǎn)換姨俩。

和內(nèi)存緩存類似蘸拔,硬盤緩存也是使用LruCache算法,谷歌還提供了一個專門的工具類DiskLruCache环葵。Glide使用的是

自己編寫的DiskLruCache工具類调窍。

根據(jù)url作為key進行緩存的策略,可能會遇到url后面拼接一個可變的token张遭,就導致了key的變化邓萨,導致圖片不變

卻緩存了很多份,可以自定義類繼承GlideUrl 菊卷。


butterknife是一個視圖注入框架缔恳,主要通過APT技術(shù),在編譯階段處理注解洁闰,生成一個新的class類

它沒有用到反射技術(shù)歉甚,性能無損耗。

原理

ButterKnife.bind(this);

根據(jù)activity獲取頂層視圖DecorView扑眉,然后調(diào)用bind方法铃芦,拿到集成Unbinder子類構(gòu)造器,

即生成xxx_ViewBinding類構(gòu)造器襟雷,創(chuàng)建對象刃滓,這個類在編譯時自動生成,加載類后沒拿到構(gòu)造器耸弄,

保存到一個LinkedHashMap咧虎,防止每次Class.forName加載。


內(nèi)存泄露優(yōu)化注意事項:

1计呈、靜態(tài)單利類里的context用getApplicationContext代替

2砰诵、注冊取消注冊

3、Handler匿名內(nèi)部類持有外部activity的引用 改為靜態(tài)內(nèi)部類

4捌显、webview導致內(nèi)存泄露 onDestroy中置為null

5茁彭、dialog、popupwindow 在activity前dismiss

6扶歪、CountDownTimer cancel

Cursor關(guān)閉

少用枚舉 枚舉比靜態(tài)變量多消耗兩倍內(nèi)存


傳統(tǒng)線程的缺陷:

·在任務(wù)眾多的情況下理肺,系統(tǒng)要為每一個任務(wù)創(chuàng)建一個線程,而任務(wù)執(zhí)行完畢后會銷

毀每一個線程,造成頻繁的創(chuàng)建與銷毀妹萨。

·多個線程頻繁的創(chuàng)建會占用大量的資源年枕,并且在資源競爭的時候容易出現(xiàn)問題,同

時這么多的線程缺乏一個統(tǒng)一的管理乎完,容易造成界面卡頓熏兄。

·多個線程頻繁的銷毀,會頻繁調(diào)用GC機制树姨,會使性能降低又非常耗時摩桶。

線程池優(yōu)點:

·重用線程池中的線程,線程在執(zhí)行完后不會立刻銷毀帽揪,而會等待另外的任務(wù)典格,這樣

不會頻繁的創(chuàng)建、銷毀和調(diào)用GC

·有效控制線程池最大并發(fā)數(shù)台丛,避免大量線程搶占資源出現(xiàn)的問題

·對多個線程進行統(tǒng)一的管理耍缴,可提供定時執(zhí)行以及指定間隔循環(huán)執(zhí)行的功能。

重用

1挽霉、繼承Thread類 復寫run方法?

2防嗡、實現(xiàn)Runnable接口 復寫run方法

3、實現(xiàn)Callable接口 復寫 復寫call方法 該接口有泛型? 與其他兩個相比有返回值

侠坎,返回值為泛型,

FutureTask<Integer> demo03 = new FutureTask<>(new Dome3

());//Demo3實現(xiàn)Callable類并復寫call方法

調(diào)用為new Thread

(demo03,"Thread_Name").start();

一般返回值調(diào)用get()方法放在代碼最后蚁趁,因為get

方法有可能造成阻塞。

4实胸、AsyncTask類 底層封裝了線程池和Handler 復寫doInBackground方法他嫡、

onProgressUpdate方法、onPostExecute方法庐完、onPreExecute方法

取消方法 cancel

(boolean)

5钢属、HandlerThread new的時候加String 要調(diào)用start方法 與Handler結(jié)合使用 取消的

時候要quit()

6、繼承IntentService類 內(nèi)部采用了HandlerThread來執(zhí)行任務(wù)门躯,任務(wù)執(zhí)行完畢會自

動退出淆党。復寫onHandleIntent()方法 、onCreate讶凉、onStartCommand染乌、onDestroy

7、線程池

線程池解決了兩個問題:

1.提升性能:通常在執(zhí)行大量異步任務(wù)時懂讯,減少了每個任務(wù)的調(diào)用開銷荷憋,并且提供了

一種限制和管理資源的方法,使性能得到提升褐望。

2.統(tǒng)計信息:每個ThreadPoolExecutor保持一些基本的統(tǒng)計信息勒庄,例如完整的任務(wù)數(shù)

量串前。

Exectuors.newCachedThreadPool();//無界線程池,自動線程回收锅铅。

Executors.newFixedThreadPool(int size);//固定大小的線程池。只有核心線程减宣,無非核心線程無超時時長盐须,并且阻塞隊列無界。

Executors.newSingleThreadExecutor();//單一后臺線程漆腌。一個任務(wù)一個任務(wù)執(zhí)行的場景

new ThreadPoolExecutor(

? ? ? ? ? int corePoolSize,//2 線程池核心線程數(shù)(平時保留的線程數(shù))


? ? ? ? ? ? ? ? int maximumPoolSize,//5 線程池最大線程數(shù)(當workQueue都放

不下時贼邓,啟動新線程,最大線程數(shù))


? long keepAliveTime,//超出corePoolSize數(shù)量的線程的保留時間闷尿。


? ? ? ? ? ? ? ? TimeUnit unit,//keepAliveTime單位


? ? ? ? BlockingQueue<Runnable> workQueue,//阻塞隊列塑径,存放來不及

執(zhí)行的線程? new LinkedBlockingDeque<>(3)


? ThreadFactory threadFactory,//線程工廠

Executors.defaultThreadFactory()

? ? ? ? ? ? RejectedExecutionHandler

handler)//飽和策略? new ThreadPoolExecutor.AbortPolicy()

workQueue:阻塞隊列

,存放來不及執(zhí)行的線程填具。

·ArrayBlockingQueue? 構(gòu)造函數(shù)一定要傳大小

·LinkedBlockingQueue 構(gòu)造函數(shù)不傳大小會默認為Integer.MAX_VALUE 當大量請求

任務(wù)時容易耗盡內(nèi)存

·SynnchronousQueue 同步隊列 一個沒有存儲空間的阻塞隊列 统舀,將任務(wù)同步交付給

工作線程

·優(yōu)先隊列

handler:拒絕策略

·AbortPolicy(默認):直接拋棄

·CallerRunsPolicy:用調(diào)用者的線程執(zhí)行任務(wù)

·DiscardOldestPolicy:拋棄隊列中最久的任務(wù)

·DiscardPolicy:拋棄當前任務(wù)

構(gòu)造方法詳解(最多參數(shù)為例):

1.corePoolSize 線程池的核心線程數(shù)。

2.maximumPoolSize 線程池最大線程數(shù)劳景。

可通過setCorePoolSize和setMaximumPoolSize方法進行修改誉简。

當在execute(Runnable)提交新任務(wù)時,如果當前少于corePoolSize盟广,即使有工作線程

處于空閑狀態(tài)闷串,也會創(chuàng)建一個新線程來處理該請求;如果多于corePoolSize但小于

maximumPoolSize的線程正在運行筋量,則如果隊列沒有滿烹吵,則進入等待隊列,如果隊列已

滿才會創(chuàng)建新線程桨武。如果maximumPoolSize已滿肋拔,則執(zhí)行拒絕策略。

可以通過設(shè)置coorPoolSize和maximumPoolSize相同來創(chuàng)建一個固定大小的線程池呀酸。

可以通過設(shè)置maximumPoolSize大小為Integer.MAX_VALUE,創(chuàng)建一個允許任意數(shù)量的并

發(fā)任務(wù)

核心線程預啟動

默認情況下只损,只有當新任務(wù)到達時,才開始創(chuàng)建和啟動核心線程七咧。但是可以通過

threadPoolExecutor.prestartCoreThread()//創(chuàng)建一個空閑任務(wù)線程等待任務(wù)的到達

threadPoolExecutor.prestartAllCoreThreads()//創(chuàng)建核心線程池數(shù)量的空閑任務(wù)線

程等待任務(wù)的到達

3.keepAliveTime 線程存活時間

如果當前線程池擁有超過corePoolSize大小的線程跃惫,那么多余的線程將在超過

keepAliveTime時被終止,可以調(diào)用allowCoreThreadTimeOut(true) 將此策略用于核

心線程艾栋。

4.TimeUnit 單位

5.BlockingQueue<Runnable> 阻塞隊列 主要用來存儲已經(jīng)被提交但尚未執(zhí)行的任務(wù)

爆存,是用exectue方法來提交的

三種隊列:

直接握手隊列,SynchronousQueue//他將任務(wù)交給線程而不需要保留蝗砾,如果沒有線程

立刻運行他先较,那么排隊任務(wù)嘗試失敗會構(gòu)建新的線程携冤。當任務(wù)持續(xù)以平均提交速度大

于平均處理速度時,會導致線程數(shù)量無限增長的問題闲勺。

無界隊列曾棕,當所有corePoolSize線程繁忙時,使用無界隊列(沒有預定義容量的

LinkedBlockingQueue)將導致新任務(wù)在隊列中等待菜循,從而導致maximux的值沒有任何

作用翘地,當任務(wù)持續(xù)以平均提交速度大于平均處理速度,會導致隊列無限增長的問題癌幕。

有界隊列衙耕, 一個有界隊列(ArrayBlockingQueue)和有限的maximum配置有助于防止

資源耗盡,但是難以控制勺远。使用大隊列和較小的maximumPoolSizes可以最大限度地減

少CPU使用率橙喘,操作系統(tǒng)資源和上下文切換開銷,但會導致人為的低吞吐量胶逢。如果任務(wù)

經(jīng)常被阻塞(比如I/O限制)厅瞎,那么系統(tǒng)可以調(diào)度比我們允許的更多的線程。

使用小隊

列通常需要較大的maximumPoolSizes初坠,這會使CPU更繁忙磁奖,但可能會遇到不可接受的調(diào)

度開銷,這也會降低吞吐量某筐。

有就新建比搭,大于了核心就先用閑著的,大于了核心而且沒有閑著的就創(chuàng)建南誊,直到超出

maximum就拒絕身诺。

6.ThreadFactory 為線程池提供創(chuàng)建新線程的功能,一般使用默認即可

7.RejectedExecutionHandler飽和策略抄囚。

AbortPolicy(中止策略)默認策略霉赡,拋出運行時異常RejectedExecutionException。

CallerRunsPolicy幔托,簡單的反饋控制機制穴亏,可以減慢提交任務(wù)的速度

DiscardPolicy 直接丟棄新提交的任務(wù)

DiscardOldestPolicy,如果執(zhí)行器沒有關(guān)閉重挑,隊列頭的任務(wù)將會被拋棄嗓化,然后執(zhí)行器

重新嘗試執(zhí)行任務(wù)(如果失敗則重復這一過程)

execute方法與submit方法的區(qū)別 submit方法內(nèi)部還是調(diào)用了execute方法,返回的是

一個Future對象

ThreadPoolExecutor 執(zhí)行任務(wù)時大致遵循如下流程:

1.如果線程池中的線程數(shù)未達到核心線程數(shù)谬哀,則會立馬啟用一個核心線程去執(zhí)行刺覆。

2.如果線程池中的線程數(shù)已經(jīng)達到核心線程數(shù),且任務(wù)隊列workQueue未滿史煎,則將新線

程放入workQueue中等待執(zhí)行谦屑。

3.如果線程池中的線程數(shù)已經(jīng)達到核心線程數(shù)但未超過線程池規(guī)定最大值驳糯,且

workQueue已滿,則開啟一個非核心線程來執(zhí)行任務(wù)氢橙。

4.如果線程池中的線程數(shù)已經(jīng)超過線程池規(guī)定最大值酝枢,則拒絕執(zhí)行該任務(wù),采取飽和

策略悍手,并拋出RejectedExecutionException異常帘睦。


性能優(yōu)化

內(nèi)存 渲染 耗電方面

內(nèi)存泄露是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間谓苟,

一次內(nèi)存泄漏似乎不會有大的影響官脓,但內(nèi)存泄漏堆積后的后果就是內(nèi)存溢出协怒。

內(nèi)存溢出指程序申請內(nèi)存時涝焙,沒有足夠的內(nèi)存供申請者使用,或者說孕暇,給了你一塊存儲int類型數(shù)據(jù)的存儲空間仑撞,

但是你卻存儲long類型的數(shù)據(jù),那么結(jié)果就是內(nèi)存不夠用妖滔,此時就會報錯OOM,即所謂的內(nèi)存溢出隧哮。

造成內(nèi)存泄漏:

1、非靜態(tài)內(nèi)部類持有外部類的引用? -》使用靜態(tài)內(nèi)部類 不持有外部引用

2座舍、單例的context 隨著activity的銷毀 還持有activity的引用 -》 使用context.getApplicationContext

3沮翔、靜態(tài)變量指向的引用永遠不會被回收 -》 盡量少使用 不使用時重置為null

4、資源對象未及時關(guān)閉曲秉,數(shù)據(jù)庫采蚀,IO流,文件流 -》讀寫時通常使用了緩沖承二,緩沖一直被占用而得不到釋放

5榆鼠、未取消注冊或回調(diào)。-》取消注冊廣播

6亥鸠、動畫導致妆够。動畫是個耗時操作,啟動了動畫在頁面或視圖銷毀時沒有調(diào)用cancel负蚊,這個動畫雖然看不見了

但會一直不斷的播下去神妹,

7、webview造成內(nèi)存泄露家妆。activity銷毀后webview持有的引用得不到釋放灾螃。

有時候獲取一張圖片只是為了得到圖片的一些信息,比如寬高揩徊,不需要顯示在界面上腰鬼,這時候

就不必吧圖片加載到內(nèi)存 可以用BitmapFactory.Options() 的 inJustDecodeBounds屬性設(shè)置為true

應(yīng)用瘦身:

只是用一套圖片 xxhdpi 1080p

資源圖片轉(zhuǎn)成webp格式

布局優(yōu)化

層級少的情況下 LineraLayout>RelativeLayout 原因 llout的測量在不設(shè)置weidgt的情況下只測量一次嵌赠,而rlout要測量兩次

使用約束布局、使用<include>標簽 熄赡、使用<ViewStub>延遲view的加載姜挺、減少層級使用<merge>替換父級布局

注意使用wrap_content 會增加測量成本 、刪除無用屬性彼硫。

渲染優(yōu)化

移除window或xml中非必要的background


==比較對象 ===比較地址值

炊豪?可null !拧篮!斷言不為null

.. [ ]

until [ )

step 2 跳2

open class? :

委托代理by

單例 object

lateinit var

const val

companion object 伴生對象

internal 修飾的同一個module下可見

as強轉(zhuǎn)

類名::class.java

inner 內(nèi)部類

object是Any

多層嵌套可以給循環(huán)起名字

Outter@for(;;){

? Inner@for(;;){

? ? break@Inner

}

}


LayoutParams?的作用是子控件告訴父控件自己要如何布局


安卓中View和ViewGroup在點擊的時候有兩個方法词渤,onTouch和onTouchEvent

onTouch是設(shè)置是了onTouchListener之后的回調(diào)方法,如果設(shè)置了onTouchListener就會回調(diào)onTouch方法串绩,在outouch方法返回true時缺虐,onTouchEvent不會再被調(diào)用,如果沒有設(shè)置onTouchListener或者onTouch返回false時礁凡,onTouchEvent會被調(diào)用高氮,onClickListener是在onTouchEvent中被調(diào)用的 優(yōu)先級最低

onTouch>onTouchEvent>onClickListener


Hanlder消息機制

每個線程中只會有一個MessageQueue對象,MessageQueue是在Looper的構(gòu)造函數(shù)中創(chuàng)建的顷牌,一個MessageQueue對應(yīng)一個Looper剪芍。每個線程中也只會有一個looper對象

子線程中直接調(diào)用new Hander()會導致崩潰,1.可以調(diào)用Looper.prepare()再調(diào)用Looper.loop() 2.可以Handler構(gòu)造參數(shù)中傳入Looper.getMainLooper()

異步處理消息流程:首先需要在主線程中創(chuàng)建一個Handler對象窟蓝,并重寫handlerMessage方法罪裹,然后當子線程中需要進行UI操作時,就創(chuàng)建一個Message對象运挫,并通過Handler將這條消息發(fā)送出去状共。之后這條消息會被添加到MessageQueue隊列中等待被處理,而Looper則會一直嘗試從MessageQueue中取出待處理的消息滑臊,最后返回給Handler的handlerMessage中

主線程為什么不會被阻塞:https://www.zhihu.com/question/34652589

new Message和Message.obtain的區(qū)別
Message.obtain和Handler().obtainMessage()是一樣的口芍,Handler().obtainMessage()內(nèi)部也調(diào)用了Message.obtain(),與直接new的區(qū)別是,省去了創(chuàng)建對象雇卷,內(nèi)部直接從消息池里面拿鬓椭,省去了創(chuàng)建對象申請內(nèi)存的開銷。

sendMessage和postMessage的區(qū)別
主要區(qū)別在于是否等待其他消息的處理关划,postMessage只是把消息放入隊列小染,不管其他程序是否處理都會返回然后繼續(xù)執(zhí)行,sendMessage必須等待其他程序處理消息后才返回贮折,繼續(xù)執(zhí)行裤翩,返回值表示其他程序處理后的返回值,postMessage返回值表示postMessage函數(shù)執(zhí)行是否正確调榄,

quit和quitSafely區(qū)別
當我們調(diào)用Looper的quit方法時踊赠,實際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法呵扛,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息筐带。

當我們調(diào)用Looper的quitSafely方法時今穿,實際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過名字就可以看出伦籍,該方法只會清空MessageQueue消息池中所有的延遲消息蓝晒,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會派發(fā)所有的非延遲消息帖鸦。

無論是調(diào)用了quit方法還是quitSafely方法只會芝薇,Looper就不再接收新的消息。即在調(diào)用了Looper的quit或quitSafely方法之后作儿,消息循環(huán)就終結(jié)了洛二,這時候再通過Handler調(diào)用sendMessage或post等方法發(fā)送消息時均返回false,表示消息沒有成功放入消息隊列MessageQueue中立倍,因為消息隊列已經(jīng)退出了灭红。

需要注意的是Looper的quit方法從API Level 1就存在了侣滩,但是Looper的quitSafely方法從API Level 18才添加進來口注。


LruCache算法原理

Least Recently Used 最近最少使用 LRU算法就是當緩存空間滿了的時候,將最近最少使用的數(shù)據(jù)從緩存空間中刪除以增加可用的緩存空間來緩存新數(shù)據(jù)君珠。這個緩存算法內(nèi)部有一個緩存列表寝志,每當一個緩存數(shù)據(jù)被訪問的時候,這個數(shù)據(jù)就會被提到列表尾部策添,每次這樣的話材部,列表頭部的數(shù)據(jù)就是最近最不經(jīng)常使用的了,當緩存空間不足時唯竹,就會刪除列表頭部的緩存數(shù)據(jù)乐导。

LinkedHashMap

public LruCache(int maxSize) {

? ? ? ? if (maxSize <= 0) {

? ? ? ? ? ? throw new IllegalArgumentException("maxSize <= 0");

? ? ? ? }

? ? ? ? this.maxSize = maxSize;

? ? ? ? this.map = new LinkedHashMap<K, V>(0, 0.75f, true);

? ? }

? · initialCapacity 用于初始化該 LinkedHashMap 的大小。

? ·loadFactor(負載因子)這個LinkedHashMap的父類 HashMap 里的構(gòu)造參數(shù)浸颓,涉及到擴容問題物臂,比如 HashMap 的最大容量是100,那么這里設(shè)置0.75f的話产上,到75的時候就會擴容棵磷。

? ·accessOrder,這個參數(shù)是排序模式,true表示在訪問的時候進行排序( LruCache 核心工作原理就在此)晋涣,false表示在插入的時才排序仪媒。

總結(jié):

? ·LruCache中維護了一個集合LinkedHashMap,該LinkedHashMap是以訪問順序排序的谢鹊。

? ·當調(diào)用put()方法時算吩,就會在結(jié)合中添加元素留凭,并調(diào)用trimToSize()判斷緩存是否已滿,如果滿了就用LinkedHashMap的迭代器刪除隊首元素偎巢,即近期最少訪問的元素冰抢。

? ·當調(diào)用get()方法訪問緩存對象時,就會調(diào)用LinkedHashMap的get()方法獲得對應(yīng)集合元素艘狭,同時會更新該元素到隊尾挎扰。


Sharepreferences apply和commit的區(qū)別

1.apply沒有返回值, commit返回boolean

2.apply是將修改的數(shù)據(jù)原子提交到內(nèi)存巢音,而后異步真正提交到硬件磁盤遵倦, commit是同步提交到硬件磁盤,因此官撼,在多個并發(fā)的提交commit時梧躺,她們會等待正在處理的commit保存到磁盤后再操作,降低了效率

3.apply不會提示任何失敗

apply效率高一些傲绣,如果沒有必要確認是否提交成功建議用apply


kotlin給空值賦值掠哥,如果一個對象User的name為空 此時把這個name賦值給另一個對象 要怎么寫

用?:的形式賦值空值的默認值?

val loginBean = LoginBean("", "")

loginBean.code =mLoginBean?.code ?:"11"

kotlin兩種延遲初始化方式:1.by lazy 2.lateinit var?
lateinit var只能用來修飾類屬性秃诵,不能用來修飾局部變量续搀,并且只能用來修飾對象,不能用來修飾基本類型菠净。
by lazy? 可以用于類屬性或者局部變量
val name by lazy{ "張三" } //只能用val修飾禁舷, 打印name 為張三

自定義高階函數(shù):

fun cus(clac:(Int,Int)->Int){
? ? val result = calc(2,3)????
? ? Log.d("dww",result.toString())
}
調(diào)用: cus{ a,b->a+b}//5????
? ? ? ? ? ? cus{ a,e->a*e}//6


自定義view

三個流程

onMeasure? 測量,系統(tǒng)會根據(jù)xml布局文件和代碼對控件屬性的設(shè)置毅往,來獲取或者計算出每一個view和viewgroup的尺寸牵咙,并將這些尺寸保存下來

measure的過程根據(jù)view的類型分兩種情況

1,單一的view:通過measure過程就完成了其測量的過程攀唯。
過程:measure()->onMeasure()->setMeasureDimension()->getDeafaultSize()->完成測量
2洁桌,ViewGroup,除了完成自身的測量過程外侯嘀,還會遍歷調(diào)用子元素的measure方法另凌,各個子元素再遞歸執(zhí)行該流程。
過程:View.measure()->viewgroup.onMeasure()->viewgroup.measureChild->vg.getChildMeasureSpec->
單一view的measure過程->合并得到viewgroup測量值->view.setMeasureDimension()->完成測量

onLayout? ?布局残拐,根據(jù)測量出的結(jié)果以及對應(yīng)的參數(shù)途茫,來確定每一個控件應(yīng)該顯示的位置。

單一view的onlayout過程:
layout->setOpticalFrame()->onlayout(空實現(xiàn))->layout結(jié)束

viewgroup的onlayout過程:
vg.layout()->調(diào)用super.layout->view.layout()->onlayout()->遍歷子view->計算當前view的位置->確定子view在自身的位置->child.layout->單一view的layout過程->vg完成layout

onDraw? ? 繪制溪食,確定好位置后將這些控件繪制到屏幕上囊卜。
單一view:繪制view本身
過程:draw()->繪制background->繪制自己->繪制子view->繪制裝飾(foreground,滾動條等)->結(jié)束
viewgroup:除了繪制自身view外,還需要繪制所有子view
過程:view.draw()->view.drawbackground()->view.ondraw()->vg.dispathcDraw()->單一view的draw過程->
view.ondrawForeground()->結(jié)束

onMeasure里面有一個MeasureSpec 栅组,MeasureSpec概括了從父布局傳遞給子view布局的要求雀瓢,每一個MeasureSpec代表了寬度或者高度要求,它由size和mode組成玉掸。重寫該方法時刃麸,必須調(diào)用setMeasureDimension(w,h)來存儲view測量出的寬高,

widthMeasureSpec:父布局加入的水平空間要求
heightMeasureSpec:父布局加入的垂直空間要求司浪。

MeasureSpec三種Mode?

UNSPECIFIED(未指明的泊业;未詳細說明的):????未指定尺寸模式,父布局沒有對子view強加任何限制啊易,他可以是任意想要的尺寸吁伺,

EXACTLY(恰好地;精確地):? ? 精確值模式租谈,父布局決定了子view的精確尺寸篮奄,子view無論想要設(shè)置多大的值都將限定在那個邊界內(nèi)(也就是寬高為具體值,如50dp,或者父布局設(shè)置成了match_parent)? ? ?

AT_MOST(至多):? ? 最大值模式割去,子view可以一直大到指定的值窟却,(相當于父布局寬高wrap_content)

onLayout

每一個父布局都會對它的子view進行布局來放置她們,

呻逆。夸赫。。沒寫完

總結(jié):

自定義view在onDraw里需要處理padding的影響页慷,widthMeasureSpec和heightMeasureSpec是包含padding大小的

子view的margin屬性是由viewGroup處理的憔足,viewGroup在onMeasure和onLayout時一定要考慮viewGroup自己的padding是子view的margin

自定義view invalidate和postInvalidate區(qū)別
invalidate和postInvalidate都是進行UI刷新的胁附,invalidate方法運用在UI線程酒繁,postInvalidate方法運用在非UI線程,用于將線程切換到UI線程控妻,postInvalidate最后還是調(diào)用的invalidate方法州袒。
postInvalidate方法調(diào)用了ViewRootImpl中的dispatchInvalidateDelayed方法向ViewRootImpl中的ViewRootHandler發(fā)送了一個消息,最后調(diào)用的還是view的invalidate方法弓候。


kotlin下的單例

1.餓漢式? object SingletonDemo{}? ? ?object進行對象聲明與我們的餓漢式的單例代碼是相同的

2.懶漢式只判斷一層null 線程不安全的

class SingleDemo private constructor(){
? ? companion object{
? ? ? ? ????private var instance:SingleDemo? = null
? ? ? ? ? ? get(){
? ? ? ? ? ? ? ? if(field==null){
? ? ? ? ? ? ? ? field = SingleDemo()
????????????????}
? ? ? ? return field
? ? ? ? ?}
? ? ? ? ?fun get():SingleDemo{
? ? ? ? ? ? return instance!!
????????}? ?
????}
}

3.安全的懶漢式? 同步鎖在方法上的那種

與2只差一個@Synchronized

class SingleDemo private constructor(){
????????companion object{
????????private var instance:SingleDemo? = null
????????????get(){
????????????if(field==null){
????????????????field = SingleDemo()
????????????????}
????????????return field
????????????}
? ? ? ? ? ? @Synchronized
????????????fun get():SingleDemo{
????????????????return instance!!
????????????????}? ?
????????????}
????}

4.懶漢式雙重檢查式 安全

class SingleDoubleCheck private constructor(){
? ? companion object{
? ? ? ? val instance : SingleDoubleCheck by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
? ? ? ? ? ? SingleDoubleCheck()
????????????????}? ? ? ?
????????}
}

5.靜態(tài)內(nèi)部類

class StaticClazz private constructor(){
? ? companion object{
? ? ? ? val instance = ClazzHolder.holder
????}
? ? private object ClazzHolder{
? ? ? ? val holder = StaticClazz()
????}
}


ArrayList擴容原理:

1郎哭,把原來的數(shù)組復制到另一個內(nèi)存空間更大的數(shù)組中。
2菇存,把新元素添加到擴容以后的數(shù)組中夸研。
每次擴容是原來的1.5倍,


Array和ArrayList的區(qū)別
存儲方面:
數(shù)組可以存儲基本類型也可以存儲對象依鸥,只能存同種類型的元素亥至,
ArrayList只能存儲對象類型,可以存object

空間大小方面:
數(shù)組的大小是固定的,空間不夠時也不能再次申請
ArrayList空間是動態(tài)增長的姐扮,如果空間不夠匀谣,會創(chuàng)建一個空間比原來大1.5倍的新數(shù)組眷柔,然后將所有元素復制到新數(shù)組中,接著拋棄舊數(shù)組,每次添加新元素的時候會去檢查內(nèi)部數(shù)組的空間是否足夠霹疫。

方法上:
ArrayList方法更多樣化,addAll(),removeAll(),返回迭代器iterator()等梭姓。
ArrayList初始化容量是10仪搔,一次擴容自身大小的1.5倍,內(nèi)部數(shù)組恬惯,擴容原理為創(chuàng)建一個新數(shù)組并將舊數(shù)組copy到新數(shù)組并舍棄舊數(shù)組塘揣。

1.ArrayList是可以動態(tài)增長和縮減的索引序列,基于數(shù)組實現(xiàn)的List類宿崭。ArrayList是有序集合
2.ArrayList封裝了一個動態(tài)再分配的ogject[]數(shù)組亲铡,每一個類對象都有一個capacity屬性,表示他所封裝的object[]數(shù)組的長度葡兑,當向ArrayList中添加元素時奖蔓,該值會自動增加。
3.ArrayList線程不安全讹堤,多條線程訪問同一ArrayList集合時吆鹤,需手動保證該集合的同步性。


HashMap默認初始容量16洲守,負載因子0.75疑务,設(shè)定threshold,threshold=capacity(16) *loadFactor (0.75) = 12
當HashMap的size到了threshold時就會進行擴容梗醇。
?HashMap要求容量必須是2的冪知允。 threshold = tableSizeFor(initialCapacity); tableSizeFor()主要功能返回一個比給定整數(shù)大且最接近2的冪的整數(shù),如給10則為2的4次方16

簡單來說HashMap由數(shù)組+鏈表組成叙谨,數(shù)組是HashMap的主體温鸽,鏈表則是主要為了解決哈希沖突而存在的,如果定位到的數(shù)組位置不含鏈表(當前Entry的next指向null)那么對于查找手负,添加等操作很快涤垫,僅需一次尋址即可,如果定位到的數(shù)組包含鏈表竟终,對于添加操作時間復雜度為O(n)蝠猬,首先遍歷鏈表,存在即覆蓋统捶,否則新增榆芦。對于查找操作來講敦姻,仍需遍歷鏈表,然后通過key對象的equals方法逐一對比歧杏,所以镰惦,性能考慮,HashMap中的鏈表出現(xiàn)越少性能才越好犬绒。

HashMap 1.7和1.8的區(qū)別
是基于哈希表實現(xiàn)Map接口的雙列集合旺入,數(shù)據(jù)結(jié)構(gòu)是鏈表散列,也就是數(shù)據(jù)+鏈表凯力,Key是唯一的茵瘾,value可以重復,允許存null鍵null值咐鹤,元素無序拗秘。線程不安全。
查詢慢 增刪快
1.7使用的是頭插法祈惶,而1.8使用的是尾插法雕旨,因為1.7是單鏈表進行的縱向延伸,當采用頭插法時會容易出現(xiàn)逆序且環(huán)形鏈表死循環(huán)的問題捧请,但是在1.8后加入了紅黑樹凡涩,使用尾插法,避免了這個問題疹蛉。
擴容后數(shù)據(jù)存儲位置的計算方式也不一樣活箕,


activity啟動流程:

1.點擊桌面app的圖標,Launcher進程采用Binder_IPC向system_server進程發(fā)起startActivity請求
2.system_server接到進程請求后可款,向zygote進程發(fā)起創(chuàng)建進程的請求育韩。
3.Zygote進程fork出新的子進程,即app進程闺鲸,
4.app進程通過Binder_IPC向system_server進程發(fā)起attachApplication請求筋讨。
5.system_server進程在收到請求后,進行一系列準備工作翠拣,再通過binder ipc向app進程發(fā)送scheduleLaunchActivity請求版仔。
6.app進程的binder線程(ApplicationThread)在收到請求后,通過handler向主線程發(fā)送LAUNCHER_ACTIVITY消息
7主線程收到message后误墓,通過反射機制創(chuàng)建目標activity,并回調(diào)activity.oncreate()方法等


synchronized和volatile的區(qū)別

多線程只有保證可見性和原子性益缎、有序性才能保證安全

可見性:線程都是基于cpu運算的谜慌,cpu有緩沖區(qū),所以每次在計算的時候都會把數(shù)據(jù)加載緩沖區(qū)計算莺奔,計算好的數(shù)據(jù)最終會被寫到主存中欣范,但是有時間差变泄,如果沒有synchronized或者volatile修飾,那么下一個線程讀取的時候可能是修改前的數(shù)據(jù)恼琼。加上synchronized或者volatile妨蛹,在該線程釋放的時候會把數(shù)據(jù)寫回到主存。

原子性:就好比你在思考一件事情的時候晴竞,不愿意被其他事情打擾一樣蛙卤,線程的原子性也是如此,在執(zhí)行一段邏輯的時候也不希望被其他線程干預噩死,多個線程同時請求同一資源或代碼塊颤难,這時候?qū)Y源或者代碼塊上加上synchronized,表示此時只能有一個線程能拿到鎖已维,其他線程只能等待他釋放才能進行下一輪爭奪行嗤。

有序性:又叫做禁止指令重復,處理器為了提高程序運行效率垛耳,可能會對輸入代碼進行優(yōu)化栅屏,所以有可能會調(diào)整語句的執(zhí)行順序,但是他會保證最終結(jié)果的正確性堂鲜,這種正確性只保證單線程里沒有問題既琴、

synchronized修飾范圍:可以變量,可以方法泡嘴,上述三個特性都有甫恩,原子性,可見性有序性酌予。

volatile是一種輕量級的同步機制磺箕,只能修飾變量。特性:只有可見性和有序性抛虫,不具有原子性松靡。



ConcurrentHashMap
JDK1.7版本中concurrenthashmap采用了數(shù)據(jù)+Segment(分段鎖)的方式實現(xiàn)
分段鎖稱為Segment,它是類似HashMap的結(jié)構(gòu)建椰,內(nèi)部擁有一個Entry數(shù)組雕欺,數(shù)組中的每一個元素又是一個鏈表,同時又是一個ReentrantLock棉姐。
內(nèi)部結(jié)構(gòu):ConcurrentHashMap使用分段鎖技術(shù)屠列,將數(shù)據(jù)分成一段一段的存儲,然后給每一段數(shù)據(jù)分配一把鎖伞矩,當一個線程占用鎖訪問其中一個數(shù)據(jù)的時候笛洛,其他數(shù)據(jù)也能被其他線程訪問。能夠?qū)崿F(xiàn)真正的并發(fā)訪問乃坤。
JDK1.8版本concurrenthashmap采用數(shù)組+鏈表+紅黑樹的實現(xiàn)方式來設(shè)計苛让。內(nèi)部大量采用CAS(compare and swap 比較替換)操作沟蔑。
CAS操作包括三個操作數(shù)---內(nèi)存位置V、預期原值A(chǔ)和新值B狱杰,如果內(nèi)存地址里面的值和A的值是一樣的瘦材,那么就將內(nèi)存里面的值更新成B,CAS是通過無限循環(huán)來獲取數(shù)據(jù)的仿畸,如果在第一輪循環(huán)中食棕,a線程獲取地址里面的值被b線程修改了,那么a線程需要自旋颁湖,到下次循環(huán)才有可能執(zhí)行宣蠕。1.8中徹底放棄了Segment(分段鎖)而采用Node。JDK1.8中的concurrenthashmap在鏈表的節(jié)點數(shù)量大于8的時候會將鏈表轉(zhuǎn)換成紅黑樹進一步提高其查找性能甥捺。

Node:保存Key抢蚀,value及key的hash值的數(shù)據(jù)結(jié)構(gòu)。

查詢時間復雜度:從原來的遍歷鏈表O(n)镰禾,變成遍歷紅黑樹O(logN)皿曲。



LinkedHashMap 繼承自HashMap,結(jié)構(gòu)為HashMap+雙向鏈表吴侦,構(gòu)造方法中有一個accessOrder 默認為false(按插入順序存儲)屋休,這跟存儲順序有關(guān),存儲數(shù)據(jù)是有序的备韧,分為兩種:插入順序和訪問順序劫樟。

LinkedHashMap構(gòu)造函數(shù),主要就是調(diào)用了HashMap構(gòu)造函數(shù)初始化了一個Entry[]數(shù)組织堂,然后調(diào)用自身init初始化了一個只有頭結(jié)點的雙向鏈表叠艳。

線程不安全的。



onNewIntent方法回調(diào)時機

在ActA的啟動模式設(shè)置為singleTask時易阳,ActA->ActB->ActC->ActA 則會調(diào)用ActA的onNewIntent方法附较。

activity第一次啟動的時候不會回調(diào)onNewIntent方法,如果以后再想啟動這個activity的時候那么會onNewIntent-》onrestart-》onstart-》onresume潦俺,如果由于系統(tǒng)內(nèi)存不足已經(jīng)把activity釋放掉了拒课,那么再次調(diào)用的時候會重新啟動activity即執(zhí)行onCreate onstart onresume

當調(diào)用到onNewIntent的時候,需要在onNewIntent中使用setIntent賦值給activity的intent事示,否則后續(xù)getIntent得到的數(shù)據(jù)都是老的intent數(shù)據(jù)早像。

Activity四種啟動模式

1.standard 默認啟動模式,每次啟動很魂,無論棧中是否有這個activity的實例扎酷,系統(tǒng)都會創(chuàng)建一個新的activity實例。

2.singleTop 當一個singleTop模式的activity已經(jīng)位于任務(wù)棧的棧頂遏匆,再去啟動它時法挨,不會再創(chuàng)建新的實例,如果不位于棧頂幅聘,就會創(chuàng)建新的實例凡纳。

3.singleTask,SingleTask模式的activity在同一個Task內(nèi)只有一個實例帝蒿,如果Activity已經(jīng)位于棧頂荐糜,系統(tǒng)不會再創(chuàng)建新的activity實例,但是如果activity已經(jīng)存在但是不位于棧頂葛超,系統(tǒng)就會把該activity移到棧頂暴氏,并把它上面的activity出棧。

4.singleInstance? 該模式也是單例的绣张,但是和singleTask不同答渔,singleTask只是任務(wù)棧內(nèi)單例,系統(tǒng)里是可以有多個singleTask實例的侥涵,而singleinstance的activity在整個系統(tǒng)里只有一個實例沼撕,啟動一個singleinstance的activity,系統(tǒng)會創(chuàng)建一個新的任務(wù)棧芜飘,并且這個任務(wù)棧里只有他一個activity

如果把一個activity設(shè)置為singleinstance模式务豺,啟動會慢一些,切換效果不好嗦明,影響用戶體驗笼沥,它往往位于多個應(yīng)用之間。




橫豎屏切換activity生命周期娶牌。

oncreate->onstart->onresume->onpause->onSaveinstancestate->onstop->ondestroy->oncreate->onstart->onrestoreinstancestate->onresume

pause后保存(onSaveinstancestate)奔浅,start后恢復(onrestoreinstancestate)。




AIDL

IPC:Inter Process Communication 也就是進程通信或者跨進程通信的意思裙戏,進程一般指一個執(zhí)行單元乘凸,它擁有獨立的地址空間,也就是一個應(yīng)用或者一個程序累榜,線程是CPU調(diào)度的最小單元营勤,是進程中一個執(zhí)行部分或者說是執(zhí)行體,兩者之間是包含與被包含的關(guān)系壹罚,因為進程間資源不能共享葛作,所以每個系統(tǒng)都有自己的IPC機制,Android自己的IPC機制就是Binder猖凛。AIDL其實就是通過Binder機制來實現(xiàn)的赂蠢。



地圖的json數(shù)據(jù)在cpu上 要傳給gpu再通過opengl渲染 我們只是告訴opengl要用什么順序進行渲染 opengl讀取gpu上的數(shù)據(jù)通過我們創(chuàng)建的buffer 這個數(shù)據(jù)怎么傳到gpu 通過program program包裝好gles的規(guī)則傳給opengl

貼圖

一張圖片有四個頂點 一般是在第一象限 所以把他想象是在第一象限 按照00 01 11 10的順序 這四個左邊稱為紋理坐標 然后把這個紋理坐標放在gl上面一一對應(yīng)起來 一般來說只需要貼一個背景 四個紋理坐標對應(yīng)4個gl坐標 如果是貼坐標比較多的大樓 需要手動拆分每4個一組

我們所做的事是把數(shù)據(jù)按什么樣的順序傳給opengl



內(nèi)存優(yōu)化 LeakCanary框架原理

原理:監(jiān)控應(yīng)用中所有activity生命周期方法中的onDestroy方法,在onDestroy中把activity轉(zhuǎn)成弱引用保存到引用隊列辨泳,然后框架會不斷遍歷分析引用隊列虱岂,檢測到內(nèi)存地址是否可達玖院,并輸出內(nèi)存泄漏的最短路徑。

給每個觀察的引用生成一個隨機key保存到集合中第岖,并把引用轉(zhuǎn)換成弱引用保存到引用隊列难菌,將能回收的引用從隊列中刪除,沒有被回收的會生成一個heap文件蔑滓,把heap文件讀取到內(nèi)存緩存HprofBuffer中郊酒,然后通過解析HprofParser產(chǎn)生Snapshot快照,键袱。燎窘。。http://www.reibang.com/p/4deb3b6e9515

LeakCanary實現(xiàn)內(nèi)存泄漏的主要判斷邏輯是這樣的蹄咖。當我們觀察的Activity或者Fragment銷毀時褐健,我們會使用一個弱引用去包裝當前銷毀的Activity或者Fragment,并且將它與本地的一個ReferenceQueue隊列關(guān)聯(lián)。我們知道如果GC觸發(fā)了比藻,系統(tǒng)會將當前的引用對象存入隊列中铝量。

如果沒有被回收,隊列中則沒有當前的引用對象银亲。所以LeakCanary會去判斷慢叨,ReferenceQueue是否有當前觀察的Activity或者Fragment的引用對象,第一次判斷如果不存在务蝠,就去手動觸發(fā)一次GC拍谐,然后做第二次判斷,如果還是不存在馏段,則表明出現(xiàn)了內(nèi)存泄漏轩拨。


Activity 5秒? ?Service20秒? BroadcastReceiver 10秒 超過主線程就會ANR

BroadcastReceiver?Service在主線程 不能進行耗時操作,可以通過IntentService進行



view和surfaceview的區(qū)別
view在主線程更新UI院喜,surfaceview可以在子線程更新UI
為什么surfaceview可以在子線程更新UI
surfaceView和view都是通過lockCanvas和unlockCanvasAndPost方法進行繪畫的亡蓉。View的刷新有一個checkThread(在ViewRootImpl.java中)的判斷,如果不是在UI線程中會拋出異常喷舀。而surfaceView中不會進行判斷砍濒,這樣他就可以在其他線程更新UI
View的繪圖效率不高,主要用于動畫變化較少的程序硫麻,SurfaceView 繪圖效率較高爸邢,用于界面更新頻繁的程序
SurfaceView使用雙緩沖機制,播放視頻時畫面更流暢拿愧。

什么是雙緩沖機制杠河?
在運用時可以理解為:SurfaceView在更新視圖時用到了兩張 Canvas,一張 frontCanvas 和一張 backCanvas ,每次實際顯示的是 frontCanvas 券敌,backCanvas 存儲的是上一次更改前的視圖唾戚。當你在播放這一幀的時候,它已經(jīng)提前幫你加載好后面一幀了陪白,所以播放起視頻很流暢颈走。
當使用lockCanvas()獲取畫布時膳灶,得到的實際上是backCanvas 而不是正在顯示的 frontCanvas 咱士,之后你在獲取到的 backCanvas 上繪制新視圖,再 unlockCanvasAndPost(canvas)此視圖轧钓,那么上傳的這張 canvas 將替換原來的 frontCanvas 作為新的frontCanvas 序厉,原來的 frontCanvas 將切換到后臺作為 backCanvas 。例如毕箍,如果你已經(jīng)先后兩次繪制了視圖A和B弛房,那么你再調(diào)用 lockCanvas()獲取視圖,獲得的將是A而不是正在顯示的B而柑,之后你將重繪的 A 視圖上傳文捶,那么 A 將取代 B 作為新的 frontCanvas 顯示在SurfaceView 上,原來的B則轉(zhuǎn)換為backCanvas媒咳。

Service的onStartCommand方法四種返回值:http://www.reibang.com/p/55586f44a810
START_STICKY_COMPATIBILITY粹排、START_STICKY、START_NOT_STICKY涩澡、START_REDELIVER_INTENT

1顽耳、START_STICKY_COMPATIBILITY
Service被殺死后會重啟執(zhí)行onCreate方法,但是onStartCommand方法沒有被執(zhí)行妙同。

2射富、START_STICKY
Service被殺死后會重啟執(zhí)行onCreate方法,并且onStartCommand方法會執(zhí)行粥帚。從startId可以看出是Service對象不是同一個胰耗,并且onStartCommand方法中的intent值為null

3芒涡、START_NOT_STICKY
Service被殺死后并不會重啟(Service的onCreate沒有被第二次被執(zhí)行)柴灯。

4、START_REDELIVER_INTENT
Service被殺死后會重啟(執(zhí)行了onCreate方法)拖陆,并且onStartCommand方法會執(zhí)行弛槐。從startId可以看出兩個Service對象是同一個,并且onStartCommand方法中的intent和前一個intent值是一致的依啰。


VISIBLE乎串、INVISIBLE、GONE
public static final int VISIBLE =0x00000000;
public static final int INVISIBLE =0x00000004;
public static final int GONE =0x00000008;
static final int VISIBILITY_MASK =0x0000000C;
調(diào)用view的setVisibility方法實際是調(diào)用了setFlags方法,
如果GONE和INVISIBLE都可以完成需求效果叹誉,應(yīng)該使用INVISIBLE鸯两,因為從源碼中看出GONE需要重新的布局(layout)和通知上層view去刷新,有緩存還要清空緩存长豁,INVISIBLE不重新layout钧唐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市匠襟,隨后出現(xiàn)的幾起案子钝侠,更是在濱河造成了極大的恐慌,老刑警劉巖酸舍,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帅韧,死亡現(xiàn)場離奇詭異,居然都是意外死亡啃勉,警方通過查閱死者的電腦和手機忽舟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淮阐,“玉大人叮阅,你說我怎么就攤上這事∑兀” “怎么了浩姥?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長群扶。 經(jīng)常有香客問我及刻,道長,這世上最難降的妖魔是什么竞阐? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任缴饭,我火速辦了婚禮,結(jié)果婚禮上骆莹,老公的妹妹穿的比我還像新娘颗搂。我一直安慰自己,他們只是感情好幕垦,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布丢氢。 她就那樣靜靜地躺著,像睡著了一般先改。 火紅的嫁衣襯著肌膚如雪疚察。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天仇奶,我揣著相機與錄音貌嫡,去河邊找鬼。 笑死,一個胖子當著我的面吹牛岛抄,可吹牛的內(nèi)容都是我干的别惦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼夫椭,長吁一口氣:“原來是場噩夢啊……” “哼掸掸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蹭秋,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤扰付,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后感凤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悯周,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年陪竿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屠橄。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡族跛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锐墙,到底是詐尸還是另有隱情礁哄,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布溪北,位于F島的核電站桐绒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏之拨。R本人自食惡果不足惜茉继,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚀乔。 院中可真熱鬧烁竭,春花似錦、人聲如沸吉挣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睬魂。三九已至终吼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氯哮,已是汗流浹背际跪。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人垫卤。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓威彰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親穴肘。 傳聞我的和親對象是個殘疾皇子歇盼,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348