Android性能優(yōu)化之啟動(dòng)加速35%

一抱虐、前言

隨著項(xiàng)目版本的迭代,App的性能問題會(huì)逐漸暴露出來梢夯,而好的用戶體驗(yàn)與性能表現(xiàn)緊密相關(guān)言疗,從本篇文章開始,我將開啟一個(gè)Android應(yīng)用性能優(yōu)化的專題颂砸,從理論到實(shí)戰(zhàn)噪奄,從入門到深挖,手把手將性能優(yōu)化實(shí)踐到項(xiàng)目中人乓,歡迎持續(xù)關(guān)注勤篮!

那么第一篇文章我就從應(yīng)用的啟動(dòng)優(yōu)化開始,根據(jù)實(shí)際案例色罚,打造閃電般的App啟動(dòng)速度碰缔。

二、初識(shí)啟動(dòng)加速

來看一下Google官方文檔《Launch-Time Performance》 對(duì)應(yīng)用啟動(dòng)優(yōu)化的概述戳护;

應(yīng)用的啟動(dòng)分為冷啟動(dòng)金抡、熱啟動(dòng)瀑焦、溫啟動(dòng),而啟動(dòng)最慢梗肝、挑戰(zhàn)最大的就是冷啟動(dòng):系統(tǒng)和App本身都有更多的工作要從頭開始榛瓮!
應(yīng)用在冷啟動(dòng)之前,要執(zhí)行三個(gè)任務(wù):

  • 加載啟動(dòng)App巫击;

  • App啟動(dòng)之后立即展示出一個(gè)空白的Window禀晓;

  • 創(chuàng)建App的進(jìn)程;

而這三個(gè)任務(wù)執(zhí)行完畢之后會(huì)馬上執(zhí)行以下任務(wù):

  • 創(chuàng)建App對(duì)象坝锰;

  • 啟動(dòng)Main Thread粹懒;

  • 創(chuàng)建啟動(dòng)的Activity對(duì)象;

  • 加載View顷级;

  • 布置屏幕凫乖;

  • 進(jìn)行第一次繪制;

而一旦App進(jìn)程完成了第一次繪制愕把,系統(tǒng)進(jìn)程就會(huì)用Main Activity替換已經(jīng)展示的Background Window拣凹,此時(shí)用戶就可以使用App了。

Picture

作為普通應(yīng)用恨豁,App進(jìn)程的創(chuàng)建等環(huán)節(jié)我們是無法主動(dòng)控制的嚣镜,可以優(yōu)化的也就是Application、Activity創(chuàng)建以及回調(diào)等過程橘蜜。

同樣菊匿,Google也給出了啟動(dòng)加速的方向

  • 利用提前展示出來的Window,快速展示出來一個(gè)界面计福,給用戶快速反饋的體驗(yàn)跌捆;

  • 避免在啟動(dòng)時(shí)做密集沉重的初始化(Heavy app initialization);

  • 定位問題:避免I/O操作象颖、反序列化佩厚、網(wǎng)絡(luò)操作、布局嵌套等说订。

備注:方向1屬于治標(biāo)不治本抄瓦,只是表面上快;方向2陶冷、3可以真實(shí)的加快啟動(dòng)速度钙姊。
接下來我們就在項(xiàng)目中實(shí)際應(yīng)用。

三埂伦、啟動(dòng)加速之主題切換

按照官方文檔的說明:使用Activity的windowBackground主題屬性來為啟動(dòng)的Activity提供一個(gè)簡(jiǎn)單的drawable煞额。
Layout XML file:

Picture

Manifest file:

Picture
Picture

這樣在啟動(dòng)的時(shí)候,會(huì)先展示一個(gè)界面,這個(gè)界面就是Manifest中設(shè)置的Style膊毁,等Activity加載完畢后胀莹,再去加載Activity的界面,而在Activity的界面中媚媒,我們將主題重新設(shè)置為正常的主題嗜逻,從而產(chǎn)生一種快的感覺涩僻。不過如上文總結(jié)這種方式其實(shí)并沒有真正的加速啟動(dòng)過程缭召,而是通過交互體驗(yàn)來優(yōu)化了展示的效果。
**備注:截圖同樣來自官方文檔《Launch-Time Performance》 **逆日。

四嵌巷、啟動(dòng)加速之Avoid Heavy App Initialization

通過代碼分析我們可以得到App啟動(dòng)的業(yè)務(wù)工作流程圖:

Picture

這一章節(jié)我們重點(diǎn)關(guān)注初始化的部分:在Application以及首屏Activity中我們主要做了:

  • **MultiDex以及Tinker的初始化,最先執(zhí)行室抽;關(guān)于MultiDex的優(yōu)化本文不再贅述搪哪,參考我之前

  • Application中主要做了各種三方組件的初始化;

項(xiàng)目中除聽云之外其余所有三方組件都搶占先機(jī)坪圾,在Application主線程初始化晓折。這樣的初始化方式肯定是過重的:

  • 考慮異步初始化三方組件,不阻塞主線程兽泄;

  • 延遲部分三方組件的初始化漓概;實(shí)際上我們粗粒度的把所有三方組件都放到異步任務(wù)里,可能會(huì)出現(xiàn)WorkThread中尚未初始化完畢但MainThread中已經(jīng)使用的錯(cuò)誤病梢,因此這種情況建議延遲到使用前再去初始化胃珍;

  • 而如何開啟WorkThread同樣也有講究,這個(gè)話題在下文詳談蜓陌。

項(xiàng)目修改:

  • 將友盟觅彰、Bugly、聽云钮热、GrowingIO填抬、BlockCanary等組件放在WorkThread中初始化;

  • 延遲地圖定位隧期、ImageLoader飒责、自有統(tǒng)計(jì)等組件的初始化:地圖及自有統(tǒng)計(jì)延遲4秒,此時(shí)應(yīng)用已經(jīng)打開厌秒;而ImageLoader
    因?yàn)檎{(diào)用關(guān)系不能異步以及過久延遲读拆,初始化從Application延遲到SplashActivity;而EventBus因?yàn)樵貯ctivity中使用所以必須在Application中初始化鸵闪。

Picture

注意:閃屏頁(yè)的2秒停留可以利用檐晕,把耗時(shí)操作延遲到這個(gè)時(shí)間間隔里。

五、啟動(dòng)加速之Diagnosing The Problem

本節(jié)我們實(shí)際定位耗時(shí)的操作辟灰,在開發(fā)階段我們一般使用BlockCanary或者ANRWatchDog找耗時(shí)操作个榕,簡(jiǎn)單明了,但是無法得到每一個(gè)方法的執(zhí)行時(shí)間以及更詳細(xì)的對(duì)比信息芥喇。我們可以通過Method Tracing或者DDMS來獲得更全面詳細(xì)的信息西采。
啟動(dòng)應(yīng)用,點(diǎn)擊 Start Method Tracing继控,應(yīng)用啟動(dòng)后再次點(diǎn)擊械馆,會(huì)自動(dòng)打開剛才操作所記錄下的.trace文件,建議使用DDMS來查看武通,功能更加方便全面霹崎。

Picture
Picture

左側(cè)為發(fā)生的具體線程,右側(cè)為發(fā)生的時(shí)間軸冶忱,下面是發(fā)生的具體方法信息尾菇。注意兩列:Real Time/Call(實(shí)際發(fā)生時(shí)間),Calls+RecurCalls/Total(發(fā)生次數(shù))囚枪;
上圖我們可以得到以下信息:

  • 可以直觀看到MainThread的時(shí)間軸很長(zhǎng)派诬,說明大多數(shù)任務(wù)都是在MainThread中執(zhí)行;

  • 通過Real Time/Call 降序排列可以看到程序中的部分代碼確實(shí)非常耗時(shí)链沼;

  • 在下一頁(yè)可以看出來部分三方SDK也比較耗時(shí)默赂;

即便是耗時(shí)操作,但是只要正確發(fā)生在WorkThread就沒問題忆植。因此我們需要確認(rèn)這些方法執(zhí)行的線程以及發(fā)生的時(shí)機(jī)放可。這些操作如果發(fā)生在主線程,可能不構(gòu)成ANR的發(fā)生條件朝刊,但是卡頓是再算難免的耀里!結(jié)合上章節(jié)圖App冷啟動(dòng)業(yè)務(wù)工作流程圖中業(yè)務(wù)操作以及分析圖失暴,再次查看代碼我們可以看到:部分耗時(shí)操作例如IO讀取等確實(shí)發(fā)生在主線程回窘。事實(shí)上在traceview里點(diǎn)擊執(zhí)行函數(shù)的名稱不僅可以跟蹤到父類及子類的方法耗時(shí),也可以在方法執(zhí)行時(shí)間軸中看到具體在哪個(gè)線程以及耗時(shí)的界面閃動(dòng)莽囤。

分析到部分耗時(shí)操作發(fā)生在主線程咙鞍,那我們把耗時(shí)操作都改到子線程是不是就萬事大吉了房官?非也!续滋!

  • 卡頓不能都靠異步來解決翰守,錯(cuò)誤的使用工程線程不僅不能改善卡頓,反而可能加劇卡頓疲酌。是否需要開啟工作線程需要根據(jù)具體的性能瓶頸根源具體分析蜡峰,對(duì)癥下藥了袁,不可一概而論;

  • 而如何開啟線程同樣也有學(xué)問:Thread湿颅、ThreadPoolExecutor载绿、AsyncTask、HandlerThread油航、IntentService等都各有利弊崭庸;例如通常情況下ThreadPoolExecutor比Thread更加高效、優(yōu)勢(shì)明顯谊囚,但是特定場(chǎng)景下單個(gè)時(shí)間點(diǎn)的表現(xiàn)Thread會(huì)比ThreadPoolExecutor好:同樣的創(chuàng)建對(duì)象怕享,ThreadPoolExecutor的開銷明顯比Thread大;

  • 正確的開啟線程也不能包治百病秒啦,例如執(zhí)行網(wǎng)絡(luò)請(qǐng)求會(huì)創(chuàng)建線程池熬粗,而在Application中正確的創(chuàng)建線程池勢(shì)必也會(huì)降低啟動(dòng)速度;因此延遲操作也必不可少余境。

通過對(duì)traceview的詳細(xì)跟蹤以及代碼的詳細(xì)比對(duì),我發(fā)現(xiàn)卡頓發(fā)生在

  • 部分?jǐn)?shù)據(jù)庫(kù)及IO的操作發(fā)生在首屏Activity主線程灌诅;

  • Application中創(chuàng)建了線程池芳来;

  • 首屏Activity網(wǎng)絡(luò)請(qǐng)求密集;

  • 工作線程使用未設(shè)置優(yōu)先級(jí)猜拾;

  • 信息未緩存即舌,重復(fù)獲取同樣信息;

  • 流程問題:例如閃屏圖每次下載挎袜,當(dāng)次使用顽聂;

以及其它細(xì)節(jié)問題:

  • 執(zhí)行無用老代碼;

  • 執(zhí)行開發(fā)階段使用的代碼盯仪;

  • 執(zhí)行重復(fù)邏輯紊搪;

  • 調(diào)用三方SDK里或者Demo里的多余代碼;
    項(xiàng)目修改:
    1. 數(shù)據(jù)庫(kù)及IO操作都移到工作線程全景,并且設(shè)置線程優(yōu)先級(jí)為THREAD_PRIORITY_BACKGROUND耀石,這樣工作線程最多能獲取到10%的時(shí)間片,優(yōu)先保證主線程執(zhí)行爸黄。

2. 流程梳理滞伟,延后執(zhí)行;
實(shí)際上炕贵,這一步對(duì)項(xiàng)目啟動(dòng)加速最有效果梆奈。通過流程梳理發(fā)現(xiàn)部分流程調(diào)用時(shí)機(jī)偏早、失誤等称开,例如:

  • 更新等操作無需在首屏尚未展示就調(diào)用亩钟,造成資源競(jìng)爭(zhēng);

  • 調(diào)用了IOS為了規(guī)避審核而做的開關(guān),造成網(wǎng)絡(luò)請(qǐng)求密集径荔;

  • 自有統(tǒng)計(jì)在Application的調(diào)用里創(chuàng)建數(shù)量固定為5的線程池督禽,造成資源競(jìng)爭(zhēng),在上圖traceview功能說明圖中最后一行可以看到編號(hào)12執(zhí)行5次总处,耗時(shí)排名前列狈惫;此處線程池的創(chuàng)建是必要但可以延后的。

  • 修改廣告閃屏邏輯為下次生效鹦马。

3.其它優(yōu)化胧谈;

  • 去掉無用但被執(zhí)行的老代碼;

  • 去掉開發(fā)階段使用但線上被執(zhí)行的代碼荸频;

  • 去掉重復(fù)邏輯執(zhí)行代碼菱肖;

  • 去掉調(diào)用三方SDK里或者Demo里的多余代碼;

  • 信息緩存旭从,常用信息只在第一次獲取稳强,之后從緩存中取和悦;

  • 項(xiàng)目是多進(jìn)程架構(gòu)退疫,只在主進(jìn)程執(zhí)行Application的onCreate();

Picture

通過以上三步及三方組件的優(yōu)化:Application以及首屏Activity回調(diào)期間主線程就沒有耗時(shí)鸽素、爭(zhēng)搶資源等情況了褒繁。此外還涉及布局優(yōu)化、內(nèi)存優(yōu)化等部分技術(shù)馍忽,因?qū)τ趹?yīng)用冷啟動(dòng)一般不是瓶頸點(diǎn)棒坏,這里不展開詳談,可根據(jù)實(shí)際項(xiàng)目實(shí)際處理遭笋。

六坝冕、對(duì)比效果:

通過ADB命令統(tǒng)計(jì)應(yīng)用的啟動(dòng)時(shí)間:adb shell am start -W 首屏Activity。
同等條件下使用MX3及Nexus6P坐梯,啟動(dòng)5次徽诲,比較優(yōu)化前與優(yōu)化后的啟動(dòng)時(shí)間;

優(yōu)化前:
MX3

ThisTime TotalTime WaitTime
1237 2205 2214
1280 2181 2189
1622 2508 2513
1485 2434 2443
1442 2418 2429

Nexus6P

ThisTime TotalTime WaitTime
1229 1832 1868
1268 1849 1880
1184 1780 1812
1262 1845 1876
1164 1766 1807

優(yōu)化后:
MX3

ThisTime TotalTime WaitTime
865 1516 1523
911 1565 1573
812 1406 1418
962 1564 1574
925 1566 1577

Nexus6P

ThisTime TotalTime WaitTime
603 1192 1243
614 1076 1115
650 1120 1163
642 1107 1139
624 1084 1124

對(duì)比:
MX3提升35%

對(duì)比 ThisTime平均數(shù) TotalTime平均數(shù) WaitTime平均數(shù)
優(yōu)化前 1413 2349 2357
優(yōu)化后 895 1523 1533

Nexus6P提升39%

對(duì)比 ThisTime平均數(shù) TotalTime平均數(shù) WaitTime平均數(shù)
優(yōu)化前 1221 1814 1848
優(yōu)化后 626 1115 1156
  • 命令含義:
    ThisTime:最后一個(gè)啟動(dòng)的Activity的啟動(dòng)耗時(shí)吵血;

TotalTime:自己的所有Activity的啟動(dòng)耗時(shí)谎替;
WaitTime: ActivityManagerService啟動(dòng)App的Activity時(shí)的總時(shí)間(包括當(dāng)前Activity的onPause()和自己Activity的啟動(dòng))。

七蹋辅、問題:

1钱贯、還可以繼續(xù)優(yōu)化的方向?

  • 項(xiàng)目里使用Retrofit網(wǎng)絡(luò)請(qǐng)求庫(kù)侦另,F(xiàn)astConverterFactory做Json解析器秩命,TraceView中看到FastConverterFactory在創(chuàng)建過程中也比較耗時(shí)尉共,考慮將其換為GsonConverterFactory。但是因?yàn)轭惖睦^承關(guān)系短時(shí)間內(nèi)無法直接替換弃锐,作為優(yōu)化點(diǎn)暫時(shí)遺留袄友;

  • 可以考慮根據(jù)實(shí)際情況將啟動(dòng)時(shí)部分接口合并為一,減少網(wǎng)絡(luò)請(qǐng)求次數(shù)霹菊,降低頻率剧蚣;

  • 相同功能的組件只保留一個(gè),例如:友盟旋廷、GrowingIO鸠按、自有統(tǒng)計(jì)等功能重復(fù);

  • 使用ReDex 進(jìn)行優(yōu)化饶碘;實(shí)驗(yàn)Redex發(fā)現(xiàn)Apk體積確實(shí)是小了一點(diǎn)目尖,但是啟動(dòng)速度沒有變化,或許需要繼續(xù)研究扎运。

2瑟曲、異步、延遲初始化及操作的依據(jù)绪囱?
注意一點(diǎn):并不是每一個(gè)組件的初始化以及操作都可以異步或延遲测蹲;是否可以取決組件的調(diào)用關(guān)系以及自己項(xiàng)目具體業(yè)務(wù)的需要。保證一個(gè)準(zhǔn)則:可以異步的都異步鬼吵,不可以異步的盡量延遲。讓應(yīng)用先啟動(dòng)篮赢,再操作齿椅。

3、通用應(yīng)用啟動(dòng)加速套路启泣?

  • 利用主題快速顯示界面涣脚;

  • 異步初始化組件;

  • 梳理業(yè)務(wù)邏輯寥茫,延遲初始化組件遣蚀、操作;

  • 正確使用線程纱耻;

  • 去掉無用代碼芭梯、重復(fù)邏輯等。

4弄喘、其它

  • 將啟動(dòng)速度加快了35%不代表之前的代碼都是問題玖喘,從業(yè)務(wù)角度上將,代碼并沒有錯(cuò)誤蘑志,實(shí)現(xiàn)了業(yè)務(wù)需求累奈。但是在啟動(dòng)時(shí)這個(gè)注重速度的階段贬派,忽略的細(xì)節(jié)就會(huì)導(dǎo)致性能的瓶頸。

  • 開發(fā)過程中澎媒,對(duì)核心模塊與應(yīng)用階段如啟動(dòng)時(shí)搞乏,使用TraceView進(jìn)行分析,盡早發(fā)現(xiàn)瓶頸戒努。

    360°Android app全方位性能調(diào)優(yōu).png

大綱與資料.png
高清視頻資料.jpg

+qq群:853967238请敦。獲取以上高清技術(shù)思維圖,以及相關(guān)技術(shù)的免費(fèi)視頻學(xué)習(xí)資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柏卤,一起剝皮案震驚了整個(gè)濱河市冬三,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缘缚,老刑警劉巖勾笆,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異桥滨,居然都是意外死亡窝爪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門齐媒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒲每,“玉大人,你說我怎么就攤上這事喻括⊙樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵唬血,是天一觀的道長(zhǎng)望蜡。 經(jīng)常有香客問我,道長(zhǎng)拷恨,這世上最難降的妖魔是什么脖律? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮腕侄,結(jié)果婚禮上小泉,老公的妹妹穿的比我還像新娘。我一直安慰自己冕杠,他們只是感情好微姊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拌汇,像睡著了一般柒桑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上噪舀,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天魁淳,我揣著相機(jī)與錄音飘诗,去河邊找鬼。 笑死界逛,一個(gè)胖子當(dāng)著我的面吹牛昆稿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播息拜,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼溉潭,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了少欺?” 一聲冷哼從身側(cè)響起喳瓣,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赞别,沒想到半個(gè)月后畏陕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仿滔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年惠毁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崎页。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鞠绰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出飒焦,到底是詐尸還是另有隱情蜈膨,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布牺荠,位于F島的核電站丈挟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏志电。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一蛔趴、第九天 我趴在偏房一處隱蔽的房頂上張望挑辆。 院中可真熱鬧,春花似錦孝情、人聲如沸鱼蝉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)魁亦。三九已至,卻和暖如春羔挡,著一層夾襖步出監(jiān)牢的瞬間洁奈,已是汗流浹背间唉。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留利术,地道東北人呈野。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像印叁,于是被迫代替她去往敵國(guó)和親被冒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載自一觸即發(fā) App啟動(dòng)優(yōu)化最佳實(shí)踐 一觸即發(fā) App啟動(dòng)優(yōu)化最佳實(shí)踐 文中的很多圖都是Google性能優(yōu)化指南...
    CP9閱讀 601評(píng)論 0 3
  • 應(yīng)用啟動(dòng)類型 冷啟動(dòng)場(chǎng)景:開機(jī)后第一次啟動(dòng)應(yīng)用 或者 應(yīng)用被殺死后再次啟動(dòng)生命周期:Process.start->...
    please邊去閱讀 2,202評(píng)論 0 2
  • 青的故事閱讀 362評(píng)論 0 0
  • 最近一段時(shí)間轮蜕,我在朋友圈很不活躍昨悼,而且就算發(fā)圈,也是比較負(fù)面情緒跃洛。 非常感謝默默關(guān)心率触,關(guān)注和支持我的朋友們,很感激...
    是晶晶啊閱讀 276評(píng)論 0 4
  • 1.什么是runloop税课? RunLoop是通過內(nèi)部維護(hù)的事件循環(huán)來對(duì)事件/消息進(jìn)行管理的一個(gè)對(duì)象闲延。 事件循環(huán) 沒...
    細(xì)雨菲菲v閱讀 377評(píng)論 0 1