一 Activity
1 Activity 生命周期
1.1 Activity 的四種狀態(tài)
running 當(dāng)前Activity正在運(yùn)行,獲取焦點(diǎn)
paused 當(dāng)前Activity處于暫停狀態(tài)棍弄,可見(jiàn)足绅,沒(méi)有焦點(diǎn)
stopped 當(dāng)前Activity處于暫停狀態(tài),完全不可見(jiàn),內(nèi)存里的成員變量和狀態(tài)信息仍在。
killed 當(dāng)前Activity被銷毀后的狀態(tài),成員變量和狀態(tài)信息被一并回收饮睬。
1.2 Activity的生命周期
Activity啟動(dòng) →onCreate()→onStart()→onResume();
點(diǎn)擊home鍵返回桌面→onPause()→onStop()篮奄;
再次回到原Activity→ onRestart()→onStart()→onResume()捆愁;
按返回鍵退出當(dāng)前Activity→onPause()→onStop()→onDestroy();
2 Android任務(wù)棧
優(yōu)先級(jí):前臺(tái)>可見(jiàn)>服務(wù)>后臺(tái)>空
前臺(tái):正在與用戶進(jìn)行交互的Activity所在的進(jìn)程
可見(jiàn):Activity可見(jiàn)但沒(méi)有在前臺(tái)所在的進(jìn)程
服務(wù):Activity在后臺(tái)開(kāi)啟了服務(wù)所在的進(jìn)程
后臺(tái):Activity完全處于后臺(tái)所在的進(jìn)程
空:沒(méi)有任何Activity存在的進(jìn)程
3. Activity的啟動(dòng)模式
3.1 為什么需要啟動(dòng)模式窟却?
? ? ? ?每次啟動(dòng)一個(gè)Activity都會(huì)把對(duì)應(yīng)的要啟動(dòng)的Activity的實(shí)例放入任務(wù)棧中昼丑,加入這個(gè)Activity被頻繁啟動(dòng),會(huì)產(chǎn)生很多的這個(gè)Activity的實(shí)例夸赫,為了杜絕這種內(nèi)存浪費(fèi)的行為菩帝,Activity的啟動(dòng)模式被創(chuàng)造出來(lái)。
3.2 Activity的啟動(dòng)模式
- 系統(tǒng)模式模式:standard
? ? ? ?標(biāo)準(zhǔn)模式,也是系統(tǒng)的默認(rèn)模式呼奢,啟動(dòng)一個(gè)activity就創(chuàng)建一個(gè)activity實(shí)例宜雀,不管這個(gè)實(shí)例是否存在,誰(shuí)啟動(dòng)了這個(gè)Activity握础,那么這個(gè)Activity就運(yùn)行在啟動(dòng)它的那個(gè)Activity的任務(wù)棧中辐董。 - 棧頂復(fù)用模式:singleTop
? ? ? ?在這種模式下,如果新的Activity已經(jīng)位于棧頂禀综,那么此Activity不會(huì)被重新創(chuàng)建郎哭,同時(shí)它的onNewIntent方法被回調(diào),通過(guò)此方法的參數(shù)我們可以取出當(dāng)前的請(qǐng)求信息菇存。需要注意,此Activity的onCreate邦蜜,onStart方法不會(huì)被系統(tǒng)調(diào)用依鸥。如果新Activity不在棧頂,那么新Activity任然會(huì)被重新重建悼沈。 - 棧內(nèi)復(fù)用模式:singleTask
? ? ? ?這是一種單實(shí)例模式贱迟,只要Activity在一個(gè)棧中存在,那么多次啟動(dòng)此Activity都不會(huì)重新創(chuàng)建實(shí)例絮供,系統(tǒng)也會(huì)回調(diào)onNewIntent方法衣吠。
例如:當(dāng)前棧內(nèi)情況為ABC,此時(shí)D被以singleTask的模式被啟動(dòng)壤靶,當(dāng)前棧變?yōu)锳BCD缚俏。
如果當(dāng)前棧內(nèi)情況為ADBC,此時(shí)D被以singleTask的模式被啟動(dòng)贮乳,當(dāng)前棧變?yōu)锳D忧换。 - 單實(shí)例模式:singleInstance
? ? ? ?這是一種加強(qiáng)的單實(shí)例模式,它除了具有singleTask模式的所有特性外向拆,還加強(qiáng)了一點(diǎn)亚茬,那就是具有此種模式的Activity只能單獨(dú)位于一個(gè)任務(wù)棧中,比如Activity A是singleInstance模式浓恳,A被啟動(dòng)時(shí)系統(tǒng)會(huì)為它創(chuàng)建一個(gè)新的任務(wù)棧刹缝,A運(yùn)行在這個(gè)單獨(dú)的任務(wù)棧中,后續(xù)的請(qǐng)求均不會(huì)再創(chuàng)建A颈将,除非這個(gè)單獨(dú)的任務(wù)棧被系統(tǒng)銷毀了梢夯。
二 Fragment
1. 為什么Fragment被稱為第五大組件?
Android中的四大組件為Activity吆鹤,service厨疙,ContentProvider,Broadcast。
Fragment因?yàn)橛猩芷谡雌啵褂妙l率不輸于四大組件梗醇,可靈活加載到Activity中。
1.1 Fragment加載到Activity的兩種方式
- 靜態(tài)加載:直接在Activity布局文件中指定Fragment撒蟀。代碼如下
<fragment
android:name="com.example.myfragment.MyFragment"
android:id="@+id/myfragment_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
- 動(dòng)態(tài)加載:動(dòng)態(tài)加載需要使用到FragmentManager叙谨,這種加載方式在開(kāi)發(fā)中是非常常見(jiàn)的,示例代碼如下:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
//將FragmentA從容器中移除掉保屯,減少內(nèi)存的消耗
fragmentTransaction.remove(fragmentA);
fragmentTransaction.add(R.id.fragment_layout,new FragmentB());
fragmentTransaction.commit();
1.2 Fragment 與ViewPager搭配使用
? ? ? ?通常情況下我們開(kāi)發(fā)應(yīng)用最常見(jiàn)的使用情況是TabLayout+ViewPager+Fragment的使用方式手负,這就涉及到兩個(gè)常用的適配器的使用,一個(gè)是FragmentPagerAdapter姑尺,另外一個(gè)是FragmentStatePagerAdapter,那么它們之間有什么區(qū)別呢竟终?其實(shí)很簡(jiǎn)單,F(xiàn)ragmentPagerAdapter適用于頁(yè)面較少的情況切蟋,而FragmentStatePagerAdapter適用于頁(yè)面較多的情況统捶。
2. Fragment的生命周期
Fragment
界面打開(kāi)
onCreate() 方法執(zhí)行!
onCreateView() 方法執(zhí)行柄粹!
onActivityCreated() 方法執(zhí)行喘鸟!
onStart() 方法執(zhí)行!
onResume() 方法執(zhí)行驻右!
按下主屏幕鍵/鎖屏
onPause() 方法執(zhí)行什黑!
onStop() 方法執(zhí)行!
重新打開(kāi)
onStart() 方法執(zhí)行堪夭!
onResume() 方法執(zhí)行愕把!
按下后退鍵
onPause() 方法執(zhí)行!
onStop() 方法執(zhí)行森爽!
onDestroyView() 方法執(zhí)行礼华!
onDestroy() 方法執(zhí)行!
onDetach() 方法執(zhí)行拗秘!
Activity
打開(kāi)應(yīng)用
onCreate() 方法執(zhí)行圣絮!
onStart() 方法執(zhí)行!
onResume() 方法執(zhí)行雕旨!
按下主屏幕鍵/鎖屏
onPause() 方法執(zhí)行扮匠!
onStop() 方法執(zhí)行!
重新打開(kāi)應(yīng)用
onRestart() 方法執(zhí)行凡涩!
onStart() 方法執(zhí)行棒搜!
onResume() 方法執(zhí)行!
按下后退鍵
onPause() 方法執(zhí)行活箕!
onStop() 方法執(zhí)行力麸!
onDestroy() 方法執(zhí)行!
在Activity中加入Fragment,對(duì)應(yīng)的生命周期
打開(kāi)
Fragment onAttach()方法執(zhí)行
Fragment onCreate() 方法執(zhí)行!
Fragment onCreateView() 方法執(zhí)行克蚂!
Fragment onViewCreated()方法執(zhí)行
Activity onCreate() 方法執(zhí)行闺鲸!
Fragment onActivityCreated() 方法執(zhí)行!
Activity onStart() 方法執(zhí)行埃叭!
Fragment onStart() 方法執(zhí)行摸恍!
Activity onResume() 方法執(zhí)行!
Fragment onResume() 方法執(zhí)行赤屋!
按下主屏幕鍵/鎖屏
Fragment onPause() 方法執(zhí)行立镶!
Activity onPause() 方法執(zhí)行!
Fragment onStop() 方法執(zhí)行类早!
Activity onStop() 方法執(zhí)行媚媒!
再次打開(kāi)
Activity onRestart() 方法執(zhí)行!
Activity onStart() 方法執(zhí)行涩僻!
Fragment onStart() 方法執(zhí)行欣范!
Activity onResume() 方法執(zhí)行!
Fragment onResume() 方法執(zhí)行令哟!
按下后退鍵
Fragment onPause() 方法執(zhí)行!
Activity onPause() 方法執(zhí)行妨蛹!
Fragment onStop() 方法執(zhí)行屏富!
Activity onStop() 方法執(zhí)行!
Fragment onDestroyView() 方法執(zhí)行蛙卤!
Fragment onDestroy() 方法執(zhí)行狠半!
Fragment onDetach() 方法執(zhí)行!
Activity onDestroy() 方法執(zhí)行颤难!
3. Fragment的通信
3.1 在Fragment中調(diào)用Activity中的方法
? ? ? ?在Fragment中調(diào)用Activity的方法很簡(jiǎn)單神年,F(xiàn)ragment有個(gè)getActivity()的方法,比如行嗤,在MainActivity中的一個(gè)Fragment中獲取MainActivity的引用已日,并調(diào)用MainActivity的某個(gè)方法methodA()方法你可以這么寫:
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.methodA();
3.2 在Activity中調(diào)用Fragment的方法
? ? ? ?在Activity中調(diào)用Fragment中的方法是最簡(jiǎn)單的,我想這里我不用多說(shuō)吧栅屏!直接接口回調(diào)即可調(diào)用Fragment的任何可訪問(wèn)的方法飘千。
3.3 在Fragment中調(diào)用另外一個(gè)Fragment的方法
? ? ? ?這個(gè)可就需要一定的思維性了,首先要想調(diào)用Fragment A的方法栈雳,除了這個(gè)Fragment A自身可以調(diào)用外护奈,這個(gè)Fragment A所屬的Activity也可以調(diào)用,要想另外一個(gè)Fragment B調(diào)用此Fragment A的方法哥纫,F(xiàn)ragment B可以間接通過(guò)Activity來(lái)進(jìn)行調(diào)用霉旗,也就是3.1 和 3.2 的結(jié)合。
三 Service
1. Service基礎(chǔ)知識(shí)
1.1 Service是什么?
? ? ? ?Service(服務(wù))是一個(gè)一種可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而沒(méi)有用戶界面的組件厌秒。它運(yùn)行于UI線程读拆,因此不能進(jìn)行耗時(shí)的操作。
1.2 Service和Thread的區(qū)別
? ? ? ?Service的運(yùn)行是在UI線程當(dāng)中的简僧,是絕對(duì)絕對(duì)不能進(jìn)行耗時(shí)操作的建椰,而Thread開(kāi)啟的子線程則可以進(jìn)行耗時(shí)操作,但是Thread開(kāi)啟的子線程是不能直接對(duì)UI進(jìn)行操作的岛马,否則極有可能發(fā)生直接讓程序崩掉棉姐,這就是它們的區(qū)別。
2. 啟動(dòng)Service的2種方式
2.1 startService()方法開(kāi)啟Service
步驟:
??a.定義一個(gè)類繼承Service啦逆。
??b.在AndroidManifest.xml文件中配置該Service伞矩。
??c.使用Context的startService(Intent)方法啟動(dòng)該Service。
??d.不再使用該Service時(shí)夏志,調(diào)用Context的stopService(Intent)方法停止該Service乃坤。
2.2 bindService方法開(kāi)啟Service(Activity與Service綁定)
步驟:
??a.創(chuàng)建BinderService服務(wù)端葛家,繼承自Service并在類中創(chuàng)建一個(gè)實(shí)現(xiàn)IBinder接口的實(shí)現(xiàn)實(shí)例對(duì)象并提供公共方法給客戶端調(diào)用春贸。
??b.從onBind()回調(diào)方法返回此Binder實(shí)例。
??c.在客戶端中差凹,從onServiceConnected回調(diào)方法接收Binder,并使用提供的方法調(diào)用綁定服務(wù)瘦材。
3. Service的生命周期
? ? ? ?服務(wù)的生命周期有兩種厅须,因?yàn)榉?wù)可以跟Activity綁定起來(lái),也可以不綁定食棕,Activity和服務(wù)進(jìn)行通信的話朗和,是需要把服務(wù)和Activity進(jìn)行綁定的。因此服務(wù)的生命周期分為未綁定Activity的和綁定Activity的簿晓。
沒(méi)有綁定Activity的服務(wù)生命周期:
啟動(dòng)服務(wù)>onCreate()>onStartCommand()>服務(wù)運(yùn)行>onDestory()>服務(wù)銷毀
綁定Activity的服務(wù)生命周期
綁定服務(wù)>onCreate()>onBind()>服務(wù)運(yùn)行>onUnBind()>onDestory()>服務(wù)被銷毀
通過(guò)Intent和startService()方法啟動(dòng)了一個(gè)服務(wù)眶拉,接下來(lái)執(zhí)行onCreate()方法,首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序(在調(diào)用 onStartCommand() 或 onBind() 之前)憔儿。如果服務(wù)已在運(yùn)行忆植,則不會(huì)調(diào)用此方法。
當(dāng)另一個(gè)組件(如 Activity)通過(guò)調(diào)用 startService() 請(qǐng)求啟動(dòng)服務(wù)時(shí)谒臼,系統(tǒng)將調(diào)用此方法唱逢。一旦執(zhí)行此方法,服務(wù)即會(huì)啟動(dòng)并可在后臺(tái)無(wú)限期運(yùn)行屋休。 如果您實(shí)現(xiàn)此方法坞古,則在服務(wù)工作完成后,需要由您通過(guò)調(diào)用 stopSelf() 或 stopService() 來(lái)停止服務(wù)劫樟。(如果您只想提供綁定痪枫,則無(wú)需實(shí)現(xiàn)此方法织堂。)
服務(wù)開(kāi)始處于運(yùn)行狀態(tài)。
某個(gè)操作導(dǎo)致服務(wù)停止奶陈,比如執(zhí)行了方法stopService()易阳,那么服務(wù)接下來(lái)會(huì)執(zhí)行onDestory()銷毀。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來(lái)清理所有資源吃粒,如線程潦俺、注冊(cè)的偵聽(tīng)器、接收器等徐勃。 這是服務(wù)接收的最后一個(gè)調(diào)用事示。
服務(wù)被完全銷毀,下一步就是等待被垃圾回收器回收了僻肖。
通過(guò)Intent和bindService()方法啟動(dòng)了一個(gè)服務(wù),接下來(lái)會(huì)執(zhí)行onCreate()方法肖爵,首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序(在調(diào)用 onStartCommand() 或 onBind() 之前)臀脏。如果服務(wù)已在運(yùn)行劝堪,則不會(huì)調(diào)用此方法。
當(dāng)另一個(gè)組件想通過(guò)調(diào)用 bindService() 與服務(wù)綁定(例如執(zhí)行 RPC)時(shí)揉稚,系統(tǒng)將調(diào)用此方法秒啦。在此方法的實(shí)現(xiàn)中,您必須通過(guò)返回 IBinder 提供一個(gè)接口搀玖,供客戶端用來(lái)與服務(wù)進(jìn)行通信余境。請(qǐng)務(wù)必實(shí)現(xiàn)此方法,但如果您并不希望允許綁定巷怜,則應(yīng)返回 null。
服務(wù)開(kāi)始處于運(yùn)行狀態(tài)暴氏。成功與Activity綁定延塑。
某個(gè)操作導(dǎo)致服務(wù)解除綁定,比如執(zhí)行了方法unbindService()答渔,那么服務(wù)接下來(lái)會(huì)解除與當(dāng)前Activity的綁定关带。接下來(lái)服務(wù)將面臨銷毀。
服務(wù)執(zhí)行onDestory()方法被銷毀沼撕。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來(lái)清理所有資源宋雏,如線程、注冊(cè)的偵聽(tīng)器务豺、接收器等磨总。 這是服務(wù)接收的最后一個(gè)調(diào)用。
服務(wù)被完全銷毀笼沥,下一步就是等待被垃圾回收器回收了蚪燕。
Service總結(jié):
被啟動(dòng)的服務(wù)的生命周期:如果一個(gè)Service被某個(gè)Activity 調(diào)用 Context.startService 方法啟動(dòng)娶牌,那么不管是否有Activity使用bindService綁定或unbindService解除綁定到該Service,該Service都在后臺(tái)運(yùn)行馆纳。如果一個(gè)Service被startService 方法多次啟動(dòng)诗良,那么onCreate方法只會(huì)調(diào)用一次,onStart將會(huì)被調(diào)用多次(對(duì)應(yīng)調(diào)用startService的次數(shù))鲁驶,并且系統(tǒng)只會(huì)創(chuàng)建Service的一個(gè)實(shí)例(因此你應(yīng)該知道只需要一次stopService調(diào)用)鉴裹。該Service將會(huì)一直在后臺(tái)運(yùn)行,而不管對(duì)應(yīng)程序的Activity是否在運(yùn)行钥弯,直到被調(diào)用stopService径荔,或自身的stopSelf方法。當(dāng)然如果系統(tǒng)資源不足寿羞,android系統(tǒng)也可能結(jié)束服務(wù)猖凛。
被綁定的服務(wù)的生命周期:如果一個(gè)Service被某個(gè)Activity 調(diào)用 Context.bindService 方法綁定啟動(dòng),不管調(diào)用 bindService 調(diào)用幾次绪穆,onCreate方法都只會(huì)調(diào)用一次辨泳,同時(shí)onStart方法始終不會(huì)被調(diào)用。當(dāng)連接建立之后玖院,Service將會(huì)一直運(yùn)行菠红,除非調(diào)用Context.unbindService 斷開(kāi)連接或者之前調(diào)用bindService 的 Context 不存在了(如Activity被finish的時(shí)候),系統(tǒng)將會(huì)自動(dòng)停止Service难菌,對(duì)應(yīng)onDestroy將被調(diào)用试溯。
被啟動(dòng)又被綁定的服務(wù)的生命周期:如果一個(gè)Service又被啟動(dòng)又被綁定,則該Service將會(huì)一直在后臺(tái)運(yùn)行郊酒。并且不管如何調(diào)用遇绞,onCreate始終只會(huì)調(diào)用一次,對(duì)應(yīng)startService調(diào)用多少次燎窘,Service的onStart便會(huì)調(diào)用多少次摹闽。調(diào)用unbindService將不會(huì)停止Service,而必須調(diào)用 stopService 或 Service的 stopSelf 來(lái)停止服務(wù)褐健。
當(dāng)服務(wù)被停止時(shí)清除服務(wù):當(dāng)一個(gè)Service被終止(1付鹿、調(diào)用stopService;2蚜迅、調(diào)用stopSelf舵匾;3、不再有綁定的連接(沒(méi)有被啟動(dòng)))時(shí)谁不,onDestroy方法將會(huì)被調(diào)用坐梯,在這里你應(yīng)當(dāng)做一些清除工作,如停止在Service中創(chuàng)建并運(yùn)行的線程刹帕。
四 Broadcast
1. 廣播的概念
1.1 定義
在Android中烛缔,它是一種廣泛運(yùn)用在應(yīng)用程序之間傳輸信息的機(jī)制馏段,Android中我們發(fā)送廣播內(nèi)容是一個(gè)Intent,這個(gè)Intent中可以攜帶我們要發(fā)送的數(shù)據(jù)。
1.2 廣播的使用場(chǎng)景
a.同一app內(nèi)有多個(gè)進(jìn)程的不同組件之間的消息通信践瓷。
b.不同app之間的組件之間消息的通信院喜。
1.3 廣播的種類
標(biāo)準(zhǔn)廣播:context.sendBroadcast(Intent)方法發(fā)送的廣播,不可被攔截
有序廣播:context.sendOrderBroadcast(Intent)方法發(fā)送的廣播晕翠,可被攔截
本地廣播:localBroadcastManager.sendBroadcast(Intent)喷舀,只在app內(nèi)傳播
2. 廣播接收器
廣播接收器是專門用來(lái)接收廣播信息的,它可分為靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè):
- 靜態(tài)注冊(cè):注冊(cè)完成一直在運(yùn)行淋肾。
首先你要?jiǎng)?chuàng)建一個(gè)廣播接收器類硫麻,實(shí)例代碼如下:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
另外,靜態(tài)的廣播接收器一定要在AndroidManifest.xml文件中注冊(cè)才可以使用樊卓,AndroidManifest.xml文件中注冊(cè)靜態(tài)廣播代碼如下:
<receiver
android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
- 動(dòng)態(tài)注冊(cè):跟隨Activity的生命周期拿愧。
新建一個(gè)類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法就行了碌尔。這樣有廣播到來(lái)時(shí)浇辜,onReceive()方法就會(huì)得到執(zhí)行,具體的邏輯就可以在這個(gè)方法中處理唾戚。 - 動(dòng)態(tài)注冊(cè)廣播接收器的優(yōu)點(diǎn)以及缺點(diǎn):
動(dòng)態(tài)注冊(cè)的廣播接收器可以自由地控制注冊(cè)與注銷柳洋,在靈活性方面有很大優(yōu)勢(shì),但是它也存在著一個(gè)缺點(diǎn)叹坦,即必須要在程序啟動(dòng)之后才能接收到廣播熊镣,因?yàn)樽?cè)的邏輯是寫在onCreate()方法中的。那么有沒(méi)有廣播能在程序未啟動(dòng)的情況下就能接收到廣播呢募书?靜態(tài)注冊(cè)的廣播接收器就可以做到绪囱。
3. 廣播內(nèi)部實(shí)現(xiàn)機(jī)制
自定義廣播接收者BroadcastReceiver,并且重寫onReceiver()方法。
通過(guò)Binder機(jī)制向AMS(Activity Manager Service)進(jìn)行注冊(cè)莹捡。
廣播發(fā)送者通過(guò)Binder機(jī)制向AMS發(fā)送廣播鬼吵。
AMS查找符合條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發(fā)送到相應(yīng)的BroadcastReceiver(一般情況下是Activity)的消息隊(duì)列中道盏。
消息循環(huán)執(zhí)行拿到此廣播而柑,回調(diào)BroadcastReceiver中的onReceiver()方法文捶。
4. 本地廣播
本地廣播的發(fā)送和注冊(cè)廣播接收器都需要使用到LocalBroadcastManager類荷逞,如下所示為本地廣播的發(fā)送和本地廣播接收器注冊(cè)的代碼:
??本地廣播的發(fā)送:
public static void sendLocalBroadcast(Context context,String action){
Intent intent = new Intent(action);
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
localBroadcastManager.sendBroadcast(intent);
}
本地廣播的接收器的注冊(cè):
IntentFilter intentFilter = new IntentFilter();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
intentFilter.addAction(new BroadcastUtil().action_next);
nasbr = new NextAndStartBroadcastReceiver();
localBroadcastManager.registerReceiver(nasbr, intentFilter);//注冊(cè)本地廣播接收器
特點(diǎn):
1. 使用它發(fā)送的廣播將只在自身app內(nèi)傳播,因此你不必?fù)?dān)心泄漏隱私的數(shù)據(jù)粹排。
2. 其他app無(wú)法對(duì)你的app發(fā)送該廣播种远,因此你的app根本不可能收到非自身app發(fā)送的該廣播,因此你不必?fù)?dān)心有安全漏洞可以利用顽耳。
3. 比系統(tǒng)廣播更加高效坠敷。
內(nèi)部實(shí)現(xiàn)機(jī)制:
1. LocalBroadcast高效的原因:因?yàn)樗鼉?nèi)部是通過(guò)Handler實(shí)現(xiàn)的妙同,它的sendBroadcast()方法含義并非和系統(tǒng)的sendBroadcast()一樣,它的sendBroadcast()方法其實(shí)就是通過(guò)Handler發(fā)送了一個(gè)Message而已膝迎。
2. LocalBroadcast安全的原因:既然它是通過(guò)Handler實(shí)現(xiàn)廣播發(fā)送的粥帚,那么相比系統(tǒng)廣播通過(guò)Binder機(jī)制實(shí)現(xiàn)那肯定更加高效,同時(shí)使用Handler來(lái)實(shí)現(xiàn)限次,別的app無(wú)法向我們應(yīng)用發(fā)送該廣播芒涡,而我們app內(nèi)部發(fā)送的廣播也不會(huì)離開(kāi)我們的app。
LocalBroadcast內(nèi)部協(xié)作主要是靠?jī)蓚€(gè)Map集合:mReceivers和mActions,當(dāng)然還有一個(gè)List集合mPendingBroadcasts,這個(gè)主要存儲(chǔ)待接收的廣播對(duì)象卖漫。
五 WebView
1. WebView常見(jiàn)的坑
API 16之前版本存在遠(yuǎn)程代碼執(zhí)行漏洞费尽,該漏洞源自于程序沒(méi)有正確限制使用WebView.addJavascriptInterface方法,攻擊者可以使用Java Reflection API利用該漏洞執(zhí)行任意Java對(duì)象和方法羊始。
WebView的銷毀和內(nèi)存泄漏問(wèn)題旱幼。WebView的完全銷毀是件麻煩事,一旦銷毀流程不正確突委,極易容易導(dǎo)致內(nèi)存泄漏柏卤。
jsbridge
??通過(guò)javascript構(gòu)建一個(gè)橋,橋的兩端一個(gè)端是客戶端鸯两,一端是服務(wù)端闷旧,它可以讓本地端調(diào)用遠(yuǎn)端的web代碼,也可以讓遠(yuǎn)端調(diào)用本地的代碼钧唐。WebViewClient.onPageFinished(不靠譜) –> WebChromeClient.onProgressChanged(靠譜)
后臺(tái)耗電(性能優(yōu)化)
??WebView開(kāi)啟網(wǎng)頁(yè)時(shí)會(huì)自己開(kāi)啟線程忙灼,如果沒(méi)有合理的銷毀,那么殘余線程就會(huì)一直運(yùn)行钝侠,so這會(huì)非常耗電的该园,解決方案:有一種暴力方式就是Activity的onDestroy中調(diào)用System.exit()方法把虛擬機(jī)關(guān)閉,也可以結(jié)合自己應(yīng)用的WebView的情況設(shè)計(jì)出一個(gè)溫柔的方案帅韧。WebView硬件加速導(dǎo)致的頁(yè)面渲染問(wèn)題
??WebView硬件加速偶爾導(dǎo)致頁(yè)面白塊里初,頁(yè)面閃爍,但是加載速度比較快忽舟,解決方案:關(guān)閉硬件加速双妨。
2. WebView的內(nèi)存泄漏問(wèn)題
原因:WebView會(huì)關(guān)聯(lián)一個(gè)Activity,WebView執(zhí)行的操作是在新線程當(dāng)中回收,時(shí)間Activity沒(méi)有辦法確認(rèn)叮阅,Activity的生命周期和WebView線程生命周期不一致導(dǎo)致WebView一直執(zhí)行刁品,因?yàn)閃ebView內(nèi)部持有Activity的引用,導(dǎo)致Activity一直不能被回收浩姥,原理類似于匿名內(nèi)部類持有外部類的引用一樣挑随。那么如何解決呢?解決方案如下:
獨(dú)立進(jìn)程勒叠,簡(jiǎn)單暴力兜挨,涉及到進(jìn)程間通信膏孟。(開(kāi)發(fā)過(guò)程中常用)
動(dòng)態(tài)添加WebView,對(duì)傳入WebView中使用Context弱引用,動(dòng)態(tài)添加WebView意思在布局中創(chuàng)建一個(gè)ViewGroup用來(lái)放置WebView,Activity創(chuàng)建add進(jìn)來(lái)拌汇,Activity停止時(shí)remove掉柒桑。
六 Bainder機(jī)制
通常情況下,Binder是一種通信機(jī)制噪舀。
對(duì)于Server來(lái)說(shuō),Binder指的是Binder本地對(duì)象/對(duì)于Client來(lái)說(shuō)幕垦,Binder指的是Binder的代理對(duì)象。
對(duì)于傳輸過(guò)程而言傅联,Binder是可以進(jìn)行跨進(jìn)程傳遞的對(duì)象先改。
AIDL是Binder機(jī)制的一個(gè)實(shí)例。
七 Handler機(jī)制
1. 定義
Handler是可以通過(guò)發(fā)送和處理Message和Runnable對(duì)象來(lái)關(guān)聯(lián)相應(yīng)線程的MessageQueue蒸走。通常我們認(rèn)為它是一種異步機(jī)制仇奶。
- 可以讓對(duì)應(yīng)的Message和Runnable在未來(lái)的某個(gè)時(shí)間點(diǎn)進(jìn)行相應(yīng)的處理。
- 讓自己想要的耗時(shí)操作在子線程中完成比驻,讓更新UI的操作在主線程中完成该溯,而子線程與主線程之間的通信就是靠Handler來(lái)完成。
2. Handler的使用方法
- post(Runnable)
- sendMessage(Message)
3. Handler內(nèi)部實(shí)現(xiàn)機(jī)制
Handler機(jī)制也可叫異步消息機(jī)制别惦,它主要由4個(gè)部分組成:Message,Handler,MessageQueue,Looper,在上面我們已經(jīng)接觸到了Message和Handler,接下來(lái)我們對(duì)4個(gè)成員進(jìn)行著重的了解:
Message
??Message是在線程之間傳遞的消息狈茉,它可以在內(nèi)部攜帶少量的信息,用于在不同線程之間交換數(shù)據(jù)掸掸。使用Message的arg1和arg2便可攜帶int數(shù)據(jù)氯庆,使用obj便可攜帶Object類型數(shù)據(jù)。Handler
??Handler顧名思義就是處理者的意思扰付,它只要用于在子線程發(fā)送消息對(duì)象Message,在UI線程處理消息對(duì)象Message堤撵,在子線程調(diào)用sendMessage方法發(fā)送消息對(duì)象Message,而發(fā)送的消息經(jīng)過(guò)一系列地輾轉(zhuǎn)之后最終會(huì)被傳遞到Handler的handleMessage方法中,最終在handleMessage方法中消息對(duì)象Message被處理羽莺。MessageQueue
??MessageQueue就是消息隊(duì)列的意思,它只要用于存放所有通過(guò)Handler發(fā)送過(guò)來(lái)的消息实昨。這部分消息會(huì)一直存放于消息隊(duì)列當(dāng)中,等待被處理盐固。每個(gè)線程中只會(huì)有一個(gè)MessageQueue對(duì)象荒给,請(qǐng)牢記這句話。其實(shí)從字面上就可以看出刁卜,MessageQueue底層數(shù)據(jù)結(jié)構(gòu)是隊(duì)列志电,而且這個(gè)隊(duì)列只存放Message對(duì)象。Looper
??Looper是每個(gè)線程中的MessageQueue的管家长酗,調(diào)用Looper的loop()方法后溪北,就會(huì)進(jìn)入到一個(gè)無(wú)限循環(huán)當(dāng)中桐绒,然后每當(dāng)MesssageQueue中存在一條消息夺脾,Looper就會(huì)將這條消息取出之拨,并將它傳遞到Handler的handleMessage()方法中。每個(gè)線程只有一個(gè)Looper對(duì)象咧叭。
Handler機(jī)制流程圖如下:
4. Handler引起的內(nèi)存泄漏以及解決方法
原因:靜態(tài)內(nèi)部類持有外部類的匿名引用蚀乔,導(dǎo)致外部activity無(wú)法得到釋放。
解決方法:handler內(nèi)部持有外部的弱引用菲茬,并把handler改為靜態(tài)內(nèi)部類吉挣,在activity的onDestory()中調(diào)用handler的removeCallback()方法。
八 IntentService機(jī)制
1.IntentService是什么婉弹?
它的優(yōu)先級(jí)高于Service睬魂。
??IntentService是繼承處理異步請(qǐng)求的一個(gè)類,在IntentService內(nèi)有一個(gè)工作線程來(lái)處理耗時(shí)操作镀赌,啟動(dòng)IntentServiced的方式和啟動(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í)行,并且玛追,每次只執(zhí)行一個(gè)工作線程税课,執(zhí)行完第一個(gè)在執(zhí)行第二個(gè)。
- 它本質(zhì)是一種特殊的Service,繼承自Service并且本身就是一個(gè)抽象類痊剖。
- 它內(nèi)部是由HandlerThread和Handler實(shí)現(xiàn)異步操作伯复。
2.IntentService的使用方法
創(chuàng)建IntentService時(shí),只需要實(shí)現(xiàn)onHandlerIntent和構(gòu)造方法邢笙,onHandlerIntent為異步方法啸如,可以執(zhí)行耗時(shí)操作。
九 AsyncTask 機(jī)制
1.AsyncTask是什么氮惯?
它本質(zhì)上是一個(gè)封裝了線程池和Handler的異步框架叮雳。
2.AsyncTask的基本用法
- 3個(gè)參數(shù):Params, Progress 和 Result
- Params表示用于AsyncTask執(zhí)行任務(wù)的參數(shù)的類型
- Progress表示在后臺(tái)線程處理的過(guò)程中,可以階段性地發(fā)布結(jié)果的數(shù)據(jù)類型
- Result表示任務(wù)全部完成后所返回的數(shù)據(jù)類型
- 5個(gè)方法
- onPreExecute
該方法是運(yùn)行在主線程中的妇汗。在AsyncTask執(zhí)行了execute()方法后就會(huì)在UI線程上執(zhí)行onPreExecute()方法帘不,該方法在task真正執(zhí)行前運(yùn)行,我們通逞罴可以在該方法中顯示一個(gè)進(jìn)度條寞焙,從而告知用戶后臺(tái)任務(wù)即將開(kāi)始。 - doInBackground
該方法是運(yùn)行在單獨(dú)的工作線程中的,而不是運(yùn)行在主線程中捣郊。 - onProgressUpdate
當(dāng)我們?cè)赿oInBackground中調(diào)用publishProgress(Progress…)方法后辽狈,就會(huì)在UI線程上回調(diào)onProgressUpdate方法。 - onPostExecute
當(dāng)doInBackgroud方法執(zhí)行完畢后呛牲,就表示任務(wù)完成了刮萌,doInBackgroud方法的返回值就會(huì)作為參數(shù)在主線程中傳入到onPostExecute方法中,這樣就可以在主線程中根據(jù)任務(wù)的執(zhí)行結(jié)果更新UI娘扩。
3.AsyncTask機(jī)制的原理
它本質(zhì)上是一個(gè)靜態(tài)的線程池着茸,AsyncTask派生出的子類可以實(shí)現(xiàn)不同的異步任務(wù),這些任務(wù)都是提交到靜態(tài)的線程池中執(zhí)行琐旁。
線程池中的工作線程執(zhí)行doInBackground(mParams)方法執(zhí)行異步的任務(wù)涮阔。
當(dāng)任務(wù)狀態(tài)改變后,工作線程向UI線程發(fā)送消息灰殴,AsyncTask內(nèi)部的InternalHandler響應(yīng)這些消息澎语,并調(diào)用相關(guān)的回調(diào)函數(shù)。
4.AsyncTask注意事項(xiàng):
- 內(nèi)存泄漏:
靜態(tài)內(nèi)部類持有外部類的匿名引用验懊,導(dǎo)致外部對(duì)象無(wú)法得到釋放擅羞,解決方法很簡(jiǎn)單,讓內(nèi)部持有外部的弱引用即可解決
生命周期
??在Activity的onDestory()中及時(shí)對(duì)AsyncTask進(jìn)行回收义图,調(diào)用其cancel()方法來(lái)保證程序的穩(wěn)定性减俏。結(jié)果丟失
??當(dāng)內(nèi)存不足時(shí),當(dāng)前的Activity被回收碱工,由于AsyncTask持有的是回收之前Activity的引用娃承,導(dǎo)致AsyncTask更新的結(jié)果對(duì)象為一個(gè)無(wú)效的Activity的引用,這就是結(jié)果丟失怕篷。并行或串行
??在1.6(Donut)之前: 在第一版的AsyncTask历筝,任務(wù)是串行調(diào)度。一個(gè)任務(wù)執(zhí)行完成另一個(gè)才能執(zhí)行廊谓。由于串行執(zhí)行任務(wù)梳猪,使用多個(gè)AsyncTask可能會(huì)帶來(lái)有些問(wèn)題。所以這并不是一個(gè)很好的處理異步(尤其是需要將結(jié)果作用于UI試圖)操作的方法蒸痹。1.6-2.3: 所有的任務(wù)并發(fā)執(zhí)行春弥,這會(huì)導(dǎo)致一種情況,就是其中一條任務(wù)執(zhí)行出問(wèn)題了叠荠,會(huì)引起其他任務(wù)出現(xiàn)錯(cuò)誤匿沛。3.0之后AsyncTask又修改為了順序執(zhí)行,并且新添加了一個(gè)函數(shù) executeOnExecutor(Executor)榛鼎,如果您需要并行執(zhí)行逃呼,則只需要調(diào)用該函數(shù)鳖孤,并把參數(shù)設(shè)置為并行執(zhí)行即可。
十 HandlerThread機(jī)制
1.HandlerThread的產(chǎn)生背景
開(kāi)啟子線程進(jìn)行耗時(shí)操作抡笼,多次創(chuàng)建和銷毀子線程是很耗費(fèi)資源的苏揣,但是木有關(guān)系,谷歌考慮了這點(diǎn)為我們專門開(kāi)發(fā)出了HandlerThread機(jī)制蔫缸。
2.HandlerThread是什么?
本質(zhì):Handler + Thread + Looper际起,是一個(gè)Thread內(nèi)部有Looper拾碌。
HandlerThread本質(zhì)上是一個(gè)線程類,它繼承了Thread街望。
HandlerThread有自己內(nèi)部的Looper對(duì)象校翔,可以進(jìn)行Looper循環(huán)。
通過(guò)獲取HandlerThread的Looper對(duì)象傳遞給Handler對(duì)象灾前,可以在handlerMessage方法中執(zhí)行異步任務(wù)防症。
優(yōu)點(diǎn)是不會(huì)有堵塞,減少對(duì)性能的消耗哎甲,缺點(diǎn)是不能進(jìn)行多任務(wù)的處理蔫敲,需要等待進(jìn)行處理,處理效率較低炭玫。
與線程池注重并發(fā)不同奈嘿,HandlerThread是一個(gè)串行隊(duì)列,HandlerThread背后只有一個(gè)線程吞加。
十一 IntentService機(jī)制
1.IntentService是什么裙犹?
它的優(yōu)先級(jí)高于Service。
??IntentService是繼承處理異步請(qǐng)求的一個(gè)類衔憨,在IntentService內(nèi)有一個(gè)工作線程來(lái)處理耗時(shí)操作叶圃,啟動(dòng)IntentServiced的方式和啟動(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í)行闽瓢,并且接癌,每次只執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)在執(zhí)行第二個(gè)扣讼。
它本質(zhì)是一種特殊的Service,繼承自Service并且本身就是一個(gè)抽象類缺猛。
它內(nèi)部是由HandlerThread和Handler實(shí)現(xiàn)異步操作。
2.IntentService的使用方法
創(chuàng)建IntentService時(shí),只需要實(shí)現(xiàn)onHandlerIntent和構(gòu)造方法荔燎,onHandlerIntent為異步方法耻姥,可以執(zhí)行耗時(shí)操作。
十二 View繪制機(jī)制
1. View樹(shù)的繪制流程
measure(測(cè)量)→layout(布局)→draw(繪制)
2. Measure過(guò)程
measure過(guò)程主要就是從頂層父View向子View遞歸調(diào)用view.measure方法(measure中又回調(diào)onMeasure方法)的過(guò)程有咨。具體measure核心主要有如下幾點(diǎn):
MeasureSpec(View的內(nèi)部類)測(cè)量規(guī)格為int型琐簇,值由高2位規(guī)格模式specMode和低30位具體尺寸specSize組成。其中specMode只有三種值:
- MeasureSpec.EXACTLY //確定模式座享,父View希望子View的大小是確定的婉商,由specSize決定;
- MeasureSpec.AT_MOST //最多模式渣叛,父View希望子View的大小最多是specSize指定的值丈秩;
- MeasureSpec.UNSPECIFIED //未指定模式,父View完全依據(jù)子View的設(shè)計(jì)值來(lái)決定淳衙;
View的measure方法是final的蘑秽,不允許重載,View子類只能重載onMeasure來(lái)完成自己的測(cè)量邏輯箫攀。
最頂層DecorView測(cè)量時(shí)的MeasureSpec是由ViewRootImpl中g(shù)etRootMeasureSpec方法確定的(LayoutParams寬高參數(shù)均為MATCH_PARENT肠牲,specMode是EXACTLY,specSize為物理屏幕大醒ヵ恕)埂材。
ViewGroup類提供了measureChild,measureChild和measureChildWithMargins方法汤求,簡(jiǎn)化了父子View的尺寸計(jì)算俏险。
只要是ViewGroup的子類就必須要求LayoutParams繼承子MarginLayoutParams,否則無(wú)法使用layout_margin參數(shù)扬绪。
View的布局大小由父View和子View共同決定竖独。
使用View的getMeasuredWidth()和getMeasuredHeight()方法來(lái)獲取View測(cè)量的寬高,必須保證這兩個(gè)方法在onMeasure流程之后被調(diào)用才能返回有效值挤牛。
3. Layout過(guò)程
整個(gè)layout過(guò)程比較容易理解莹痢,從上面分析可以看出layout也是從頂層父View向子View的遞歸調(diào)用view.layout方法的過(guò)程,即父View根據(jù)上一步measure子View所得到的布局大小和布局參數(shù)墓赴,將子View放在合適的位置上竞膳。具體layout核心主要有以下幾點(diǎn):
View.layout方法可被重載,ViewGroup.layout為final的不可重載诫硕,ViewGroup.onLayout為abstract的坦辟,子類必須重載實(shí)現(xiàn)自己的位置邏輯。
measure操作完成后得到的是對(duì)每個(gè)View經(jīng)測(cè)量過(guò)的measuredWidth和measuredHeight章办,layout操作完成之后得到的是對(duì)每個(gè)View進(jìn)行位置分配后的mLeft锉走、mTop滨彻、mRight、mBottom挪蹭,這些值都是相對(duì)于父View來(lái)說(shuō)的亭饵。
凡是layout_XXX的布局屬性基本都針對(duì)的是包含子View的ViewGroup的,當(dāng)對(duì)一個(gè)沒(méi)有父容器的View設(shè)置相關(guān)layout_XXX屬性是沒(méi)有任何意義的(前面《Android應(yīng)用setContentView與LayoutInflater加載解析機(jī)制源碼分析》也有提到過(guò))梁厉。
使用View的getWidth()和getHeight()方法來(lái)獲取View測(cè)量的寬高辜羊,必須保證這兩個(gè)方法在onLayout流程之后被調(diào)用才能返回有效值。
4.Draw過(guò)程
繪制過(guò)程就是把View對(duì)象繪制到屏幕上词顾,整個(gè)draw過(guò)程需要注意如下細(xì)節(jié):
如果該View是一個(gè)ViewGroup八秃,則需要遞歸繪制其所包含的所有子View。
View默認(rèn)不會(huì)繪制任何內(nèi)容计技,真正的繪制都需要自己在子類中實(shí)現(xiàn)喜德。
View的繪制是借助onDraw方法傳入的Canvas類來(lái)進(jìn)行的山橄。
區(qū)分View動(dòng)畫和ViewGroup布局動(dòng)畫垮媒,前者指的是View自身的動(dòng)畫,可以通過(guò)setAnimation添加航棱,后者是專門針對(duì)ViewGroup顯示內(nèi)部子視圖時(shí)設(shè)置的動(dòng)畫睡雇,可以在xml布局文件中對(duì)ViewGroup設(shè)置layoutAnimation屬性(譬如對(duì)LinearLayout設(shè)置子View在顯示時(shí)出現(xiàn)逐行、隨機(jī)饮醇、下等顯示等不同動(dòng)畫效果)它抱。
在獲取畫布剪切區(qū)(每個(gè)View的draw中傳入的Canvas)時(shí)會(huì)自動(dòng)處理掉padding,子View獲取Canvas不用關(guān)注這些邏輯朴艰,只用關(guān)心如何繪制即可观蓄。
默認(rèn)情況下子View的ViewGroup.drawChild繪制順序和子View被添加的順序一致,但是你也可以重載ViewGroup.getChildDrawingOrder()方法提供不同順序祠墅。
十三 Android部分事件分發(fā)機(jī)制
1. 為什么有事件分發(fā)機(jī)制
Android上面的View是樹(shù)形結(jié)構(gòu)侮穿,View可能會(huì)重疊在一起,當(dāng)我們點(diǎn)擊的地方有多個(gè)View都可以響應(yīng)的時(shí)候怜森,這個(gè)點(diǎn)擊事件應(yīng)該給誰(shuí)呢郭膛?為了解決這個(gè)問(wèn)題盹廷,就有了事件分發(fā)機(jī)制。
2. 3個(gè)重要的有關(guān)事件分發(fā)的方法
-
dispatch TouchEvent
用來(lái)進(jìn)行事件的分發(fā)克锣。如果事件能夠傳遞給當(dāng)前View,那么此方法一定會(huì)被調(diào)用,返回結(jié)果受當(dāng)前View的onTouchEvent和下級(jí)的dispatchTouchEvent方法影響腔长,表示是否消耗此事件袭祟。 -
onInterceptTouchEvent
在上述方法dispatchTouchEvent內(nèi)部調(diào)用,用來(lái)判斷是否攔截某個(gè)事件捞附,如果當(dāng)前View攔截了某個(gè)事件榕酒,那么同一個(gè)事件序列當(dāng)中胚膊,此方法不會(huì)被再次調(diào)用,返回結(jié)果表示是否攔截當(dāng)前事件想鹰。 -
onTouchEvent
同樣也會(huì)在dispatchTouchEvent內(nèi)部調(diào)用紊婉,用來(lái)處理點(diǎn)擊事件,返回結(jié)果表示是否消耗當(dāng)前事件辑舷,如果不消耗喻犁,則在同一個(gè)事件序列中,當(dāng)前View無(wú)法再次接收到事件何缓。
偽代碼
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;//記錄返回值
if(onInterceptTouchEvent(ev)){//判斷是否攔截此事件
consume = onTouchEvent(ev);//如果當(dāng)前確認(rèn)攔截此事件肢础,那么就處理這個(gè)事件
}else{
consume = child.dispatchToucnEvent(ev);//如果當(dāng)前確認(rèn)不攔截此事件,那么就將事件分發(fā)給下一級(jí)
}
return consume;
}
通過(guò)上述偽代碼碌廓,我們可以得知點(diǎn)擊事件的傳遞規(guī)則:對(duì)于一個(gè)根ViewGroup而言传轰,點(diǎn)擊事件產(chǎn)生后,首先會(huì)傳遞給它谷婆,這時(shí)它的dispatchTouch就會(huì)被調(diào)用慨蛙,如果這個(gè)ViewGroup的onInterceptTouchEvent方法返回true就表示它要攔截當(dāng)前的事件,接著事件就會(huì)交給這個(gè)ViewGroup處理纪挎,即它的onTouch方法就會(huì)被調(diào)用期贫;如果這個(gè)ViewGroup的onInterceptTouchEvent方法返回false就表示它不攔截當(dāng)前事件,這時(shí)當(dāng)前事件就會(huì)繼續(xù)傳遞給它的子元素异袄,接著子元素的dispatchTouchEvent方法就會(huì)被調(diào)用通砍,如此直到事件被最終處理。
當(dāng)一個(gè)View需要處理事件時(shí)烤蜕,如果它設(shè)置了OnTouchListener,那么OnTouchListener中的onTouch方法會(huì)被回調(diào)封孙。這時(shí)事件處理還要看onTouch的返回值,如果返回false,則當(dāng)前View的onTouchEvent方法會(huì)被調(diào)用;如果返回true,那么當(dāng)前View的onTouchEvent方法不會(huì)被調(diào)用讽营。由此可見(jiàn)虎忌,給View設(shè)置的onTouchListener的優(yōu)先級(jí)比onTouchEvent要高。在onTouchEvent方法中斑匪,如果當(dāng)前設(shè)置的有onClickListener呐籽,那么它的onClick方法會(huì)被調(diào)用∈慈常可以看出狡蝶,平時(shí)我們常用的OnClickListener,其優(yōu)先級(jí)最低,即處于事件傳遞的尾端贮勃。
當(dāng)一個(gè)點(diǎn)擊事件產(chǎn)生后贪惹,它的傳遞過(guò)程遵循如下順序:Activity–>Window–>View,即事件總數(shù)先傳遞給Activity,Activity再傳遞給Window,最后Window再傳遞給頂級(jí)View,頂級(jí)View接收到事件后,就會(huì)按照事件分發(fā)機(jī)制去分發(fā)事件寂嘉∽嗨玻考慮一種情況枫绅,如果一個(gè)View的onTouchEvent返回false,那么它的父容器的onTouchEvent將會(huì)被調(diào)用,依次類推硼端。如果所有的元素都不處理這個(gè)事件并淋,那么這個(gè)事件將會(huì)最終傳遞給Activity處理, 即Activity的onTouchEvent方法會(huì)被調(diào)用珍昨。這個(gè)過(guò)程其實(shí)很好理解县耽,我們可以換一種思路,假設(shè)點(diǎn)擊事件是一個(gè)難題镣典,這個(gè)難題最終被上級(jí)領(lǐng)導(dǎo)分給了一個(gè)程序員去處理(這是事件分發(fā)過(guò)程)兔毙,結(jié)果這個(gè)程序員搞不定(onTouchEvent返回了false),現(xiàn)在該怎么辦呢?難題必須要解決兄春,那就只能交給水平更高的上級(jí)解決(上級(jí)的onTouchEvent被調(diào)用)澎剥,如果上級(jí)再搞不定,那就只能交給上級(jí)的上級(jí)去解決赶舆,就這樣難題一層層地向上拋哑姚,這是公司內(nèi)部一種常見(jiàn)的處理問(wèn)題的過(guò)程。
關(guān)于事件傳遞機(jī)制還需要注意以下:
同一見(jiàn)事件序列是從手指接觸屏幕的那一刻起涌乳,到手指離開(kāi)屏幕的那一刻結(jié)束蜻懦,在這個(gè)過(guò)程中所產(chǎn)生的一系列事件甜癞,這個(gè)事件的序列以down開(kāi)始夕晓,中間含有數(shù)量不定的move事件,最終以u(píng)p事件結(jié)束悠咱。
正常情況下蒸辆,一個(gè)事件序列只能被一個(gè)View攔截且消耗。這一條的原因可以參考(3)析既,因?yàn)橐坏┮粋€(gè)元素?cái)r截了某個(gè)事件躬贡,那么同一個(gè)事件序列的所有事件都會(huì)直接交給它處理,因此同一個(gè)事件序列中的事件不能分別由兩個(gè)View同時(shí)處理眼坏,但是通過(guò)特殊手段可以做到拂玻,比如
一個(gè)View將本該自己處理的事件通過(guò)onTouchEvent強(qiáng)行傳遞給其他View處理。某個(gè)View一旦決定攔截宰译,那么這個(gè)事件序列都只能由它來(lái)處理(如果事件序列能夠傳遞給它的話)檐蚜,并且它的onInterceptTouchEvent不會(huì)被調(diào)用。這條也很好理解沿侈,就是說(shuō)當(dāng)一個(gè)View決定攔截一個(gè)事件后闯第,那么系統(tǒng)會(huì)把同一個(gè)事件序列內(nèi)的其他方法都直接交給它來(lái)處理,因此就不用再調(diào)用這個(gè)View的onInterceptTouchEvent去詢問(wèn)它是否攔截了缀拭。
某個(gè)View一旦開(kāi)始處理事件咳短,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false)填帽,那么同一件序列中的其他事件都不會(huì)再交給它處理,并且事件 將重新交由它的父元素去處理咙好,即父元素的onTouchEvent會(huì)被調(diào)用篡腌。意思就是事件一旦交給一個(gè)View處理,那么它就必須消耗掉勾效,否則同一事件序列中剩下的事件就不再交給它處理了哀蘑,這就好比上級(jí)交給程序員一件事,如果這件事沒(méi)有處理好葵第,短時(shí)間內(nèi)上級(jí)就不敢再把事件交給這個(gè)程序員做了绘迁,二者是類似的道理。
如果View不消耗ACTION_DOWN以外的事件卒密,那么這個(gè)點(diǎn)擊事件會(huì)消失缀台,此時(shí)父元素的onTouchEvent并不會(huì)調(diào)用,并且當(dāng)前View可以持續(xù)收到后續(xù)的事件哮奇,最終這些消失的點(diǎn)擊事件會(huì)傳遞給Activity處理膛腐。
ViewGroup默認(rèn)不攔截任何事件。Android源碼中ViewGroup的onInterceptTouchEvent方法默認(rèn)返回false鼎俘。
View沒(méi)有onInterceptTouchEvent方法哲身,一旦點(diǎn)擊事件傳遞給它,那么它的onTouchEvent方法就會(huì)被調(diào)用贸伐。
View的onTouchEvent默認(rèn)都會(huì)消耗事件(返回true),除非它是不可點(diǎn)擊的(clickable和longClickable同時(shí)為false)勘天。View的longClickable屬性默認(rèn)為false,clickable屬性要分情況捉邢,比如Button的clickable屬性默認(rèn)為true,而TextView的clickable屬性默認(rèn)為false脯丝。
View的enable屬性不影響onTouchEvent的默認(rèn)返回值。哪怕一個(gè)View是disable狀態(tài)的伏伐,只要它的clickable或者longClickable有一個(gè)為true,那么它的onTouchEvent就返回true宠进。
onClick會(huì)發(fā)生的前提是當(dāng)前View是可點(diǎn)擊的,并且它接收到了down和up事件藐翎。
事件傳遞過(guò)程是由外向內(nèi)的材蹬,即事件總是先傳遞給父元素,然后再由父元素分發(fā)給子View,通過(guò)requestDisallowInterTouchEvent方法可以在子元素中干預(yù)父元素的事件分發(fā)過(guò)程吝镣,但是ACTION_DOWN事件除外堤器。
3. 事件分發(fā)的流程
Activity–>PhoneWindow–>DecorView–>ViewGroup–>…–>View(View樹(shù)最底部的View)
十三 ListView
1. ListView是什么?
ListView就是能用一個(gè)數(shù)據(jù)集合以動(dòng)態(tài)滾動(dòng)的方式展示到用戶界面上的View赤惊。
2. ListView的適配器
- ArrayAdapter:支持泛型操作吼旧,最簡(jiǎn)單的一個(gè)Adapter,只能展現(xiàn)一行文字
- SimpleAdapter:同樣具有良好擴(kuò)展性的一個(gè)Adapter未舟,可以自定義多種效果
- BaseAdapter:抽象類圈暗,實(shí)際開(kāi)發(fā)中我們會(huì)繼承這個(gè)類并且重寫相關(guān)方法掂为,用得最多的一個(gè)Adapter
BaseAdapter是開(kāi)發(fā)中最常用的適配器ArrayAdapter, SimpleAdapter 都繼承于BaseAdapter。BaseAdapter可以完成自己定義的Adapter员串,可以將任何復(fù)雜組合的數(shù)據(jù)和資源勇哗,以任何你想要的顯示效果展示給用戶。
繼承BaseAdapter之后寸齐,需要重寫以下四個(gè)方法:getCount欲诺,getItem,getItemId渺鹦,getView扰法。
系統(tǒng)在繪制ListView之前,將會(huì)先調(diào)用getCount方法來(lái)獲取Item的個(gè)數(shù)毅厚。每繪制一個(gè)Item就會(huì)調(diào)用一次getView方法塞颁,在getView中引用事先定義好的layout布局確定顯示的效果并返回一個(gè)View對(duì)象作為一個(gè)Item顯示出來(lái)。
這兩個(gè)方法是自定ListView顯示效果中最為重要的吸耿,同時(shí)只要重寫好了這兩個(gè)方法祠锣,ListView就能完全按開(kāi)發(fā)者的要求顯示。而getItem和getItemId方法將會(huì)在調(diào)用ListView的響應(yīng)方法的時(shí)候被調(diào)用到咽安。
3. ListView的recycleBin機(jī)制
在某一時(shí)刻伴网,我們看到ListView中有許多View呈現(xiàn)在UI上,這些View對(duì)我們來(lái)說(shuō)是可見(jiàn)的妆棒,這些可見(jiàn)的View可以稱作OnScreen的View澡腾,即在屏幕中能看到的View,也可以叫做ActiveView募逞,因?yàn)樗鼈兪窃赨I上可操作的蛋铆。
當(dāng)觸摸ListView并向上滑動(dòng)時(shí)馋评,ListView上部的一些OnScreen的View位置上移放接,并移除了ListView的屏幕范圍,此時(shí)這些OnScreen的View就變得不可見(jiàn)了留特,不可見(jiàn)的View叫做OffScreen的View纠脾,即這些View已經(jīng)不在屏幕可見(jiàn)范圍內(nèi)了,也可以叫做ScrapView蜕青,Scrap表示廢棄的意思苟蹈,ScrapView的意思是這些OffScreen的View不再處于可以交互的Active狀態(tài)了。ListView會(huì)把那些ScrapView(即OffScreen的View)刪除右核,這樣就不用繪制這些本來(lái)就不可見(jiàn)的View了慧脱,同時(shí),ListView會(huì)把這些刪除的ScrapView放入到RecycleBin中存起來(lái)贺喝,就像把暫時(shí)無(wú)用的資源放到回收站一樣菱鸥。
當(dāng)ListView的底部需要顯示新的View的時(shí)候宗兼,會(huì)從RecycleBin中取出一個(gè)ScrapView,將其作為convertView參數(shù)傳遞給Adapter的getView方法氮采,從而達(dá)到View復(fù)用的目的殷绍,這樣就不必在Adapter的getView方法中執(zhí)行LayoutInflater.inflate()方法了。
RecycleBin中有兩個(gè)重要的View數(shù)組鹊漠,分別是mActiveViews和mScrapViews主到。這兩個(gè)數(shù)組中所存儲(chǔ)的View都是用來(lái)復(fù)用的,只不過(guò)mActiveViews中存儲(chǔ)的是OnScreen的View躯概,這些View很有可能被直接復(fù)用登钥;而mScrapViews中存儲(chǔ)的是OffScreen的View,這些View主要是用來(lái)間接復(fù)用的娶靡。
4. ListView優(yōu)化
convertView重用機(jī)制
ViewHolder機(jī)制
三級(jí)緩沖/滑動(dòng)監(jiān)聽(tīng)事件
優(yōu)化一:在Adapter中的getView方法中使用ConvertView怔鳖,即ConvertView的復(fù)用,不需要每次都inflate一個(gè)View出來(lái)固蛾,這樣既浪費(fèi)時(shí)間结执,又浪費(fèi)內(nèi)存。
優(yōu)化二:使用ViewHolder艾凯,不要在getView方法中寫findViewById方法献幔,因?yàn)間etView方法會(huì)執(zhí)行很多遍,這樣也可以節(jié)省時(shí)間趾诗,節(jié)約內(nèi)存蜡感。
優(yōu)化三:使用分頁(yè)加載,講真實(shí)際開(kāi)發(fā)中恃泪,ListView的數(shù)據(jù)肯定不止幾百條郑兴,成千上萬(wàn)條數(shù)據(jù)你不可能一次性加載出來(lái),所以這里需要用到分頁(yè)加載贝乎,一次加載幾條或者十幾條情连,但是如果數(shù)據(jù)量很大的話,像qq览效,微信這種却舀,如果順利加載到最后面的話,那么你的list中也會(huì)有幾萬(wàn)甚至幾十萬(wàn)的數(shù)據(jù)锤灿,這樣可能也會(huì)導(dǎo)致OOM挽拔,所以你的數(shù)據(jù)集List中也不能有那么多數(shù)據(jù),所以每加載一頁(yè)的時(shí)候你可以覆蓋前一頁(yè)的數(shù)據(jù)但校。
優(yōu)化四:如果數(shù)據(jù)當(dāng)中有圖片的話螃诅,使用第三方庫(kù)來(lái)加載(也就是緩存),如果你的能力強(qiáng)大到能自己維護(hù)的話,那也不是不可以术裸。
優(yōu)化五:當(dāng)你手指在滑動(dòng)列表的時(shí)候空执,盡可能的不加載圖片,這樣的話滑動(dòng)就會(huì)更加流暢穗椅。
十四 動(dòng)畫
1.Android動(dòng)畫的分類
1.1 補(bǔ)間動(dòng)畫
a.漸變動(dòng)畫支持四種類型:平移(Translate)辨绊、旋轉(zhuǎn)(Rotate)、縮放(Scale)匹表、不透明度
b. 只是顯示的位置變動(dòng)门坷,View的實(shí)際位置未改變,表現(xiàn)為View移動(dòng)到其他地方袍镀,點(diǎn)擊事件仍在原處才能響應(yīng)默蚌。
c. 組合使用步驟較復(fù)雜。
d. View Animation 也是指此動(dòng)畫苇羡。
1.2 幀動(dòng)畫
a. 用于生成連續(xù)的Gif效果圖绸吸。
b. DrawableAnimation也是指此動(dòng)畫
1.3 屬性動(dòng)畫
a.支持對(duì)所有View能更新的屬性的動(dòng)畫(需要屬性的setXxx()和getXxx())。
b. 更改的是View實(shí)際的屬性设江,所以不會(huì)影響其在動(dòng)畫執(zhí)行后所在位置的正常使用锦茁。
c. Android3.0(API11)及以后出現(xiàn)的功能,3.0之前的版本可使用github第三方開(kāi)源庫(kù)nineoldandroids.jar進(jìn)行支持叉存。
2.補(bǔ)間動(dòng)畫码俩,幀動(dòng)畫,屬性動(dòng)畫優(yōu)缺點(diǎn)
2.1 補(bǔ)間動(dòng)畫優(yōu)缺點(diǎn)
缺點(diǎn):當(dāng)平移動(dòng)畫執(zhí)行完停在最后的位置歼捏,結(jié)果焦點(diǎn)還在原來(lái)的位置(控件的屬性沒(méi)有真的被改變)
優(yōu)點(diǎn):相對(duì)于逐幀動(dòng)畫來(lái)說(shuō)稿存,補(bǔ)間動(dòng)畫更為連貫自然
2.2 幀動(dòng)畫優(yōu)缺點(diǎn)
缺點(diǎn):效果單一,逐幀播放需要很多圖片瞳秽,占用控件較大
優(yōu)點(diǎn):制作簡(jiǎn)單
2.3 屬性動(dòng)畫優(yōu)缺點(diǎn)
缺點(diǎn):(3.0+API出現(xiàn))向下兼容問(wèn)題瓣履。
優(yōu)點(diǎn):易定制,效果強(qiáng)练俐。
十五 自定義View
1. 自定義View的幾種方式
對(duì)原View進(jìn)行擴(kuò)展方式
多個(gè)View的組合方式
重寫View的方式
2.自定義View需要重寫的方法袖迎。
- onMesure(測(cè)量)
- onLayout(布局)
- onDraw(繪制)
十六 Context
Context的中文翻譯為:語(yǔ)境; 上下文; 背景; 環(huán)境,在開(kāi)發(fā)中我們經(jīng)常說(shuō)稱之為“上下文”痰洒,那么這個(gè)“上下文”到底是指什么意思呢瓢棒?在語(yǔ)文中,我們可以理解為語(yǔ)境丘喻,在程序中,我們可以理解為當(dāng)前對(duì)象在程序中所處的一個(gè)環(huán)境念颈,一個(gè)與系統(tǒng)交互的過(guò)程泉粉。比如微信聊天,此時(shí)的“環(huán)境”是指聊天的界面以及相關(guān)的數(shù)據(jù)請(qǐng)求與傳輸,Context在加載資源嗡靡、啟動(dòng)Activity跺撼、獲取系統(tǒng)服務(wù)、創(chuàng)建View等操作都要參與讨彼。
Context提供了關(guān)于應(yīng)用環(huán)境全局信息的接口歉井。它是一個(gè)抽象類,它的執(zhí)行被Android系統(tǒng)所提供哈误。它允許獲取以應(yīng)用為特征的資源和類型哩至,是一個(gè)統(tǒng)領(lǐng)一些資源(應(yīng)用程序環(huán)境變量等)的上下文。就是說(shuō)蜜自,它描述一個(gè)應(yīng)用程序環(huán)境的信息(即上下文)菩貌;是一個(gè)抽象類,Android提供了該抽象類的具體實(shí)現(xiàn)類重荠;通過(guò)它我們可以獲取應(yīng)用程序的資源和類(包括應(yīng)用級(jí)別操作箭阶,如啟動(dòng)Activity,發(fā)廣播戈鲁,接受Intent等)仇参。
Context的作用域:
十七 ContentProvider
1. 簡(jiǎn)介
內(nèi)容提供者(Content Provider)主要用于在不同的應(yīng)用程序之間實(shí)現(xiàn)數(shù)據(jù)共享的功能,它提供了一套完整的機(jī)制婆殿,允許一個(gè)程序訪問(wèn)另一個(gè)程序中的數(shù)據(jù)冈敛,同時(shí)還能保證被訪數(shù)據(jù)的安全性。目前鸣皂,使用內(nèi)容提供者是Android實(shí)現(xiàn)跨程序共享數(shù)據(jù)的標(biāo)準(zhǔn)方式抓谴。
不同于文件存儲(chǔ)和SharedPreferences存儲(chǔ)中的兩種全局可讀可寫操作模式,內(nèi)容提供者可以選擇只對(duì)哪一部分?jǐn)?shù)據(jù)進(jìn)行共享寞缝,從而保證我們程序中的隱私數(shù)據(jù)不會(huì)泄露的風(fēng)險(xiǎn)癌压。
2.通過(guò)內(nèi)容提供者訪問(wèn)其他程序的數(shù)據(jù)
內(nèi)容提供者的用法一般有兩種,一種是使用現(xiàn)有的內(nèi)容提供器來(lái)讀取和操作相應(yīng)程序中的數(shù)據(jù)荆陆,另一種是創(chuàng)建自己的內(nèi)容提供者來(lái)給我們的程序提供外部訪問(wèn)接口滩届。如果一個(gè)程序通過(guò)內(nèi)容提供者對(duì)其數(shù)據(jù)提供外部訪問(wèn)接口,那么任何其他的應(yīng)用程序就都可以對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行訪問(wèn)被啼。Android系統(tǒng)中自帶的電話簿帜消,短信,媒體庫(kù)等程序都提供了類似的訪問(wèn)接口浓体,這就使得第三方應(yīng)用程序可以充分利用這部分?jǐn)?shù)據(jù)來(lái)實(shí)現(xiàn)更好的功能泡挺。下面我們就來(lái)看看如何通過(guò)內(nèi)容提供者訪問(wèn)其他程序的數(shù)據(jù):
2.1 ContentResolver的基本用法
想要訪問(wèn)內(nèi)容提供者中共享的數(shù)據(jù),就一定要借助CotentResolver類命浴,可以通過(guò)Context中的getContentResolver()方法獲取該類的實(shí)例娄猫。ContentResolver中提供了一系列的方法用于對(duì)數(shù)據(jù)進(jìn)行CRUD(增刪改查)操作贱除,其中insert()方法用于添加數(shù)據(jù),update()方法用于數(shù)據(jù)的更新媳溺,delete()方法用于數(shù)據(jù)的刪除月幌,query()方法用于數(shù)據(jù)的查詢。這好像SQLite數(shù)據(jù)庫(kù)操作有木有悬蔽?
??不同于SQLiteDatabase,ContentResolver中的增刪改查方法都是不接收表名參數(shù)的扯躺,而是使用一個(gè)Uri的參數(shù)代替,這個(gè)參數(shù)被稱作內(nèi)容URI蝎困。內(nèi)容URI給內(nèi)容提供者中的數(shù)據(jù)建立了唯一的標(biāo)識(shí)符录语,它主要由兩部分組成:authority和path。authority是用于對(duì)不同的應(yīng)用程序做區(qū)分的难衰,一般為了避免沖突钦无,都會(huì)采用程序包名的方式來(lái)進(jìn)行命名。比如某個(gè)程序的包名為com.example.app,那么該程序?qū)?yīng)的authority就可以命名為com.example.app.provider盖袭。path則是用于對(duì)同一應(yīng)用程序中不同的表做區(qū)分的失暂,通常都會(huì)添加到authority的后面。比如某個(gè)程序的數(shù)據(jù)庫(kù)里存在兩張表:table1和table2,這時(shí)就可以將path分別命名為/table1和/table2鳄虱,然后把a(bǔ)uthority和path進(jìn)行組合弟塞,內(nèi)容的URI就變成了com.example.app.provider/table1和com.example.app.provider/table2。不過(guò)目前還是很難辨認(rèn)出這兩個(gè)字符串就是兩個(gè)內(nèi)容URI,我們還需要在字符串的頭部加上協(xié)議聲明拙已。因此决记,內(nèi)容URI最標(biāo)準(zhǔn)的格式寫法如下:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
在得到內(nèi)容URI字符串之后,我們還需要將它解析成Uri對(duì)象才可以作為參數(shù)傳入倍踪。解析的方法也相當(dāng)簡(jiǎn)單系宫,代碼如下所示:
Uri uri = new Uri.parse("content://com.example.app.provider/table1");
只需要調(diào)用Uri的靜態(tài)方法parse()就可以把內(nèi)容URI字符串解析成URI對(duì)象。
??現(xiàn)在建车,我們可以通過(guò)這個(gè)Uri對(duì)象來(lái)查詢table1表中的數(shù)據(jù)了扩借。代碼如下所示:
Cursor cursor = getContentResolver()
.query(
uri,projection,selection,selectionArgs,sortOrder
);
query()方法接收的參數(shù)跟SQLiteDatabase中的query()方法接收的參數(shù)很像,但總體來(lái)說(shuō)這個(gè)稍微簡(jiǎn)單一些缤至,畢竟這是在訪問(wèn)其他程序中的數(shù)據(jù)潮罪,沒(méi)必要構(gòu)建復(fù)雜的查詢語(yǔ)句。下標(biāo)對(duì)內(nèi)容提供者中的query的接收的參數(shù)進(jìn)行了詳細(xì)的解釋:
查詢完成仍然會(huì)返回一個(gè)Cursor對(duì)象领斥,這時(shí)我們就可以將數(shù)據(jù)從Cursor對(duì)象中逐個(gè)讀取出來(lái)了嫉到。讀取的思路仍然是對(duì)這個(gè)Cursor對(duì)象進(jìn)行遍歷,然后一條一條的取出數(shù)據(jù)即可月洛,代碼如下:
if(cursor != null){//注意這里一定要進(jìn)行一次判空何恶,因?yàn)橛锌赡苣阋樵兊谋砀静淮嬖? while(cursor.moveToNext()){
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
}
增加,刪除膊存,修改
//增加數(shù)據(jù)
ContentValues values = new ContentValues();
values.put("Column1","text");
values.put("Column2","1");
getContextResolver.insert(uri,values);
//刪除數(shù)據(jù)
getContextResolver.delete(uri,"column2 = ?",new String[]{ "1" });
//更新數(shù)據(jù)
ContentValues values = new ContentValues();
values.put("Column1","改數(shù)據(jù)");
getContextResolver.update(uri,values,"column1 = 导而? and column2 = ?",new String[]{"text","1"});
3. 創(chuàng)建自己的內(nèi)容提供者
前面已經(jīng)提到過(guò)忱叭,如果要想實(shí)現(xiàn)跨程序共享數(shù)據(jù)的功能隔崎,官方推薦的方式就是使用內(nèi)容提供器今艺,可以新建一個(gè)類去繼承ContentProvider類的方式來(lái)創(chuàng)建一個(gè)自己的內(nèi)容提供器。ContentProvider類有6個(gè)抽象方法爵卒,我們?cè)谑褂米宇惱^承它的時(shí)候虚缎,需要將這6個(gè)方法全部重寫。新建MyProvider繼承字ContentProvider類钓株,代碼如下所示:
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}//查詢
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}//添加
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}//更新
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}//刪除
@Override
public String getType(Uri uri) {
return null;
}
}
onCreate()方法:
??初始化內(nèi)容提供器的時(shí)候調(diào)用实牡。通常會(huì)在這里完成對(duì)數(shù)據(jù)庫(kù)的創(chuàng)建和升級(jí)等操作。返回true表示內(nèi)容提供器初始化成功轴合,返回false則表示失敗创坞。注意,只有當(dāng)存在ContentResolver嘗試訪問(wèn)我們的程序中的數(shù)據(jù)時(shí)受葛,內(nèi)容提供器才會(huì)被初始化题涨。query()方法:
??從內(nèi)容提供器中查詢數(shù)據(jù)。使用uri參數(shù)來(lái)確定查詢的哪張表总滩,projection參數(shù)用于確定查詢的哪一列纲堵,selection和selectionArgs參數(shù)用于約束查詢哪些行,sortOrder參數(shù)用于對(duì)結(jié)果進(jìn)行排序闰渔,查詢的結(jié)果存放在Cursor對(duì)象中返回席函。insert()方法:
??向內(nèi)容提供器中添加一條數(shù)據(jù)。使用uri參數(shù)來(lái)確定要添加的表冈涧,待添加的數(shù)據(jù)保存在values參數(shù)中茂附。添加完成后,返回一個(gè)用于表示這條新紀(jì)錄的URI督弓。update()方法:
??更新內(nèi)容提供器中已有的數(shù)據(jù)营曼。使用uri參數(shù)來(lái)確定更新哪一張表中的數(shù)據(jù),新數(shù)據(jù)保存著values參數(shù)當(dāng)中咽筋,selection和selectionArgs參數(shù)用于約束更新哪些行溶推,受影響的行數(shù)將作為返回值返回。delete()方法:
??從內(nèi)容提供器中刪除數(shù)據(jù)奸攻。使用uri參數(shù)來(lái)確定刪除哪一張表中的數(shù)據(jù)蒜危,selection和selectionArgs參數(shù)用于約束刪除哪些行,被刪除的行數(shù)將作為返回值返回睹耐。getType()方法:
??根據(jù)傳入的內(nèi)容URI來(lái)返回相應(yīng)的MIME類型辐赞。