公共技術(shù)點(diǎn)之 Android 動畫基礎(chǔ)
公共技術(shù)點(diǎn)之 Java 動態(tài)代理
公共技術(shù)點(diǎn)之依賴注入
公共技術(shù)點(diǎn)之 View 事件傳遞
公共技術(shù)點(diǎn)之 View 繪制流程
一捐韩、Android的Framework和Android apk的打包過程
底層的Binder驅(qū)動拯辙,IPC的核心就缆,SGL 2D繪圖吁脱,OpenGL 3D繪圖
二持隧、多線程
AsyncTask:
AsyncTask的缺陷和問題
關(guān)于線程池:asynctask對應(yīng)的線程池ThreadPoolExecutor都是進(jìn)程范圍內(nèi)共享的即硼,都是static的,所以是asynctask控制著進(jìn)程范圍內(nèi)所有的子類實(shí)例屡拨。由于這個限制的存在只酥,當(dāng)使用默認(rèn)線程池時,如果線程數(shù)超過線程池的最大容量呀狼,線程池就會爆掉(3.0后默認(rèn)串行執(zhí)行裂允,不會出現(xiàn)這個問題)。針對這種情況哥艇,可以嘗試自定義線程池绝编,配合asynctask使用。
關(guān)于默認(rèn)線程池:核心線程池中最多有CPU_COUNT+1個她奥,最多有CPU_COUNT*2+1個瓮增,線程等待隊列的最大等待數(shù)為128,但是可以自定義線程池哩俭。線程池是由AsyncTask來管理的绷跑,線程池允許tasks并行運(yùn)行,xuyao注意的是并發(fā)情況下數(shù)據(jù)的一致性問題凡资,新數(shù)據(jù)可能會被老數(shù)據(jù)覆蓋掉砸捏,類似volatile變量。所以希望tasks能夠串行運(yùn)行的話隙赁,使用SERIAL_EXECUTOR垦藏。
自定義線程池:executeOnExecutor(Executor exec,Params… params) 自定義Executor
execute(Params… params){return executeOnExecutor(sDefaultExecutor,params);}
AsyncTask在不同的SDK版本中的區(qū)別:
調(diào)用AsyncTask的excute方法不能立即執(zhí)行程序的原因分析及改善方案
通過查閱官方文檔發(fā)現(xiàn),AsyncTask首次引入時伞访,異步任務(wù)是在一個獨(dú)立的線程中順序的執(zhí)行掂骏,也就是說一次只能執(zhí)行一個任務(wù),不能并行的執(zhí)行厚掷,從1.6開始弟灼,AsyncTask引入了線程池级解,支持同時執(zhí)行5個異步任務(wù),也就是說同時只能有5個線程運(yùn)行田绑,超過的線程只能等待勤哗,等待前面的線程某個執(zhí)行完了才被調(diào)度和運(yùn)行。換句話說掩驱,如果一個進(jìn)程中的AsyncTask實(shí)例個數(shù)超過5個芒划,那么假如前5個都運(yùn)行很長時間的話,那么第6個只能等待機(jī)會了欧穴。這是AsyncTask的一個限制民逼,而且對于2.3以前的版本無法解決。如果你的應(yīng)用需要大量的后臺線程去執(zhí)行任務(wù)苔可,那么你只能放棄使用AsyncTask缴挖,自己創(chuàng)建線程池來管理Thread,或者干脆不用線程池直接使用Thread也無妨焚辅。不得不說,雖然AsyncTask較Thread使用起來方便苟鸯,但是它最多只能同時運(yùn)行5個線程同蜻,這也大大局限了它的實(shí)力,你必須要小心設(shè)計你的應(yīng)用早处,錯開使用AsyncTask的時間湾蔓,盡力做到分時,或者保證數(shù)量不會大于5個砌梆,否則就會遇到上次提到的問題默责。可能是Google意識到了AsyncTask的局限性了莺丑,從Android3.0開始對AsyncTask的API作出了一些調(diào)整:每次只啟動一個線程執(zhí)行一個任務(wù)住涉,完成之后再執(zhí)行第二個任務(wù)蜡饵,也就是相當(dāng)于只有一個后臺線程在執(zhí)行所提交的任務(wù)。
1媒熊、生命周期
很多開發(fā)者會認(rèn)為一個在Activity中創(chuàng)建的AsyncTask會隨著Activity的銷毀而銷毀。然而事實(shí)并非如此坟比。AsyncTask會一直執(zhí)行芦鳍,直到doInBackground()方法執(zhí)行完畢。然后葛账,如果cancel(boolean)被調(diào)用,那么onCancelled(Result result)方法會被執(zhí)行柠衅;否則,執(zhí)行onPostExecute(Result result)方法籍琳。如果我們的Activity銷毀之前菲宴,沒有取消AsyncTask贷祈,這有可能讓我們的AsyncTask崩潰(crash)。因?yàn)樗胍幚淼膙iew已經(jīng)不在了裙顽。所以付燥,我們總是必須確保在銷毀活動之前取消任務(wù)∮蹋總之键科,我們使用AsyncTask需要確保AsyncTask正確的取消。
2漩怎、內(nèi)存泄漏
如果AsyncTask被聲明為Activity的非靜態(tài)的內(nèi)部類勋颖,那么AsyncTask會保留一個對Activity的引用。如果Activity已經(jīng)被銷毀勋锤,AsyncTask的后臺線程還在執(zhí)行饭玲,它將繼續(xù)在內(nèi)存里保留這個引用,導(dǎo)致Activity無法被回收叁执,引起內(nèi)存泄漏茄厘。
3、結(jié)果丟失
屏幕旋轉(zhuǎn)或Activity在后臺被系統(tǒng)殺掉等情況會導(dǎo)致Activity的重新創(chuàng)建谈宛,之前運(yùn)行的AsyncTask會持有一個之前Activity的引用次哈,這個引用已經(jīng)無效,這時調(diào)用onPostExecute()再去更新界面將不再生效吆录。
4窑滞、并行還是串行
在Android1.6之前的版本,AsyncTask是串行的恢筝,在1.6至2.3的版本哀卫,改成了并行的撬槽。在2.3之后的版本又做了 修改带斑,可以支持并行和串行敢靡,當(dāng)想要串行執(zhí)行時赶站,直接執(zhí)行execute()方法,如果需要執(zhí)行executeOnExecutor(Executor)瑟蜈。
三乔宿、Android機(jī)制
1、Linux Sandbox 沙箱機(jī)制:Android將數(shù)據(jù)分為system和data兩個區(qū)驳庭。其中system是只讀的狼讨,dada用來存放應(yīng)用自己的數(shù)據(jù)布隔,這保證了系統(tǒng)數(shù)據(jù)不會被隨意改寫招刨。
應(yīng)用之間的數(shù)據(jù)相互獨(dú)立,每個應(yīng)用都會有一個user id和group id哀军,只有相同的user id并且來自同一個作者沉眶,才能訪問它們的數(shù)據(jù)打却。作者通過對apk簽名來標(biāo)識自己,簽名和uid構(gòu)成了雙重的保證谎倔。
2柳击、用戶權(quán)限機(jī)制:文件權(quán)限,UID,GID
3片习、用戶權(quán)限機(jī)制:Android permission機(jī)制限制應(yīng)用訪問特定的資源捌肴,例如照相機(jī)、網(wǎng)絡(luò)毯侦、外部存儲等api
4哭靖、如何讓兩個app運(yùn)行在同一個進(jìn)程里?
- 1>兩個app要用相同的private key來簽名
- 2>兩個app的Manifest文件中要添加一樣的屬性 android:sharedUserId(設(shè)置成相同的UID)
四侈离、Binder機(jī)制试幽;參考原文
五、NDK
Dalvik虛擬機(jī)在調(diào)用一個成員函數(shù)的時候卦碾,如果發(fā)現(xiàn)該成員函數(shù)是一個JNI方法铺坞,那么就會直接跳到它的地址去執(zhí)行。也就是說洲胖,JNI方法是直接在本地操作系統(tǒng)執(zhí)行的济榨,而不是Dalvik虛擬機(jī)解釋器執(zhí)行。由此也可以看出绿映,JNI方法是Android應(yīng)用程序與本地操作系統(tǒng)直接進(jìn)行通信的一個手段擒滑。
JNI原理:
Dalvik虛擬機(jī)JNI方法的注冊過程分析
例子:當(dāng)libnanosleep.so文件被加載的時候,函數(shù)JNI_OnLoad就會被調(diào)用叉弦。在函數(shù)JNI_OnLoad中丐一,參數(shù)vm描述的是當(dāng)前線程中的Dalvik虛擬機(jī),通過調(diào)用它的成員函數(shù)GetEnv就可以獲得一個JNIEnv對象淹冰。有了這個JNIEnv對象之后库车,我們就可以調(diào)用另外一個函數(shù)jniRegisterNativeMethods來向當(dāng)前進(jìn)程的Dalvik虛擬機(jī)注冊一個JNI方法。
六樱拴、Android系統(tǒng)啟動過程柠衍,App啟動過程
App啟動過程:
從桌面點(diǎn)擊到activity啟動的過程
1、Launcher線程捕獲onclick的點(diǎn)擊事件晶乔,調(diào)用Launcher.startActivitySafely,進(jìn)一步調(diào)用Launcher.startActivity珍坊,最后調(diào)用父類Activity的startActivity。
2瘪弓、Activity和ActivityManagerService交互垫蛆,引入Instrumentation,將啟動請求交給Instrumentation,調(diào)用Instrumentation.execStartActivity袱饭。
3川无、調(diào)用ActivityManagerService的startActivity方法,這里做了進(jìn)程切換(具體過程請查看源碼)虑乖。
4懦趋、開啟Activity,調(diào)用onCreate方法
七疹味、Activity,Fragment,Service生命周期
常見的例子:程序正運(yùn)行著來電話了仅叫,這個程序咋辦呢?中止了唄糙捺,如果中止的時候新出的一個Activity是全屏的onPause->onStop诫咱,恢復(fù)的時候onStart->onResume,如果打斷這個應(yīng)用程序的是一個Theme為Translucent或者Dialog的Activity那么只是onPause,恢復(fù)的時候onResume。
onPause:恢復(fù)的時候onResume
onCreate:在這里創(chuàng)建界面洪灯,做一些數(shù)據(jù)的初始化工作
onStart:到這一步變成用戶可見不可交互的
onPause:到這一步是可見但不可交互的坎缭,系統(tǒng)會停止動畫等消耗CPU的事情,應(yīng)該在這里保存你的一些 數(shù)據(jù)签钩,因?yàn)檫@個時候你的程序的優(yōu)先級降低掏呼,有可能被 系統(tǒng)回收。在這里保存的數(shù)據(jù)铅檩,應(yīng)該在onResume里讀出來憎夷。注意:這個方法里做的事情時間要短,因?yàn)橄乱粋€Activity不會等到這個方法完成才啟動昧旨。
onStop:變得不可見拾给,被下一個Activity覆蓋了(onPause和onStop的區(qū)別是否可見)
onDestroy:這是Activity被干掉前最后一個被調(diào)用方法了,可能是外面類調(diào)用finish方法或者是系統(tǒng)為了節(jié)省空間將它暫時性的干掉兔沃,可以用isFinishing()來判斷它鸣戴,如果你有一個ProgressDialog在線程中轉(zhuǎn)動,請在onDestroy里把它c(diǎn)ancel掉粘拾,不然等線程結(jié)束的時候,調(diào)用Dialog的cancel會拋出異常的创千。
onPause,onstop,onDestroy缰雇,三種狀態(tài)下,Activity都有可能被系統(tǒng)干掉追驴。
啟動另一個Activity然后finish械哟,先調(diào)用舊Activity的onPause方法,然后調(diào)用新的Activity和onCreate->onStart->onResume方法殿雪,然后調(diào)用舊Activity的onStop->onDestroy方法暇咆。
如果沒有調(diào)用finish那么onDestroy方法不會被調(diào)用,而且在onStop之前還會調(diào)用onSavedInstanceState方法
onRestart方法執(zhí)行完了之后還會調(diào)用onStart方法
fragment:[SupportFragmentManager,childFragment]
service:
Android Service的生命周期
android-Service和Thread的區(qū)別
Service和Intent Service:沒啥區(qū)別,只是IntentService在onCreate方法中開啟新的HandlerThread去執(zhí)行爸业。
Service運(yùn)行的進(jìn)程和線程:當(dāng)它運(yùn)行的時候如果是LocalService其骄,那么對應(yīng)的Service是運(yùn)行在主進(jìn)程的main線程上的。如onCreate,onStart這些函數(shù)都是在系統(tǒng)調(diào)用的時候在主進(jìn)程的main線程上運(yùn)行的扯旷。如果是RemoteSevice拯爽,那么對應(yīng)的Service則是運(yùn)行在獨(dú)立的main線程上。
服務(wù)不是單一的進(jìn)程钧忽,服務(wù)沒有自己的進(jìn)程毯炮,應(yīng)用程序可以不同,服務(wù)運(yùn)行在相同的進(jìn)程中
服務(wù)不是線程耸黑,可以在線程中工作
在應(yīng)用中桃煎,如果是長時間的在后臺運(yùn)行,而且不需要交互的情況下大刊,使用服務(wù)
同樣是在后臺運(yùn)行为迈,不需要交互的情況下,如果只是完成某個任務(wù)奈揍,之后就不需要運(yùn)行曲尸,而且可能是多個任務(wù),需要長時間運(yùn)行的情況下使用線程
如果任務(wù)占用CPU時間多男翰,資源大的情況下另患,要使用線程
Thread的運(yùn)行是獨(dú)立于Activity的,也就是說當(dāng)一個Activity被finish之后蛾绎,如果你沒有主動停止Thread或者Thread里的run方法沒有執(zhí)行完畢的話昆箕,Thread就會一直執(zhí)行。