一洋腮、Activity
1.什么是activity?
Activity一個(gè)應(yīng)用程序的組件讼育,它提供一個(gè)屏幕來(lái)與用戶交互帐姻,以便做一些諸如打電話、發(fā)郵件和看地圖之類的事情奶段,原話如下:
An [Activity](http://developer.android.com/reference/android/app/Activity.html)
is an application component that provides a screen with which users can interact in order to do something, such as dial the phone, take a photo, send an email, or view a map.
2.activity四種狀態(tài)
running / paused /stopped / killed
running:處于活動(dòng)狀態(tài)饥瓷,用戶可以點(diǎn)擊屏幕,屏幕會(huì)做出相應(yīng)的響應(yīng)痹籍,處于
activity棧頂?shù)囊粋€(gè)狀態(tài)呢铆。
paused:失去焦點(diǎn)的狀態(tài),或者是被一個(gè)非全屏的activity所占據(jù)蹲缠,又或是被一個(gè)
透明的activity放置再棧頂棺克,只是失去了和用戶交互的能力,所有的狀態(tài)信息和成
員變量都還在线定,除非在內(nèi)存非常緊張的情況下會(huì)被回收娜谊。
stopped:一個(gè)activity被另一個(gè)activity完全覆蓋的時(shí)候,被覆蓋的activtiy的就會(huì)
處于stopped狀態(tài)斤讥,所有的狀態(tài)信息和成員變量都還在纱皆,除非在內(nèi)存非常緊張的
情況下會(huì)被回收。
killed:activity已經(jīng)被系統(tǒng)回收周偎,所有保存的狀態(tài)信息和成員變量都將不存在了抹剩。
3.activity生命周期
-
Activity啟動(dòng)?? onCreate()?? onStart()?? onResume()
onCreate():activity被創(chuàng)建的時(shí)候調(diào)用,生命周期的第一個(gè)調(diào)用方法蓉坎,創(chuàng)建
activity的時(shí)候一定要重寫該方法,可以做一些初始化的操作胡嘿,比如布局資源的加
載或者一些數(shù)據(jù)的加載蛉艾。onStart():表明此時(shí)activity正在啟動(dòng),已經(jīng)處于用戶可見(jiàn)的狀態(tài),當(dāng)然此時(shí)還沒(méi)
有處于前臺(tái)的顯示勿侯,就是說(shuō)此時(shí)用戶還不能與用戶進(jìn)行交互操作拓瞪;總結(jié)就是一個(gè)
可以看見(jiàn)但是無(wú)法觸摸的狀態(tài)。onResume():已經(jīng)在前臺(tái)進(jìn)行展示助琐,可以與用戶進(jìn)行交互了祭埂。
-
點(diǎn)擊Home鍵回到手機(jī)桌面(Activity不可見(jiàn)):onPause()?? onstop()
onPause():activity處于一個(gè)暫停的狀態(tài),可見(jiàn)但是不可交互
onstop():整個(gè)activity表明已經(jīng)完全停止兵钮,或者完全被覆蓋的狀態(tài)蛆橡,完全不可
見(jiàn),處于后臺(tái)的狀態(tài)掘譬,如果處于內(nèi)存緊張的狀態(tài)下就有可能會(huì)被系統(tǒng)回收掉泰演。
-
當(dāng)我們?cè)俅位氐皆瑼ctivity的時(shí)候:onRestart()?? onStart()?? onResume()
onRestart():表示activity正在重新啟動(dòng),是由不可見(jiàn)狀態(tài)變?yōu)榭梢?jiàn)狀態(tài)的時(shí)候調(diào)用
- 退出Activity時(shí):onPause()?? onStop()?? onDestory()
onDestory():當(dāng)前activity正在銷毀葱轩,是生命周期中的最后一個(gè)方法睦焕,可以做一
些回收工作以及資源的釋放
1.onStart和onResume、onPause和onStop從描述上來(lái)看差不多靴拱,對(duì)我們來(lái)說(shuō)有什么實(shí)質(zhì)性的不同呢垃喊?
在實(shí)際使用過(guò)程中的確是沒(méi)有什么具體的區(qū)分,甚至我們可以只保留其中的一對(duì)袜炕,比如onStart和onStop缔御,
但是從代碼回調(diào)的意義層面來(lái)說(shuō),onStart和onStop是從activity是否可見(jiàn)的角度來(lái)回調(diào)的妇蛀,而onResume和onPause是從activity是否處于前臺(tái)這個(gè)角度來(lái)回調(diào)的耕突,除了這個(gè)區(qū)別,實(shí)際使用過(guò)程中并無(wú)其他明顯區(qū)別评架。
2.假設(shè)當(dāng)前Activity為A眷茁,如果這是用戶打開(kāi)一個(gè)新的Activity B,那么B的onResume和A的onPause哪個(gè)先執(zhí)行呢纵诞?
當(dāng)啟動(dòng)一個(gè)新的Activity時(shí)上祈,舊Activity的onPause會(huì)先執(zhí)行,然后才會(huì)啟動(dòng)新的activity浙芙。例如從A activity 點(diǎn)擊按鈕跳轉(zhuǎn)到B Activity時(shí)登刺,生命周期的回調(diào)方法如下圖所示:
3.當(dāng)系統(tǒng)配置發(fā)生改變后,Activity會(huì)被銷毀嗡呼,會(huì)調(diào)用onPause()?? onStop()?? onDestory()纸俭,但是同時(shí)由于activity是異常狀態(tài)下終止的,系統(tǒng)會(huì)調(diào)用onSaveInstanceState來(lái)保存當(dāng)前activity的狀態(tài)南窗,這個(gè)方法一定是在onStop之前被回調(diào)的揍很,但是可能在onPause之前也可能是在之后調(diào)用郎楼,并沒(méi)有一定的時(shí)序。當(dāng)這個(gè)Activity被重新創(chuàng)建之后窒悔,系統(tǒng)會(huì)調(diào)用onCreate呜袁、onStart、onRestoreInstanceState(調(diào)用時(shí)序在onStart之后)简珠,系統(tǒng)調(diào)用onRestoreInstanceState會(huì)把a(bǔ)ctivity銷毀時(shí)調(diào)用的onSaveInstanceState方法保存的Bundle對(duì)象作為參數(shù)傳遞給onRestoreInstanceState和onCreate方法阶界,因此我們可以通過(guò)onRestoreInstanceState和onCreate方法來(lái)判斷activity是否被重建了,那么我們就可以取出之前保存的數(shù)據(jù)并恢復(fù)聋庵。
系統(tǒng)調(diào)用onSaveInstanceState和onRestoreInstanceState后會(huì)自動(dòng)為我們做一些恢復(fù)工作膘融,比如說(shuō)文本框的輸入內(nèi)容,listview的滾動(dòng)位置等珍策。
4.不想讓系統(tǒng)重建Activity托启,可以在AndroidManifest.xml中給activity配置configChanges屬性
常用的屬性有以下幾個(gè):
loacl :設(shè)備的本地位置發(fā)生了改變,一般指切換了系統(tǒng)語(yǔ)言
keyboardHidden: 鍵盤的可訪問(wèn)性發(fā)生了改變攘宙,比如用戶調(diào)出了鍵盤
orientation: 屏幕方向發(fā)生了改變屯耸,這個(gè)是最常用的,比如旋轉(zhuǎn)了手機(jī)屏幕
screenSize:當(dāng)屏幕的尺寸信息發(fā)生了改變蹭劈,比如屏幕旋轉(zhuǎn)疗绣,這個(gè)選項(xiàng)比較特殊,當(dāng)編譯選項(xiàng)中的minSdkVersion和targetSdkVersion均低于13時(shí)铺韧,此選項(xiàng)不會(huì)導(dǎo)致activity重啟多矮,否則大于13時(shí)就會(huì)導(dǎo)致activity重啟,所以當(dāng)這個(gè)配置大于13時(shí)哈打,需要配置configChanges 為 screenSize
4.進(jìn)程優(yōu)先級(jí)
可見(jiàn)進(jìn)程:處于可見(jiàn)但是用戶不可點(diǎn)擊的進(jìn)程
前臺(tái)進(jìn)程:處于前臺(tái)正在與用戶交互的塔逃,或者前臺(tái)activity綁定的service
后臺(tái)進(jìn)程:前臺(tái)進(jìn)程點(diǎn)擊了home鍵回到桌面后,這個(gè)進(jìn)程就會(huì)轉(zhuǎn)變?yōu)楹笈_(tái)進(jìn)
程料仗,不會(huì)立馬被kill掉蔓同,會(huì)根據(jù)內(nèi)存的情況來(lái)做回收驶赏。
服務(wù)進(jìn)程:在后臺(tái)開(kāi)啟的service服務(wù)
空進(jìn)程:五個(gè)進(jìn)程中優(yōu)先級(jí)最低,是一個(gè)沒(méi)有活躍的組件节猿,只是出于緩存的目的
而保留
二涌矢、Activity任務(wù)棧
一個(gè)用來(lái)管理Activity的容器葫掉,后進(jìn)先出的棧管理模式誊锭,一個(gè)應(yīng)用中可以有多個(gè)任
務(wù)棧撩独,也可以只有一個(gè)任務(wù)棧,這得根據(jù)啟動(dòng)模式來(lái)決定胜卤。
三疆导、Activity啟動(dòng)模式
1.standard
每次啟動(dòng)activity都會(huì)重新創(chuàng)建一個(gè)activity的實(shí)例,然后將它加到任務(wù)棧中瑰艘,不會(huì)
去考慮任務(wù)棧是否有該activity的實(shí)例是鬼,默認(rèn)的情況就是此種啟動(dòng)模式肤舞。如果activity A啟動(dòng)了Activity B(B是標(biāo)準(zhǔn)模式)紫新,B就會(huì)進(jìn)入到A所在的棧中均蜜,如果用ApplicationContext去啟動(dòng)standard模式的Activity會(huì)報(bào)錯(cuò),因?yàn)锳pplicationContext并沒(méi)有所謂的任務(wù)棧芒率。
2.singleTop(棧頂復(fù)用模式)
如果需要?jiǎng)?chuàng)建的activity實(shí)例剛好處于任務(wù)棧的棧頂囤耳,那么就不會(huì)再去創(chuàng)建一個(gè)新
的activity實(shí)例了,而是復(fù)用這個(gè)棧頂?shù)腶ctivity偶芍,同時(shí)它的onNewIntent方法會(huì)被回調(diào)充择,但是他的onCreate()、 onStart()不會(huì)被調(diào)用匪蟀,因?yàn)樗](méi)有改變椎麦。如果新的activity實(shí)例已經(jīng)存在但是不是位于棧頂,那么新的activity任然會(huì)重新重建材彪。
3.singleTask(棧內(nèi)復(fù)用模式)
是一個(gè)單例模式观挎,當(dāng)需要?jiǎng)?chuàng)建一個(gè)activity的時(shí)候,會(huì)去檢測(cè)整個(gè)任務(wù)棧中是否存
在該activity實(shí)例段化,如果存在嘁捷,會(huì)將其置于任務(wù)棧的棧頂,并將處于該activity以上
的activity都移除銷毀显熏,這時(shí)會(huì)回調(diào)一個(gè)onNewIntent()方法雄嚣。
- 補(bǔ)充
<activity android:name=".MainActivity" android:launchMode="singleTask" android:taskAffinity="com.demo.singletask"/>
默認(rèn)情況下taskAffinity的值就是包名,taskAffinity相同就說(shuō)明是在同一個(gè)棧中喘蟆,TaskId即一樣
taskAffinity屬性主要和singleTask啟動(dòng)模式或者allowTaskReparenting屬性配對(duì)使用缓升。
當(dāng)taskAffinity和singleTask啟動(dòng)模式配對(duì)使用的時(shí)候,它是具有該模式的activity的目前任務(wù)棧的名字蕴轨,待啟動(dòng)的activity會(huì)運(yùn)行在名字和taskAffinity相同的任務(wù)棧中
當(dāng)taskAffinity和allowTaskReparenting結(jié)合港谊,allowTaskReparenting用于配置是否允許該activity可以更換從屬task,通常情況二者連在一起使用尺棋,用于實(shí)現(xiàn)把一個(gè)應(yīng)用程序的Activity移到另一個(gè)應(yīng)用程序的Task中
4. singleInstance
singleTask的升級(jí)版封锉,整個(gè)系統(tǒng)中只有一個(gè)實(shí)例,啟動(dòng)一singleInstanceActivity
時(shí)膘螟,系統(tǒng)會(huì)創(chuàng)建一個(gè)新的任務(wù)棧成福,并且這個(gè)任務(wù)棧只有他一個(gè)Activity,一般用于
多個(gè)應(yīng)用之間的跳轉(zhuǎn)荆残。
- singleTask與singleTask的卻別:
一個(gè)系統(tǒng)中可能存在多個(gè)singleTask Activity實(shí)例奴艾,
一個(gè)系統(tǒng)中只能存在一個(gè)singleInstance Activity實(shí)例。
設(shè)置activity的啟動(dòng)模式
1.在AndroidManifest.xml中設(shè)置
<activity
android:name="com.zsw.demo.activity.CallProgramAcitivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/MaterialNoTitle"
android:launchMode="singleTask"/>
2.通過(guò)在Intent中設(shè)置標(biāo)志位
Intent intent = new Intent();
intent.setClass(this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
四内斯、scheme跳轉(zhuǎn)協(xié)議
android中的scheme是一種頁(yè)面內(nèi)跳轉(zhuǎn)協(xié)議蕴潦,是一種非常好的實(shí)現(xiàn)機(jī)制像啼,通過(guò)定義自己的scheme協(xié)議,可以非常方便的跳轉(zhuǎn)app中的各個(gè)頁(yè)面潭苞;通過(guò)scheme協(xié)議忽冻,服務(wù)器可以定制化的告訴app跳轉(zhuǎn)哪個(gè)頁(yè)面,可以通過(guò)消息欄定義化跳轉(zhuǎn)頁(yè)面此疹,可以通過(guò)H5頁(yè)面跳轉(zhuǎn)頁(yè)面等僧诚。
二、Fragment
1.Fragment為什么被稱為第五大組件
首先在使用上是不屬于其他四大組件的蝗碎,它有自己的生命周期湖笨,同時(shí)它可以靈活
動(dòng)態(tài)的加載到activity中去,同時(shí)它并不是像activity一樣完全獨(dú)立的蹦骑,它必須依附
于activity慈省,而且還需要加載到activity中去。
2.Fragment加載到Activity中的兩種方式
靜態(tài)加載:只需要把Fragment當(dāng)成一個(gè)普通UI控件放到界面Layout中就完事了
動(dòng)態(tài)加載:得先通過(guò)FragmentManage來(lái)獲取FragmentTransaction(事務(wù))眠菇,然后使用add或者replace的方式加載fragment边败,最后commit提交事物。
3.FragmentPagerAdapter與FragmentStatePagerAdapter的區(qū)別
FragmentPagerAdapter適用于頁(yè)面較少的情況下琼锋,在源碼中destoryItem()函數(shù)中的最后一行可以看到放闺,調(diào)用的是detach方法,該方法的作用是將fragment與activity的關(guān)聯(lián)取消掉缕坎,并沒(méi)有做內(nèi)存回收處理怖侦,所以會(huì)更加的消耗內(nèi)存
FragmentStatePagerAdapter適用于頁(yè)面較多的情況下,查看源碼可發(fā)現(xiàn)調(diào)用的是remove的方法谜叹,會(huì)進(jìn)行內(nèi)存回收處理匾寝。
4.commit和commitAllowingStateLoss區(qū)別
commit:該方法必須在存儲(chǔ)狀態(tài)之前調(diào)用,也就是onSaveInstanceState()荷腊,如果在存儲(chǔ)狀態(tài)之后調(diào)用就會(huì)報(bào)出:
Can not perform this action after onSaveInstanceState錯(cuò)誤信息
commitAllowingStateLoss:允許在存儲(chǔ)狀態(tài)之后再調(diào)用艳悔,但是這是危險(xiǎn)的,因?yàn)槿绻鸻ctivity需要從其狀態(tài)恢復(fù)女仰,那么提交就會(huì)丟失猜年,因此,只有在用戶可以意外的更改UI狀態(tài)的情況下疾忍,才可以使用該提交乔外。
以下是部分的核心源碼:
5.Fragment的生命周期
下面列出兩張圖,第一張可用于面試記憶一罩,第二張可以詳細(xì)的摸索清楚activity與
fragment生命周期的走向杨幼。
onAttach:將fragment與activity關(guān)聯(lián)
onCreate:初次創(chuàng)建fragment時(shí)調(diào)用,只是用來(lái)創(chuàng)建fragment,此時(shí)的activity并沒(méi)有創(chuàng)建完成
onCreateView:系統(tǒng)在fragment首次繪制界面的時(shí)候調(diào)用
onViewCreated:fragment的界面已經(jīng)繪制完畢差购。
Activity - onCreate:初始化activity中的布局
onActivityCreate:activity渲染繪制完畢
Activity - onStart:activity可見(jiàn)但不可交互操作
onStart:fragment可見(jiàn)但不可交互操作
Activity - onResume:activity已經(jīng)在前臺(tái)進(jìn)行展示四瘫,可以與用戶進(jìn)行交互了
onResume:fragment已經(jīng)在前臺(tái)進(jìn)行展示,可以與用戶進(jìn)行交互了
onPause:fragment處于一個(gè)暫停的狀態(tài)欲逃,可見(jiàn)但是不可交互
Activity - onPause:activity處于一個(gè)暫停的狀態(tài)找蜜,可見(jiàn)但是不可交互
onStop:fragment不可見(jiàn)
Activity - onStop:activity不可見(jiàn)
onDestoryView:與onCreateView關(guān)聯(lián),fragment即將結(jié)束會(huì)被保存
onDestory:銷毀Fragment暖夭,通常按Back鍵退出或者Fragment被回收時(shí)調(diào)用此方法
onDetach:會(huì)將fragment從activity中移除,和remove()不同,此時(shí)fragment的狀態(tài)依然由FragmentManager維護(hù)
Activity - onDesroty:activity銷毀
3.Fragment之間的通信
在Fragment中獲取Activity中的方法:getActivity
在Activity中獲取Fragment中的方法:接口回調(diào)
在Fragment中獲取Fragment中的方法:先使用getActivity獲取到activity锹杈,然后使
用getFragmentById
三撵孤、Service
1.service是什么
service(服務(wù))是一個(gè)可以在用戶后臺(tái)執(zhí)行長(zhǎng)時(shí)間操作,而沒(méi)有用戶界面的應(yīng)用組件
注意:service是運(yùn)行在主線程中的迈着,絕對(duì)是不能做耗時(shí)操作的。
請(qǐng)勿將服務(wù)與子線程混為一談
2.兩種啟動(dòng)service的方式
startService
1邪码、定義一個(gè)類繼承Service
2裕菠、在Manifest.xml文件中配置該service
3、使用Context中的startService(Intent)方法啟動(dòng)該Service
4闭专、不使用時(shí)奴潘,使用stopService(Intent)方法停止該服務(wù)
5、onCreate()方法只會(huì)調(diào)用一次, onStartCommand()方法可以重復(fù)調(diào)用
6影钉、服務(wù)一旦啟動(dòng)画髓,服務(wù)即可在后臺(tái)無(wú)限期的運(yùn)行,即便啟動(dòng)服務(wù)的組件被銷毀
了也不會(huì)受影響平委,除非手動(dòng)關(guān)閉奈虾,已啟動(dòng)的服務(wù)通常是執(zhí)行單一操作,而且不會(huì)
將結(jié)果返回給調(diào)用方bindService
1廉赔、創(chuàng)建BindService服務(wù)端肉微,繼承自service并在類中,創(chuàng)建一個(gè)實(shí)現(xiàn)IBinder接
口的實(shí)例對(duì)象并提供公共方法給客戶端使用
2蜡塌、從onBind()回調(diào)方法返回此Binder實(shí)例
3碉纳、在客戶端中,從onServiceConncted()回調(diào)方法接收Binder馏艾,并使用提供的方法調(diào)用綁定服務(wù)
4劳曹、當(dāng)應(yīng)用組件通過(guò)調(diào)用 bindService() 綁定到服務(wù)時(shí),服務(wù)即處于“綁定”狀態(tài)琅摩。
綁定服務(wù)提供了一個(gè)客戶端-服務(wù)器接口铁孵,允許組件與服務(wù)進(jìn)行交互、發(fā)送請(qǐng)求迫吐、
獲取結(jié)果库菲,甚至是利用進(jìn)程間通信 (IPC) 跨進(jìn)程執(zhí)行這些操作。 僅當(dāng)與另一個(gè)應(yīng)
用組件綁定時(shí)志膀,綁定服務(wù)才會(huì)運(yùn)行熙宇。 多個(gè)組件可以同時(shí)綁定到該服務(wù)鳖擒,但全部取
消綁定后,該服務(wù)即會(huì)被銷毀
四烫止、Broadcast receiver
1.廣播定義
在Android中蒋荚,Broadcast是一種廣泛運(yùn)用在應(yīng)用程序之間傳輸信息的機(jī)制,我們
要發(fā)送的廣播內(nèi)容是一個(gè)Intent馆蠕,這個(gè)Itent中可以攜帶我們需要傳輸?shù)臄?shù)據(jù)期升。
2.廣播的使用場(chǎng)景
1、同一app具有多個(gè)進(jìn)程的不同組件之間的消息通信
2互躬、不同app之間的組件之間消息通信
3.廣播種類
1播赁、普通廣播(Normal Broadcast):Context.sendBroadcast
2、系統(tǒng)廣播(System Broadcast):Android中內(nèi)置了多個(gè)系統(tǒng)廣播,只要涉及到手
機(jī)的基本操作(如開(kāi)機(jī)吼渡、網(wǎng)絡(luò)狀態(tài)變化容为、拍照等等),都會(huì)發(fā)出相應(yīng)的廣播
2寺酪、有序廣播(Ordered Broadcast):Context.sendOrderedBroadcast
3坎背、本地廣播(Local Broadcast):只在app內(nèi)傳播
4.廣播的實(shí)現(xiàn)
1、靜態(tài)注冊(cè):在AndroidManifest中注冊(cè)就可以寄雀,注冊(cè)完成就一直運(yùn)行得滤,如果它
所依賴的activity銷毀了,仍然能夠接受廣播盒犹,甚至app 進(jìn)程殺死仍然能夠接受廣
播
2懂更、動(dòng)態(tài)注冊(cè):跟隨activity生命周期,在代碼中調(diào)用Context.registerReceiver方法
// 選擇在Activity生命周期方法中的onResume()中注冊(cè)
@Override
protected void onResume(){
super.onResume();
// 1. 實(shí)例化BroadcastReceiver子類 & IntentFilter
mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
// 2. 設(shè)置接收廣播的類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
// 3. 動(dòng)態(tài)注冊(cè):調(diào)用Context的registerReceiver()方法
registerReceiver(mBroadcastReceiver, intentFilter);
}
// 注冊(cè)廣播后,要在相應(yīng)位置記得銷毀廣播
// 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
// 當(dāng)此Activity實(shí)例化時(shí)阿趁,會(huì)動(dòng)態(tài)將MyBroadcastReceiver注冊(cè)到系統(tǒng)中
// 當(dāng)此Activity銷毀時(shí)膜蛔,動(dòng)態(tài)注冊(cè)的MyBroadcastReceiver將不再接收到相應(yīng)的廣播。
@Override
protected void onPause() {
super.onPause();
//銷毀在onResume()方法中的廣播
unregisterReceiver(mBroadcastReceiver);
}
}
??特別注意
動(dòng)態(tài)廣播最好在Activity 的 onResume()注冊(cè)脖阵、onPause()注銷皂股。
原因:
對(duì)于動(dòng)態(tài)廣播,有注冊(cè)就必然得有注銷命黔,否則會(huì)導(dǎo)致內(nèi)存泄露
重復(fù)注冊(cè)呜呐、重復(fù)注銷也不允許
5.廣播內(nèi)部實(shí)現(xiàn)機(jī)制
1、自定義廣播接受者BroadcastReceiver,并復(fù)寫onRecvice()方法悍募;
2蘑辑、接收者通過(guò)Binder機(jī)制向AMS(Activity Manager Service)進(jìn)行注冊(cè);
3坠宴、廣播發(fā)送著通過(guò)Binder機(jī)制向AMS發(fā)送廣播洋魂;
4、AMS查找符合相應(yīng)條件(IntentFilter/Permission等)的BrocastReceiver,將廣播發(fā)送到BrocasrReceiver(一般是Activity)相應(yīng)的循環(huán)隊(duì)列中;
5、消息循環(huán)執(zhí)行拿到該廣播副砍,回調(diào)BrocastReceiver的onRecerve()方法
6.LocalBroadcastManager詳解
1.LocalBroadcastManager高效的原因主要是它的內(nèi)部是通過(guò)Handler實(shí)現(xiàn)的衔肢,
sendBrocast()方法含義并非和我們平時(shí)所用一樣,它的sendBrocast()其實(shí)是通過(guò)
handler發(fā)送一個(gè)Message實(shí)現(xiàn)的
2.既然它內(nèi)部是通過(guò)Handler來(lái)實(shí)現(xiàn)廣播的發(fā)送豁翎,那么相比與系統(tǒng)使用Binder實(shí)現(xiàn)
自然是更加高效了角骤,同時(shí)使用Handler來(lái)實(shí)現(xiàn),別的應(yīng)用無(wú)法向我們的應(yīng)用發(fā)送
廣播心剥,而我們應(yīng)用內(nèi)發(fā)送的廣播也不會(huì)離開(kāi)我們的廣播
五邦尊、Webview
1.WebView安全漏洞
Android API level 16以及之前的版本存在遠(yuǎn)程代碼執(zhí)行安全漏洞,該漏洞源于程
序沒(méi)有正確限制使用addJavascriptInterface方法优烧,遠(yuǎn)程攻擊者可通過(guò)使用
Java Reflection API 利用該漏洞執(zhí)行任意java對(duì)象的方法
2.WebView的性能優(yōu)化
如果WebView是使用xml進(jìn)行加載的往往在關(guān)閉Activity的時(shí)候WebView的資源并不會(huì)隨著Activity的銷毀而銷毀蝉揍。
網(wǎng)上推薦的方法解決大體分為2種:
一種是使用代碼動(dòng)態(tài)的創(chuàng)建WebView,對(duì)傳入WebView中的Context使用弱引用,
動(dòng)態(tài)添加WebView的意思是在布局創(chuàng)建一個(gè)ViewGroup用來(lái)放置
WebView,Activity創(chuàng)建時(shí)add進(jìn)來(lái)匙隔,在Activity停止時(shí)remove掉
第二種是為WebView新開(kāi)一個(gè)進(jìn)程疑苫,不過(guò)這樣的話使用起來(lái)會(huì)比較麻煩,效果還
是挺簡(jiǎn)單粗暴的纷责,據(jù)說(shuō)QQ微信也在使用這種方式:參考
六、Binder
一撼短、Linux內(nèi)核的基礎(chǔ)知識(shí)
1.進(jìn)程隔離/虛擬地址控件
在操作系統(tǒng)中再膳,為了保護(hù)某些進(jìn)程之間的互不干擾,設(shè)計(jì)了一個(gè)叫進(jìn)程隔離的技術(shù)曲横,就是為了避免進(jìn)程A可以去操作進(jìn)程B而實(shí)現(xiàn)的喂柒;進(jìn)程的隔離實(shí)現(xiàn)用到了虛擬地址空間,就是說(shuō)進(jìn)程A的虛擬地址空間和進(jìn)程B的虛擬空間是不一樣的禾嫉,這樣灾杰,就防止了進(jìn)程A的數(shù)據(jù)可以寫到進(jìn)程B中;所以操作系統(tǒng)中不同的進(jìn)程之間數(shù)據(jù)是不共享的熙参,如果需要進(jìn)程間的數(shù)據(jù)通信艳吠,就需要某種進(jìn)程間通信的機(jī)制來(lái)完成,在android中就是使用Binder這個(gè)機(jī)制來(lái)完成的孽椰。
不同進(jìn)程間的引用叫做句柄昭娩,相同進(jìn)程間的應(yīng)用叫做指針,也就是對(duì)進(jìn)程空間中虛擬地址的引用
2.系統(tǒng)調(diào)用
對(duì)內(nèi)核有保護(hù)機(jī)制黍匾,對(duì)于應(yīng)用程序只可以訪問(wèn)某些許可的資源栏渺,不許可的資源是不可以訪問(wèn)的。
3.Binder驅(qū)動(dòng)
在android系統(tǒng)中锐涯,是運(yùn)行在內(nèi)核之中的磕诊;負(fù)責(zé)各個(gè)用戶進(jìn)程通過(guò)Binder通信的內(nèi)核來(lái)交互的模塊叫Binder驅(qū)動(dòng)
二、Binder通信機(jī)制介紹
1.為什么使用Binder
1)Android使用的Linux內(nèi)核擁有著非常多的跨進(jìn)程通信機(jī)制
2)性能:在移動(dòng)設(shè)備上(性能受限制的設(shè)備,比如要省電)霎终,廣泛地使用跨進(jìn)
程通信對(duì)通信機(jī)制的性能有嚴(yán)格的要求融痛,Binder相對(duì)出傳統(tǒng)的Socket方式,更加
高效神僵。Binder數(shù)據(jù)拷貝只需要一次雁刷,而管道、消息隊(duì)列保礼、Socket都需要2次沛励,共
享內(nèi)存方式一次內(nèi)存拷貝都不需要,但實(shí)現(xiàn)方式又比較復(fù)雜炮障。
3)安全:傳統(tǒng)的進(jìn)程通信方式對(duì)于通信雙方的身份并沒(méi)有做出嚴(yán)格的驗(yàn)證目派,比
如Socket通信ip地址是客戶端手動(dòng)填入,很容易進(jìn)行偽造胁赢,而B(niǎo)inder機(jī)制從協(xié)議
本身就支持對(duì)通信雙方做身份校檢企蹭,因而大大提升了安全性
2.Binder通信模型
客戶端進(jìn)程只不過(guò)是持有了我們一個(gè)服務(wù)端的一個(gè)代理
3.到底什么是Binder??
1)通常意義下,binder指的是一種通信機(jī)制
2)對(duì)于Server進(jìn)程來(lái)說(shuō)智末,Binder指的是Binder本地對(duì)象谅摄;
對(duì)于Client對(duì)象來(lái)說(shuō),Binder指的是Binder代理對(duì)象
3)對(duì)于傳輸過(guò)程而言系馆,Binder是可以進(jìn)行跨進(jìn)程傳遞的對(duì)象
七送漠、Handler
1、處理過(guò)程:
從handler中獲取一個(gè)消息對(duì)象由蘑,把數(shù)據(jù)封裝到消息對(duì)象中闽寡,通過(guò)handler的
send…方法把消息push到MessageQueue隊(duì)列中。
Looper對(duì)象會(huì)輪詢MessageQueue隊(duì)列尼酿,把消息對(duì)象取出爷狈。
通過(guò)dispatchMessage分發(fā)給Handler,再回調(diào)用Handler實(shí)現(xiàn)的handleMessage
方法處理消息
2裳擎、Handler中為什么要使用ThreadLocal來(lái)獲取Lopper呢涎永?
因?yàn)樵诓煌€程訪問(wèn)同一ThreadLocal時(shí),不管是set方法還是get方法對(duì)
ThreadLocal所做的讀寫操作僅限與各自線程內(nèi)部句惯,這樣就可以使每一個(gè)線程有
單獨(dú)唯一的Lopper土辩。
ThreadLocal博文
3、Handler引起的內(nèi)存泄漏以及解決辦法
原因:在java中抢野,非靜態(tài)的內(nèi)部類和匿名內(nèi)部類都會(huì)隱式的持有一個(gè)外部類的引
用拷淘,所以原因就是匿名內(nèi)部類持有外部類的引用,導(dǎo)致外部Activity無(wú)法釋放
解決辦法:
1指孤、最直接的思路就是避免使用非靜態(tài)內(nèi)部類启涯。使用Handler的時(shí)候贬堵,放在一個(gè)新建的文件中來(lái)繼承Handler或者使用靜態(tài)的內(nèi)部類來(lái)替代。靜態(tài)內(nèi)部類不會(huì)隱含的持有外部類的引用结洼,因此這個(gè)activity也就不會(huì)出現(xiàn)內(nèi)存泄漏問(wèn)題黎做。
2、如果你需要在Handler內(nèi)部調(diào)用外部Activity的方法松忍,你可以讓這個(gè)Handler持有這個(gè)Activity的弱引用蒸殿,這樣便不會(huì)出現(xiàn)內(nèi)存泄漏的問(wèn)題了。
3鸣峭、另外宏所,對(duì)于匿名類Runnable,我們同樣可以設(shè)置成靜態(tài)的摊溶,因?yàn)殪o態(tài)內(nèi)部類不會(huì)持有外部類的引用爬骤。
4、注意:如果使用Handler發(fā)送循環(huán)消息莫换,最好是在Activity的OnDestroy方法中調(diào)用mLeakHandler.removeCallbacksAndMessages(null);移除消息霞玄。(這不是解決內(nèi)存泄漏的方法)
博文
八、AnsycTask
1.Asynctask是什么?
它是Android提供的一個(gè)抽象類拉岁,他本質(zhì)上就是一個(gè)封裝了線程池和handler的異
步框架坷剧,主要是來(lái)執(zhí)行異步任務(wù)的,由于它內(nèi)部繼承了handler,所以他可以在工
作線程和UI線程中隨意切換膛薛。
注意:Asynctask能夠讓你避免使用線程類thread和handler直接處理后臺(tái)操作听隐,
他可以把運(yùn)算好的結(jié)果交給UI 線程來(lái)顯示,不過(guò)Asynctask只能做一些耗時(shí)較短
的操作哄啄,如果我們要做耗時(shí)較長(zhǎng)的操作,我們還是盡量使用線程池风范。
2.Asynctask使用
它主要有三個(gè)重要參數(shù)咨跌,五個(gè)重要方法
- 三個(gè)參數(shù),三種泛型分別代表:
public abstract class AsyncTask<Params, Progress, Result> { }
第一個(gè):“啟動(dòng)任務(wù)執(zhí)行的輸入?yún)?shù)”硼婿。
第二個(gè):“后臺(tái)任務(wù)執(zhí)行的進(jìn)度”锌半。
第三個(gè):“后臺(tái)計(jì)算結(jié)果的類型”。
- 五個(gè)方法:
第一種:execute(params…params):執(zhí)行一個(gè)異步任務(wù)寇漫,需要我們?cè)诖a中調(diào)用
此方法刊殉,觸發(fā)異步任務(wù)的執(zhí)行(必須在UI線程中調(diào)用)
第二種:onPreExecute(),在execute(Params… params)被調(diào)用后立即執(zhí)行州胳,一
般用來(lái)在執(zhí)行后臺(tái)任務(wù)前對(duì)UI做一些標(biāo)記(也可以理解為初始化數(shù)據(jù))记焊。
第三種:doInBackground(Params… params),在onPreExecute()完成后立即執(zhí)
行栓撞,用于執(zhí)行較為費(fèi)時(shí)的操作遍膜,此方法將接收輸入?yún)?shù)和返回計(jì)算結(jié)果碗硬。在執(zhí)行
過(guò)程中可以調(diào)用publishProgress(Progress… values)來(lái)更新進(jìn)度信息。
第四種:onProgressUpdate(Progress… values)瓢颅,在調(diào)用
publishProgress(Progress… values)時(shí)恩尾,此方法被執(zhí)行,直接將進(jìn)度信息更新到
UI組件上挽懦。
第五種:onPostExecute(Result result)翰意,當(dāng)后臺(tái)操作結(jié)束時(shí),此方法將會(huì)被調(diào)
用信柿,計(jì)算結(jié)果將做為參數(shù)傳遞到此方法中冀偶,直接將結(jié)果顯示到UI組件上。
3.Asynctask的內(nèi)部原理
1角塑、Asynctask的本質(zhì)是一個(gè)靜態(tài)的線程池蔫磨,Asynctask派生出的子類可以顯現(xiàn)不
同的異步任務(wù),這些任務(wù)都是提交到靜態(tài)的線程池中執(zhí)行圃伶。
2堤如、線程池中的工作線程執(zhí)行doinbackground(mparams)方法來(lái)執(zhí)行異步操作。
3窒朋、當(dāng)任務(wù)狀態(tài)改變后搀罢,工作線程會(huì)向UI線程發(fā)送消息,Asynctask內(nèi)部的
internalHandler相應(yīng)這些消息侥猩,并調(diào)用相關(guān)的回調(diào)榔至。
4.Asynctask的注意事項(xiàng)
一、內(nèi)存泄露欺劳。和handler造成的問(wèn)題一樣唧取。非靜態(tài)內(nèi)部類持有外部類的匿名引
用,導(dǎo)致外部activity像被內(nèi)存回收划提,由于非靜態(tài)內(nèi)部類還持有外部類的引用枫弟,導(dǎo)
致外部類不能被系統(tǒng)回收,造成內(nèi)存泄露鹏往。
解決方法:
1淡诗、誰(shuí)為靜態(tài)內(nèi)部類。
2伊履、非靜態(tài)內(nèi)部類使用弱引用韩容。
3、在destroy方法中finish唐瀑。
5.為什么AsyncTask只會(huì)執(zhí)行一次
AsyncTask定義了一個(gè)mStatus變量群凶,表示異步任務(wù)的運(yùn)行狀態(tài),分別是PENDING介褥、RUNNING座掘、FINISHED递惋,當(dāng)只有PENDING狀態(tài)時(shí),AsyncTask才會(huì)執(zhí)行溢陪,這樣也就保證了AsyncTask只會(huì)被執(zhí)行一次
二萍虽、生命周期
如果在外部類被銷毀的時(shí)候,沒(méi)有執(zhí)行onCancelled方法形真,這有可能讓我們的
activity在銷毀之前導(dǎo)致崩潰杉编。因?yàn)锳synctask正在處理某些view。但是activity不
存在了咆霜,所以就會(huì)崩潰邓馒。
三、結(jié)果丟失
假如說(shuō)蛾坯,activity被系統(tǒng)回收或者橫豎屏切換光酣,導(dǎo)致activity被重新創(chuàng)建,而之前運(yùn)
行的Asynctask會(huì)持有之前activity的引用脉课,但是這個(gè)引用已經(jīng)無(wú)效救军,所以這個(gè)時(shí)
候,你調(diào)用onpostExecute()方法去更新界面就會(huì)失敗倘零,因?yàn)榻Y(jié)果已經(jīng)丟失唱遭。
5.為什么AsyncTask只能執(zhí)行一次?
應(yīng)該說(shuō)同一時(shí)間段內(nèi)呈驶,只執(zhí)行一次任岸,防止對(duì)同一件事進(jìn)行操作蜈块,造成的混亂儡陨。我
們知道異步的線程執(zhí)行的順序很大程度上是不確定的煞躬,有可能先執(zhí)行的最后執(zhí)行
完成,后執(zhí)行的反而先完成聋迎。如果在同一時(shí)間段內(nèi)蚌吸,執(zhí)行多個(gè)線程這里就會(huì)出現(xiàn)
混亂。
6.什么是并行砌庄,什么是串行,兩者的區(qū)別是什么
在android1.6版本之前奕枢,Asynctask都是串行娄昆,也就是他會(huì)把所有任務(wù),一串一串
的放在線程池中缝彬。但是在1.6到2.3的版本中萌焰,它改成了并行。為了維護(hù)系統(tǒng)的穩(wěn)
定谷浅,2.3版本后又改回了串行扒俯,但是還是可以執(zhí)行并行的奶卓,建議使用串行
九、HandlerThread
1.由來(lái)
當(dāng)我們需要做一個(gè)耗時(shí)操作時(shí)撼玄,自然而然會(huì)啟動(dòng)一個(gè)子線程去執(zhí)行夺姑,當(dāng)子線程執(zhí)
行完成之后,就會(huì)自動(dòng)關(guān)閉掉掌猛;如果過(guò)了一會(huì)我們又想執(zhí)行一個(gè)耗時(shí)操作呢盏浙,那
就又得重新開(kāi)啟一個(gè)子線程,這樣重復(fù)的來(lái)回開(kāi)啟是非常消耗性能的荔茬;而在
android中就為我們提供了HandlerThrea來(lái)完成這樣的操作废膘。
2.特點(diǎn)
- HandlerThread本質(zhì)上是一個(gè)線程類,它繼承了Thread;
- HandlerThread有自己內(nèi)部的Lopper對(duì)象慕蔚,可以進(jìn)行l(wèi)ooper循環(huán)丐黄;
- HandlerThread中是不可以處理界面更新的,還是得交給Handler處理孔飒;
- 優(yōu)點(diǎn)是不會(huì)堵塞灌闺,減少了對(duì)性能的消耗;缺點(diǎn)是不能同時(shí)進(jìn)行多任務(wù)
的處理十偶,需要等待進(jìn)行處理菩鲜,處理效率比較低; - 與線程池重并發(fā)不同惦积,HandlerThread是一個(gè)串行隊(duì)列接校,HandlerThread背后只
有一個(gè)線程
十、intentService
1.IntentService是什么
IntentService是繼承并處理異步請(qǐng)求的一個(gè)類狮崩,在IntentService內(nèi)有一個(gè)工作線程來(lái)處理耗時(shí)操作蛛勉,啟動(dòng)IntentService的方式和啟動(dòng)傳統(tǒng)的Service一樣,同時(shí)睦柴,當(dāng)任務(wù)執(zhí)行完后诽凌,IntentService會(huì)自動(dòng)停止,而不需要我們手動(dòng)去控制或stopSelf()坦敌。另外侣诵,可以啟動(dòng)IntentService多次,而每一個(gè)耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandlerIntent回調(diào)方法中執(zhí)行狱窘,并且杜顺,每次只會(huì)執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)再執(zhí)行第二個(gè)蘸炸。
2.IntentService使用方法
創(chuàng)建IntentService時(shí)躬络,只需要實(shí)現(xiàn)onHandlerIntent方法和構(gòu)造方法,onHandlerIntent為異步方法搭儒,可以執(zhí)行耗時(shí)操作穷当。
十一提茁、View繪制
首先是measure(測(cè)量) 其次 layout(布局) 最后 draw(繪制)
1.measure
測(cè)量中首先得知道測(cè)量規(guī)則,MeasureSpec這個(gè)類
MeasureSpec這個(gè)類包括測(cè)量模式(specModel)
和測(cè)量模式下的規(guī)格大心俨恕(specSize)
MeasureSpec表示形式是32位的int值
前兩位是specModel 后30位是specSize
我們都知道SpecMode的尺子類型有很多茴扁,不同的尺子有不同的功能,而SpecSize刻度是固定的一種火邓,所以SpecMode又分為三種模式
UNSPECIFIED:父容器不對(duì)View有任何大小的限制丹弱,這種情況一般用于系統(tǒng)內(nèi)部,表示一種測(cè)量狀態(tài)
EXACTLY:父容器檢測(cè)出View所需要的精確大小铲咨,這時(shí)候View的值就是SpecSize
AT_MOST:父容器指定了一個(gè)可用大小即SpecSize躲胳,View的大小不能大于這個(gè)值
measure是final修飾的,需要重寫的方式是onMeasure()
2.layout
3.draw
4.Android視圖工作機(jī)制中的重繪
一纤勒、invalidate()和requestLayout()
invalidate()和requestLayout()坯苹,常用于View重繪和更新,其主要區(qū)別如下
invalidate方法只會(huì)執(zhí)行onDraw方法
requestLayout方法只會(huì)執(zhí)行onMeasure方法和onLayout方法摇天,并不會(huì)執(zhí)行onDraw方法粹湃。
所以當(dāng)我們進(jìn)行View更新時(shí),若僅View的顯示內(nèi)容發(fā)生改變且新顯示內(nèi)容不影響View的大小泉坐、位置为鳄,則只需調(diào)用invalidate方法;若View寬高腕让、位置發(fā)生改變且顯示內(nèi)容不變孤钦,只需調(diào)用requestLayout方法;若兩者均發(fā)生改變纯丸,則需調(diào)用兩者偏形,按照View的繪制流程,推薦先調(diào)用requestLayout方法再調(diào)用invalidate方法
二觉鼻、invalidate()和postInvalidate()
invalidate方法用于UI線程中重新繪制視圖
postInvalidate方法用于非UI線程中重新繪制視圖俊扭,省去使用handler
十二、事件分發(fā)
1坠陈、簡(jiǎn)要的談?wù)凙ndroid的事件分發(fā)機(jī)制萨惑?
當(dāng)點(diǎn)擊事件發(fā)生時(shí),首先Activity將TouchEvent傳遞給Window仇矾,再?gòu)腤indow傳遞給頂層View咒钟。TouchEvent會(huì)最先到達(dá)最頂層 view 的 dispatchTouchEvent ,然后由 dispatchTouchEvent 方法進(jìn)行分發(fā)若未,如果dispatchTouchEvent返回true ,則整個(gè)事件將會(huì)被銷毀倾鲫,如果dispatchTouchEvent返回 false 粗合,則交給上層view的 onTouchEvent 方法來(lái)開(kāi)始處理這個(gè)事件萍嬉,如果 interceptTouchEvent 返回 true ,也就是攔截掉了隙疚,則交給自身的 onTouchEvent 來(lái)處理壤追,如果 interceptTouchEvent 返回 false ,那么事件將繼續(xù)傳遞給子 view 供屉,由子 view 的 dispatchTouchEvent 再來(lái)開(kāi)始這個(gè)事件的分發(fā)行冰。如果事件傳遞到某一層的子 view 的 onTouchEvent 上了,且這個(gè)方法返回了 false 伶丐,那么這個(gè)事件會(huì)從這個(gè) view 往上傳遞悼做,都是 onTouchEvent 來(lái)接收。而如果傳遞到最頂view的 onTouchEvent 也返回 false 的話哗魂,這個(gè)事件就會(huì)消失肛走,直到onTouchEvent返回true為止。
2录别、為什么View有dispatchTouchEvent方法朽色?
因?yàn)閂iew可以注冊(cè)很多事件的監(jiān)聽(tīng)器,如長(zhǎng)按组题、滑動(dòng)葫男、點(diǎn)擊等,它也需要一個(gè)管理者來(lái)分發(fā)
3崔列、ViewGroup中可能有很多個(gè)子View梢褐,如何判斷應(yīng)該分配給哪一個(gè)?
根據(jù)源碼可知峻呕,它會(huì)分配給在點(diǎn)擊范圍內(nèi)的子View
4利职、當(dāng)點(diǎn)擊時(shí),子View重疊應(yīng)該如何分配瘦癌?
一般分配給最上層的子View猪贪,這是由于安卓的渲染機(jī)制導(dǎo)致的
1.簡(jiǎn)介
Android事件分發(fā)機(jī)制的發(fā)生在View與View之間或者ViewGroup與View之間具有鑲嵌的視圖上,而且視圖上必須為點(diǎn)擊可用讯私。當(dāng)一個(gè)點(diǎn)擊事件產(chǎn)生后热押,它的傳遞過(guò)程遵循如下順序:Activity->Window->View,即事件先傳遞給Activity斤寇,再到Window桶癣,再到頂級(jí)View,才開(kāi)始我們的事件分發(fā)
2.概念
Android事件分發(fā)機(jī)制主要由三個(gè)重要的方法共同完成的
dispatchTouchEvent:用于進(jìn)行點(diǎn)擊事件的分發(fā)
onInterceptTouchEvent:用于進(jìn)行點(diǎn)擊事件的攔截
onTouchEvent:用于處理點(diǎn)擊事件
這里需要注意的是View中是沒(méi)有onInterceptTouchEvent()方法的
dispatchTouchEvent
- return true:表示該View內(nèi)部消化掉了所有事件
- return false:表示事件在本層不再繼續(xù)進(jìn)行分發(fā)娘锁,并交由上層控件的onTouchEvent方法進(jìn)行消費(fèi)
- return super.dispatchTouchEvent(ev):默認(rèn)事件將分發(fā)給本層的事件攔截onInterceptTouchEvent方法進(jìn)行處理
onInterceptTouchEvent
- return true:表示將事件進(jìn)行攔截牙寞,并將攔截到的事件交由本層控件的onTouchEvent進(jìn)行處理
- return false:表示不對(duì)事件進(jìn)行攔截,事件得以成功分發(fā)到子View
- return super.onInterceptTouchEvent(ev):默認(rèn)表示不攔截該事件,并將事件傳遞給下一層View的dispatchTouchEvent
onTouchEvent
- return true:表示onTouchEvent處理完事件后消費(fèi)了此次事件
- return fasle:表示不響應(yīng)事件间雀,那么該事件將會(huì)不斷向上層View的onTouchEvent方法傳遞悔详,直到某個(gè)View的onTouchEvent方法返回true
- return super.dispatchTouchEvent(ev):表示不響應(yīng)事件,結(jié)果與return false一樣
十三惹挟、ListView
十四茄螃、構(gòu)建
業(yè)務(wù)需求很繁雜時(shí),為了避免開(kāi)發(fā)一個(gè)版本就人為的打包一次的耗時(shí)費(fèi)力的事件连锯,自動(dòng)化構(gòu)建apk是我們努力的目標(biāo)归苍,Jenkins提供了這樣一個(gè)功能,他可以持續(xù)的集成構(gòu)建我們的apk,同時(shí)需要配置一些gradle文件
ProGuard工具是用于壓縮运怖、優(yōu)化和混淆我們的代碼拼弃,主要作用是可以移除代碼中的無(wú)用類,字段驳规,方法和屬性同時(shí)可以混淆(是對(duì)即將要發(fā)布的程序進(jìn)行重新的組織和處理肴敛,這個(gè)代碼不容易被反編譯)
ProGuard技術(shù)功能:
壓縮(Shrink):檢測(cè)并移除代碼中無(wú)用的類、字段吗购、方法和特性(Attribute)医男。
優(yōu)化(Optimize):對(duì)字節(jié)碼進(jìn)行優(yōu)化,移除無(wú)用的指令捻勉。
混淆(Obfuscate):使用a镀梭,b,c踱启,d這樣簡(jiǎn)短而無(wú)意義的名稱报账,對(duì)類、字段和方法進(jìn)行重命名埠偿。
預(yù)檢(Preveirfy):在Java平臺(tái)上對(duì)處理后的代碼進(jìn)行預(yù)檢透罢,確保加載的class文件是可執(zhí)行的。
ProGuard工作原理:
Entry Point是在ProGuard過(guò)程中不會(huì)被處理的類或方法冠蒋。在壓縮的步驟中羽圃,ProGuard會(huì)從上述的Entry Point開(kāi)始遞歸遍歷,搜索哪些類和類的成員在使用抖剿,對(duì)于沒(méi)有被使用的類和類的成員朽寞,就會(huì)在壓縮段丟棄,在接下來(lái)的優(yōu)化過(guò)程中斩郎,那些非Entry Point的類脑融、方法都會(huì)被設(shè)置為private、static或final缩宜,不使用的參數(shù)會(huì)被移除肘迎,此外,有些方法會(huì)被標(biāo)記為內(nèi)聯(lián)的,在混淆的步驟中膜宋,ProGuard會(huì)對(duì)非Entry Point的類和方法進(jìn)行重命名窿侈。以便預(yù)檢測(cè)來(lái)保證我們整個(gè)代碼的穩(wěn)定性
十五、Okhttp
1.Okhttp簡(jiǎn)單使用
① 創(chuàng)建一個(gè)OkHttpClient對(duì)象
②創(chuàng)建一個(gè)request對(duì)象秋茫,通過(guò)內(nèi)部類Builer調(diào)用生成Request對(duì)象
③創(chuàng)建一個(gè)call對(duì)象,調(diào)用execute/enqueue
//首先創(chuàng)建一個(gè)Handler
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
imageView.setImageBitmap((Bitmap) msg.obj);
break;
}
}
};
//然后使用OkHttp發(fā)送網(wǎng)絡(luò)請(qǐng)求乃秀,并將結(jié)果通過(guò)Handler發(fā)送到主線程
public void sendRequestByOkHttp() {
//創(chuàng)建Request對(duì)象肛著,并傳入請(qǐng)求地址
Request request = new Request.Builder().url( "http://tnfs.tngou.net/img/ext/160321/e57d5816cb72d7486aa6dbf19a7d0c6c.jpg").build();
//構(gòu)造Call對(duì)象--其實(shí)是AsyncCall對(duì)象
Call call = client.newCall(request);
//調(diào)用Call.enqueue方法進(jìn)行異步請(qǐng)求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//網(wǎng)絡(luò)請(qǐng)求失敗
Log.d("lenve", "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//網(wǎng)絡(luò)請(qǐng)求成功,將請(qǐng)求的圖片信息顯示的ImageView控件上
Bitmap bitmap = BitmapFactory.decodeStream( response.body().byteStream());
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.obj = bitmap;
mHandler.sendMessage(msg);
}
});
}
源碼解析:
發(fā)送一個(gè)請(qǐng)求會(huì)到RealCall的execute()和enqueue(CallBack callBack) 方法中跺讯,首先看一下這倆個(gè)方法的實(shí)現(xiàn)枢贿。
@Override
public Response execute() throws IOException {
synchronized (this) {// 判斷這個(gè)Call有沒(méi)有執(zhí)行過(guò),每一個(gè)Call只能執(zhí)行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);// 最終交給client的任務(wù)調(diào)度器處理
Response result = getResponseWithInterceptorChain();// 使用攔截器處理返回結(jié)果
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);//通知dispatcher任務(wù)已經(jīng)執(zhí)行完了
}
}
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));// 還是交給dispatcher處理
}
AsynCall 是RealCall的內(nèi)部類刀脏,實(shí)現(xiàn)NameRunnable接口局荚,NameRunable為Runnable的實(shí)現(xiàn),在run()方法里會(huì)執(zhí)行execute()抽象方法愈污,所以在線程池運(yùn)行AsynCall時(shí)會(huì)調(diào)用AsynCall的execute()方法耀态,下面看一下AsynCall的execute()方法
2.如何使用OkHttp進(jìn)行異步網(wǎng)絡(luò)請(qǐng)求,并根據(jù)請(qǐng)求結(jié)果刷新UI
3.可否介紹一下OkHttp的整個(gè)異步請(qǐng)求流程
4.OkHttp對(duì)于網(wǎng)絡(luò)請(qǐng)求都有哪些優(yōu)化暂雹,如何實(shí)現(xiàn)的
5.OkHttp框架中都用到了哪些設(shè)計(jì)模式
OkHttp的底層是通過(guò)Java的Socket發(fā)送HTTP請(qǐng)求與接受響應(yīng)的(這也好理解首装,HTTP就是基于TCP協(xié)議的),但是OkHttp實(shí)現(xiàn)了連接池的概念杭跪,即對(duì)于同一主機(jī)的多個(gè)請(qǐng)求仙逻,其實(shí)可以公用一個(gè)Socket連接,而不是每次發(fā)送完HTTP請(qǐng)求就關(guān)閉底層的Socket涧尿,這樣就實(shí)現(xiàn)了連接池的概念系奉。而OkHttp對(duì)Socket的讀寫操作使用的OkIo庫(kù)進(jìn)行了一層封裝。
十六姑廉、retrofit
1.retrofit使用
① 在retrofit中通過(guò)一個(gè)接口作為http請(qǐng)求的api接口
public interface GitHubService {
@GET(“repos/{owner}/{repo}/contributors”)
Call<List<Contributor>> repoContributors(
@Path(“owner”) String owner,
@Path(“repo”) String repo);
}
② 創(chuàng)建一個(gè)Retrofit實(shí)例
public static final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("[https://api.github.com/](https://api.github.com/)")
.build();
③ 調(diào)用api接口
GitHubService gitHubService=GitHubService.retrofit.create(GitHubService.class);
Call<List<Contributor>> call = gitHubService.repoContributors(“square”, “retrofit”);
List<Contributor> result = call.execute().body();
另外缺亮,有人可能也會(huì)選擇設(shè)定請(qǐng)求的時(shí)間,讓它成為異步請(qǐng)求庄蹋,同時(shí)在執(zhí)行完畢后提供 callback瞬内。
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
// handle success
}
@Override
public void onFailure(Throwable t) {
// handle failure
}
});
2.動(dòng)態(tài)代理
① 首先,通過(guò)method把他轉(zhuǎn)換成ServiceMethod;
② 然后通過(guò)ServiceMethod限书,args獲取到OkhttpCall對(duì)象
③ 最后再把okhttpCall進(jìn)一步封裝并返回Call對(duì)象
3.源碼剖析
① 創(chuàng)建一個(gè)retrofit對(duì)象
② 通過(guò)Retrofit.create()方法是怎么把我們所定義的接口轉(zhuǎn)化成接口實(shí)例并使用接口中的方法
③ 最終的網(wǎng)絡(luò)請(qǐng)求調(diào)用的okhttp
十七虫蝶、volley
1.首先需要獲取到一個(gè)RequestQueue對(duì)象
RequestQueue mQueue = Volley.newRequestQueue(mContext);
2.創(chuàng)建一個(gè)StringRequest對(duì)象
StringRequest stringRequest = new StringRequest("http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("TAG", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
3.將StringRequest對(duì)象添加到RequestQueue里面
mQueue.add(stringRequest);
使用總結(jié):通過(guò)newRequestQueue(...)函數(shù)新建并啟動(dòng)一個(gè)請(qǐng)求隊(duì)列RequestQueue后,只需要往這個(gè)RequestQueue不斷add Request即可
![volley網(wǎng)絡(luò)框架流程圖.png](https://upload-images.jianshu.io/upload_images/2191038-654fcc9045a62f86.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1.首先我們初始化一個(gè)RequestQueue,因?yàn)槌跏蓟疪equestQueue非常的消耗性能倦西,所以只需要初始化一次即可
2.在newRequestQueue中我們會(huì)發(fā)現(xiàn)能真,如果Android版本大于2.3會(huì)調(diào)用HttpUrlConnection的HurlStack,如果Android版本小于2.3會(huì)調(diào)用一個(gè)HttpClient的HttpClientStack
3.接下來(lái)Volley會(huì)創(chuàng)建RequestQueue,并調(diào)用他的start方法
4.接著會(huì)創(chuàng)建1個(gè)緩存調(diào)度線程(CacheDispatcher)和4個(gè)網(wǎng)絡(luò)調(diào)度線程(netDispatcher),并分別調(diào)用他們的start方法,所以會(huì)默認(rèn)開(kāi)啟5個(gè)后臺(tái)線程粉铐,線程優(yōu)先級(jí)都為10
5.然后分別去輪詢各自的消息隊(duì)列
6.Volley是如何把請(qǐng)求的數(shù)據(jù)回調(diào)回主線程中的疼约?
使用Handler.postRunnable(Runnable)方法回調(diào)回主線程中進(jìn)行處理,ExecutorDelivery的構(gòu)造方法中可以看到這段代碼
十八蝙泼、ButterKnife
其實(shí)就使用一個(gè)依托Java的注解機(jī)制來(lái)實(shí)現(xiàn)輔助代碼生成的框架
1.使用
- 綁定一個(gè)view
- 給一個(gè)view添加點(diǎn)擊事件
- 給多個(gè)view添加點(diǎn)擊事件
- 給ListView 設(shè)置 setItemClickListener
2.原理
?? 首先我們應(yīng)該避免一個(gè)誤區(qū)程剥,butterknife中并不是用的反射的原理來(lái)實(shí)現(xiàn)的,
因?yàn)橛梅瓷涞脑捫阅軙?huì)很差
自己用反射實(shí)現(xiàn)原理:通過(guò)反射獲得類中所有注解的屬性汤踏,并且獲得注解當(dāng)中資
源中Layout的值织鲸,最后通過(guò)反射findViewById獲取到這個(gè)View,并賦值給Activity
當(dāng)中的屬性溪胶。
很大的缺點(diǎn)是在運(yùn)行時(shí)會(huì)大量的使用到反射搂擦,而反射其實(shí)會(huì)影響app的性能,特
別是運(yùn)行時(shí)的性能哗脖,容易造成卡頓瀑踢;又會(huì)產(chǎn)生很多的臨時(shí)變量,臨時(shí)變量又會(huì)引
起垃圾回收才避,在UI優(yōu)化中橱夭,大量頻繁的變量的垃圾回收會(huì)造成UI卡頓,UI卡頓也
是一種性能的標(biāo)志之一工扎。
而我們的butterknife沒(méi)有使用這樣的方法徘钥。butterknife使用的是java的注解處理技
術(shù),也就是在代碼編譯的時(shí)候肢娘,編譯成字節(jié)碼的時(shí)候呈础,它就處理好了注解操作
注意:java的注解處理技術(shù)是在編譯階段執(zhí)行的,它的原理是通過(guò)讀入我們的源
代碼橱健,解析注解然后生產(chǎn)新的java代碼而钞,而新生產(chǎn)的java代碼當(dāng)中,最后被編譯
成java字節(jié)碼拘荡,由于注解解釋器它是不能改變讀入的java類的臼节。這就是butterknife的注解原理。
梳理ButterKnife原理流程
- 開(kāi)始它會(huì)掃描java代碼中所有的ButterKnife注解
- ButterKnifeProcssor ---><className>$$ViewBinder
- 調(diào)用bind方法加載生成的ViewBinder類
3.綁定view的時(shí)候珊皿,為什么不能private和static网缝??
因?yàn)樾阅軉?wèn)題蟋定,如圖我們我們把這個(gè)view設(shè)置成private粉臊,那么這個(gè)框架他就不能
通過(guò)注解的方式來(lái)獲取了,只能通過(guò)反射來(lái)獲取驶兜,此時(shí)不管你的性能有多快扼仲,都
會(huì)影響性能远寸。這是必須注意并且避免的。這也就是和其他注解方式不同的一點(diǎn)屠凶。
十九驰后、Glide加載圖片
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
RequestManager其實(shí)是一個(gè)圖片加載請(qǐng)求的管理類,實(shí)現(xiàn)了LifecycleListener接口矗愧,這個(gè)接口管理生命周期灶芝,需要和activity或fragment所綁定,這樣我們可以把我們的request綁定到我們的activity唉韭、組件當(dāng)中监署,然后我們就可以通過(guò)生命周期方法對(duì)request請(qǐng)求進(jìn)行暫停,恢復(fù)和清除操作
RequestManagerRetriever這個(gè)實(shí)例其實(shí)是將RequestManager和activity或fragment進(jìn)行綁定的一個(gè)大管家的類纽哥,這樣就能通過(guò)生命周期來(lái)進(jìn)行回調(diào)管理
Glide原理的核心是為bitmap維護(hù)一個(gè)對(duì)象池。對(duì)象池的主要目的是通過(guò)減少大對(duì)象內(nèi)存的分配以重用來(lái)提高性能
glide與picasso對(duì)比
glide原理
二十栖秕、ANR
1.什么是ANR春塌?
Application Not Responding
在主線程中做耗時(shí)的操作,導(dǎo)致長(zhǎng)時(shí)間無(wú)法對(duì)用戶的操作做出響應(yīng)簇捍,Activity最長(zhǎng)
為5秒只壳,BrocastReceiver最長(zhǎng)為10秒,Service最長(zhǎng)為20秒暑塑。
2.原因:應(yīng)用程序的響應(yīng)性是由Activity Manager和Window Manager系統(tǒng)服務(wù)監(jiān)視的,當(dāng)它監(jiān)測(cè)到組件在相應(yīng)的響應(yīng)的時(shí)間沒(méi)有響應(yīng)就會(huì)彈出ARN的提示吼句。
-
哪些操作是在主線程中呢?
Activity中所有生命周期的回調(diào)都是在主線程中事格。Service默認(rèn)是執(zhí)行在主線程中的惕艳。
BrocastReceiver中的onReceve()回調(diào)執(zhí)行在主線程中。
沒(méi)有使用子線程的Lopper的Handler的handlerMessage,post(Runner)是執(zhí)行在
主線程中的驹愚。AsyncTask中除了doInBackground,其他方法都是執(zhí)行在主線程中的远搪。
3.處理:
- 使用AnsycTask處理耗時(shí)IO操作
- 使用Thread或者HandlerThread提高優(yōu)先級(jí)
- 使用Handler來(lái)處理工作線程的耗時(shí)任務(wù)
- Activity的onCreate()和onResume()回調(diào)中盡量避免耗時(shí)代碼
二十一、OOM
1.什么是oom逢捺?
當(dāng)前占用的內(nèi)存加上我們申請(qǐng)的內(nèi)存資源超過(guò)了Dalvik虛擬機(jī)的最大內(nèi)存限制就
會(huì)拋出的out of memory 異常谁鳍。
二十二、bitmap
1.recycle
2.LRU
3.計(jì)算inSampleSize
4.縮略圖
5.三級(jí)緩存
二十三劫瞳、UI卡頓問(wèn)題
1.UI卡頓原理
60fps --> 16ms
60fps:1秒60楨倘潜,1000/16
16ms:android中每隔16ms會(huì)進(jìn)行一個(gè)渲染,16ms以內(nèi)完成不了就會(huì)導(dǎo)致界面
的卡頓
每次dalvik虛擬機(jī)進(jìn)行GC的時(shí)候志于,所有的線程都會(huì)暫停涮因,所以說(shuō)在16ms內(nèi)正在
渲染的時(shí)候正好遇到了大量的GC操作,就會(huì)導(dǎo)致渲染時(shí)間不夠,從而導(dǎo)致UI卡頓.
overdraw:過(guò)度繪制恨憎,在屏幕上蕊退,它的某個(gè)像素在同一楨的時(shí)間內(nèi)繪制了很多
次郊楣,經(jīng)常出現(xiàn)在多層次的UI結(jié)構(gòu)中∪坷螅可以在手機(jī)中的GPU選項(xiàng)中進(jìn)行觀察净蚤,有藍(lán)
色、淡綠输硝、淡紅今瀑、紅色、深紅色点把,減少紅色盡量出現(xiàn)藍(lán)色橘荠。
2.UI卡頓原因分析
1.人為的在UI線程中做輕微的耗時(shí)操作,導(dǎo)致UI線程卡頓;
2.布局Layout過(guò)于復(fù)雜郎逃,無(wú)法在16ms內(nèi)完成渲染哥童;
3.同一時(shí)間動(dòng)畫執(zhí)行的次數(shù)過(guò)多,導(dǎo)致CPU或GPU負(fù)載過(guò)重褒翰;
4.View過(guò)度繪制贮懈,導(dǎo)致某些像素在同一幀時(shí)間內(nèi)被繪制多次,從而使CPU或GPU
負(fù)載過(guò)重优训;
5.View頻繁的觸發(fā)measure朵你、layout,導(dǎo)致measure揣非、layout累計(jì)耗時(shí)過(guò)多及整個(gè)View頻繁的重新渲染抡医;
6.內(nèi)存頻繁觸發(fā)GC過(guò)多(同一幀中頻繁創(chuàng)建內(nèi)存),導(dǎo)致暫時(shí)阻塞渲染操作早敬;
7.冗余資源及邏輯等導(dǎo)致加載和執(zhí)行緩慢忌傻;
8.臭名昭著的ANR;
3.總結(jié)
1.布局優(yōu)化搁嗓;盡量使用include芯勘、merge、ViewStub標(biāo)簽腺逛,盡量不存在冗余嵌套及過(guò)于復(fù)雜布局(譬如10層就會(huì)直接異常)荷愕,盡量使用GONE替換INVISIBLE,使用weight后盡量將width和heigh設(shè)置為0dp減少運(yùn)算棍矛,Item存在非常復(fù)雜的嵌套時(shí)考慮使用自定義Item View來(lái)取代安疗,減少measure與layout次數(shù)等。
2.列表及Adapter優(yōu)化够委;盡量復(fù)用getView方法中的相關(guān)View荐类,不重復(fù)獲取實(shí)例導(dǎo)致卡頓,列表盡量在滑動(dòng)過(guò)程中不進(jìn)行UI元素刷新等茁帽。
3.背景和圖片等內(nèi)存分配優(yōu)化玉罐;盡量減少不必要的背景設(shè)置屈嗤,圖片盡量壓縮處理顯示,盡量避免頻繁內(nèi)存抖動(dòng)等問(wèn)題出現(xiàn)吊输。
4.自定義View等繪圖與布局優(yōu)化饶号;盡量避免在draw、measure季蚂、layout中做過(guò)于耗時(shí)及耗內(nèi)存操作茫船,尤其是draw方法中,盡量減少draw扭屁、measure算谈、layout等執(zhí)行次數(shù)。
5.避免ANR料滥,不要在UI線程中做耗時(shí)操作然眼,遵守ANR規(guī)避守則,譬如多次數(shù)據(jù)庫(kù)操作等
二十四葵腹、內(nèi)存泄漏
1.java內(nèi)存泄漏基礎(chǔ)知識(shí)
該被釋放的對(duì)象沒(méi)有被釋放罪治,一直被某個(gè)或者某個(gè)實(shí)例所持有,導(dǎo)致不能垃圾回收
二十五礁蔗、內(nèi)存管理
二十六、冷啟動(dòng)優(yōu)化
1.什么是冷啟動(dòng)
冷啟動(dòng):當(dāng)后臺(tái)不存在該應(yīng)用的任何進(jìn)程或者服務(wù)時(shí)雁社,用戶點(diǎn)擊icon圖標(biāo)啟動(dòng)浴井,我們稱之為冷啟動(dòng)。
熱啟動(dòng):當(dāng)后臺(tái)存在該應(yīng)用的進(jìn)程或者服務(wù)時(shí)霉撵,用戶點(diǎn)擊icon圖標(biāo)啟動(dòng)磺浙,我們稱之為熱啟動(dòng)。
一般是用戶按了home鍵回到桌面徒坡,或者返回鍵沒(méi)有殺進(jìn)程撕氧,或者app本身做了進(jìn)程重啟的機(jī)制。
2.冷啟動(dòng)流程
3.如何對(duì)冷啟動(dòng)的時(shí)間進(jìn)行優(yōu)化
我們主要優(yōu)化冷啟動(dòng)時(shí)間喇完,只要冷啟動(dòng)時(shí)間優(yōu)化了伦泥,熱啟動(dòng)其實(shí)也跟著優(yōu)化了。
冷啟動(dòng)時(shí)間分布如下:
application啟動(dòng)時(shí)間+歡迎頁(yè)停留時(shí)間
按用戶體驗(yàn)的啟動(dòng)時(shí)間應(yīng)該是:
application啟動(dòng)時(shí)間+歡迎頁(yè)停留時(shí)間+進(jìn)入主頁(yè)后顯示主題的時(shí)間锦溪;
二十七不脯、其他優(yōu)化
1.android中不用靜態(tài)變量存儲(chǔ)數(shù)據(jù)
2.關(guān)于sp的安全問(wèn)題
3.內(nèi)存對(duì)象序列化
4.避免ui線程中做繁重的操作
二十七、mvc/mvp/mvvm
二十八刻诊、插件化
二十九防楷、熱修復(fù)
原理
三十、進(jìn)程痹蜓模活
1.Android進(jìn)程的優(yōu)先級(jí)
- 前臺(tái)進(jìn)程
- 可見(jiàn)進(jìn)程
- 服務(wù)進(jìn)程
- 后臺(tái)進(jìn)程
*空進(jìn)程
2.Android進(jìn)程的回收策略
Low momery killer:通過(guò)一些比較復(fù)雜的評(píng)分機(jī)制复局,對(duì)進(jìn)程進(jìn)行打分冲簿,然后將分?jǐn)?shù)高的進(jìn)程判定為bad進(jìn)程,殺死并釋放內(nèi)存亿昏。
OOM_ODJ:判讀進(jìn)程優(yōu)先級(jí)
3.進(jìn)程甭吞蓿活方案
- 利用系統(tǒng)廣播進(jìn)行拉活
- 利用系統(tǒng)的Service機(jī)制拉活
- 利用native進(jìn)程拉活(5.0以后無(wú)法實(shí)現(xiàn))
- 利用 JobScheuler機(jī)制拉活(5.0以后新加)
- 利用賬號(hào)同步機(jī)制拉活
三十一龙优、UIL
三十二羊异、Lint
1.什么是Android lint 檢查
Android Lint 是一個(gè)靜態(tài)代碼分析工具,它能夠?qū)δ愕腁ndroid項(xiàng)目中潛在的bug彤断、可優(yōu)化的代碼野舶、安全性、性能宰衙、可用性平道、可訪問(wèn)性、國(guó)際化等進(jìn)行檢查供炼。
2.工作流程
他有個(gè)lint tool 工具一屋,它會(huì)把我們的Android源代碼和lint xml配置文件打包成一個(gè)文件之后,輸出一個(gè)lint output 袋哼,并展現(xiàn)出具體哪行代碼有問(wèn)題冀墨,我們可以定位到具體問(wèn)題所在,改寫代碼涛贯,保證上線時(shí)的代碼質(zhì)量
3.配置lint
1.配置lint.xml
2.java代碼和xml布局文件如何忽略lint檢查
3.自定義lint
1)原因
三十三诽嘉、Kotlin
1.kotlin到底是什么
- 是一種基于JVM的編程語(yǔ)言
- 是對(duì)java的一種擴(kuò)展
- kotlin支持函數(shù)式編程
- kotlin類與java類能相互調(diào)用
2.kotlin的環(huán)境搭建
- Android studio安裝kotlin插件
- 編寫kotlinActivity測(cè)試
- kotlin會(huì)自動(dòng)配置kotlin
三十四、LruCache
LruCache是一個(gè)針對(duì)內(nèi)存層面的緩存弟翘,基于LRU算法(最近最少使用)實(shí)現(xiàn)的虫腋。
內(nèi)部主要是使用LinkHashMap來(lái)存儲(chǔ)數(shù)據(jù),LinkHashMap是繼承HashMap的稀余,主要是重寫了get方法悦冀,當(dāng)獲取數(shù)據(jù)的時(shí)候會(huì)把自己添加到節(jié)點(diǎn)的頭部,保證處于鏈表的最前面睛琳;不常用的數(shù)據(jù)就會(huì)排在最后面盒蟆,當(dāng)緩存的數(shù)據(jù)滿了之后,一般是申請(qǐng)進(jìn)程空間的1/8师骗,就會(huì)清楚掉排在最后的這些數(shù)據(jù)茁影,trimToSize()方法中執(zhí)行
public V get(Object key) {
//使用HashMap的getEntry方法,驗(yàn)證了我們所說(shuō)的查詢效率為O(1)
LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);//在找到節(jié)點(diǎn)后調(diào)用節(jié)點(diǎn)recordAccess方法 往下看
return e.value;
}
//LinkedHashMapEntry
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {//accessOrder該值默認(rèn)為false 但是 在LruCache中設(shè)置為true
lm.modCount++;
remove();//該方法將本身節(jié)點(diǎn)移除鏈表
addBefore(lm.header);//將自己添加到節(jié)點(diǎn)頭部 保證最近使用的節(jié)點(diǎn)位于鏈表前邊
}
}
三十五丧凤、算法