轉載於:http://blog.csdn.net/byxdaz/article/details/9708491
http://blog.csdn.net/q876266464/article/details/19641251
Android四大基本組件分別是Activity,Service服務,Content Provider內容提供者,Broadcast Receiver廣播接收器。
一、了解四大基本組件
Activity :
應用程序中,一個Activity通常就是一個單獨的屏幕,它上面可以顯示一些控件也可以監聽並處理用戶的事件做出響應。
Activity之間通過Intent進行通信。在Intent 的描述結構中,有兩個最重要的部分:動作和動作對應的數據。
典型的動作類型有:MAIN(activity的門戶)、VIEW、PICK、EDIT 等。而動作對應的數據則以URI 的形式進行表示。例如:要查看一個人的聯系方式,你需要創建一個動作類型為VIEW 的intent,以及一個表示這個人的URI。
與之有關系的一個類叫IntentFilter。相對於intent 是一個有效的做某事的請求,一個intentfilter 則用於描述一個activity(或者IntentReceiver)能夠操作哪些intent。一個activity 如果要顯示一個人的聯系方式時,需要聲明一個IntentFilter,這個IntentFilter 要知道怎么去處理VIEW 動作和表示一個人的URI。IntentFilter 需要在AndroidManifest.xml 中定義。通過解析各種intent,從一個屏幕導航到另一個屏幕是很簡單的。當向前導航時,activity將會調用startActivity(Intent myIntent)方法。然后,系統會在所有安裝的應用程序中定義的IntentFilter中查找,找到最匹配myIntent 的Intent 對應的activity。新的activity 接收到myIntent 的通知后,開始運行。當startActivity 方法被調用將觸發解析myIntent 的動作,這個機制提供了兩個關鍵好處:
A、Activities 能夠重復利用從其它組件中以Intent 的形式產生的一個請求;
B、Activities 可以在任何時候被一個具有相同IntentFilter 的新的Activity取代。
AndroidManifest文件中含有如下過濾器的Activity組件為默認啟動類當程序啟動時系統自動調用它:
<intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter>
BroadcastReceive廣播接收器:
你的應用可以使用它對外部事件進行過濾只對感興趣的外部事件(如當電話呼入時,或者數據網絡可用時)進行接收並做出響應。廣播接收器沒有用戶界面。然而,它們可以啟動一個activity或serice 來響應它們收到的信息,或者用NotificationManager 來通知用戶。通知可以用很多種方式來吸引用戶的注意力——閃動背燈、震動、播放聲音等。一般來說是在狀態欄上放一個持久的圖標,用戶可以打開它並獲取消息。
廣播類型:
- 普通廣播,通過Context.sendBroadcast(Intent myIntent)發送的
- 有序廣播,通過Context.sendOrderedBroadcast(intent, receiverPermission)發送的,該方法第2個參數決定該廣播的級別,級別數值是在 -1000 到 1000 之間 , 值越大 , 發送的優先級越高;廣播接收者接收廣播時的級別級別(可通過intentfilter中的priority進行設置設為2147483647時優先級最高),同級別接收的先后是隨機的,再到級別低的收到廣播,高級別的或同級別先接收到廣播的可以通過abortBroadcast()方法截斷廣播使其他的接收者無法收到該廣播,還有其他構造函數
- 異步廣播,通過Context.sendStickyBroadcast(IntentmyIntent)發送的,還有sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode,initialData, initialExtras)方法,該方法具有有序廣播的特性也有異步廣播的特性;發送異步廣播要: <uses-permission android:name="android.permission.BROADCAST_STICKY" />權限,接收並處理完Intent后,廣播依然存在,直到你調用removeStickyBroadcast(intent)主動把它去掉
注意:發送廣播時的intent參數與Contex.startActivity()啟動起來的Intent不同,前者可以被多個訂閱它的廣播接收器調用,后者只能被一個(Activity或service)調用
監聽廣播Intent步驟:
1> 寫一個繼承BroadCastReceiver的類,重寫onReceive()方法,廣播接收器僅在它執行這個方法時處於活躍狀態。當onReceive()返回后,它即為失活狀態,注意:為了保證用戶交互過程的流暢,一些費時的操作要放到線程里,如類名SMSBroadcastReceiver
2> 注冊該廣播接收者,注冊有兩種方法程序動態注冊和AndroidManifest文件中進行靜態注冊(可理解為系統中注冊)如下:
靜態注冊,注冊的廣播,下面的priority表示接收廣播的級別"2147483647"為最高優先級
<receiver android:name=".SMSBroadcastReceiver"> <intent-filter android:priority= "2147483647"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver >
動態注冊,一般在Activity可交互時onResume()內注冊BroadcastReceiver:
IntentFilter intentFilter=newIntentFilter("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(mBatteryInfoReceiver,intentFilter); //反注冊 unregisterReceiver(receiver);
注意:
1.生命周期只有十秒左右,如果在 onReceive() 內做超過十秒內的事情,就會報ANR(Application No Response) 程序無響應的錯誤信息,如果需要完成一項比較耗時的工作 , 應該通過發送 Intent 給 Service, 由Service 來完成 . 這里不能使用子線程來解決 , 因為 BroadcastReceiver的生命周期很短 , 子線程可能還沒有結束BroadcastReceiver 就先結束了 .BroadcastReceiver 一旦結束 , 此時 BroadcastReceiver 的所在進程很容易在系統需要內存時被優先殺死 , 因為它屬於空進程 ( 沒有任何活動組件的進程 ). 如果它的宿主進程被殺死 , 那么正在工作的子線程也會被殺死 . 所以采用子線程來解決是不可靠的
2. 動態注冊廣播接收器還有一個特點,就是當用來注冊的Activity關掉后,廣播也就失效了。靜態注冊無需擔憂廣播接收器是否被關閉,只要設備是開啟狀態,廣播接收器也是打開着的。也就是說哪怕app本身未啟動,該app訂閱的廣播在觸發時也會對它起作用
系統常見廣播Intent,如開機啟動、電池電量變化、時間改變等廣播。
Service 服務:
一個Service 是一段長生命周期的,沒有用戶界面的程序,可以用來開發如監控類程序。
比較好的一個例子就是一個正在從播放列表中播放歌曲的媒體播放器。在一個媒體播放器的應用中,應該會有多個activity,讓使用者可以選擇歌曲並播放歌曲。然而,音樂重放這個功能並沒有對應的activity,因為使用者當然會認為在導航到其它屏幕時音樂應該還在播放的。在這個例子中,媒體播放器這個activity 會使用Context.startService()來啟動一個service,從而可以在后台保持音樂的播放。同時,系統也將保持這個service 一直執行,直到這個service 運行結束。另外,我們還可以通過使用Context.bindService()方法,連接到一個service 上(如果這個service 還沒有運行將啟動它)。當連接到一個service 之后,我們還可以service 提供的接口與它進行通訊。拿媒體播放器這個例子來說,我們還可以進行暫停、重播等操作。
Service使用步驟如下
1>繼承service類
2>AndroidManifast.xml配置清單文件中<application>節點里對服務進行配置
<servicename=".SMSService"/>
服務不能自己運行,需要通過Contex.startService()或Contex.bindService()啟動服務
通過startService()方法啟動的服務於調用者沒有關系,即使調用者關閉了,服務仍然運行想停止服務要調用Context.stopService(),此時系統會調用onDestory(),使用此方法啟動時,服務首次啟動系統先調用服務的onCreate()-->onStart(),如果服務已經啟動再次調用只會觸發onStart()方法
使用bindService()啟動的服務與調用者綁定,只要調用者關閉服務就終止,使用此方法啟動時,服務首次啟動系統先調用服務的onCreate()-->onBind(),如果服務已經啟動再次調用不會再觸發這2個方法,調用者退出時系統會調用服務的onUnbind()-->onDestory(),想主動解除綁定可使用Contex.unbindService(),系統依次調用onUnbind()-->onDestory();
Content Provider內容提供者 :
android平台提供了Content Provider使一個應用程序的指定數據集提供給其他應用程序。這些數據可以存儲在文件系統中、在一個SQLite數據庫、或以任何其他合理的方式,
其他應用可以通過ContentResolver類(見ContentProviderAccessApp例子)從該內容提供者中獲取或存入數據.(相當於在應用外包了一層殼),
只有需要在多個應用程序間共享數據是才需要內容提供者。例如,通訊錄數據被多個應用程序使用,且必須存儲在一個內容提供者中
它的好處:統一數據訪問方式。
android系統自帶的內容提供者(頂級的表示數據庫名,非頂級的都是表名)這些內容提供者在SDK文檔的android.provider Java包中都有介紹。見:http://developer.android.com/reference/android/provider/package-summary.html
├————Browser
├————CallLog
├————Contacts
│ ├————Groups
│ ├————People
│ ├————Phones
│ └————Photos
├————Images
│ └————Thumbnails
├————MediaStore
│ ├————Albums
│ ├————Artists
│ ├————Audio
│ ├————Genres
│ └————Playlists
├————Settings
└————Video
CallLog:地址和接收到的電話信息
Contact.People.Phones:存儲電話號碼
Setting.System:系統設置和偏好設置
使用Content Provider對外共享數據的步驟
1>繼承ContentProvider類並根據需求重寫以下方法:
publicboolean onCreate();//處理初始化操作 /** * 插入數據到內容提供者(允許其他應用向你的應用中插入數據時重寫) * @param uri * @param initialValues 插入的數據 * @return */ public Uri insert(Uri uri, ContentValuesinitialValues); /** * 從內容提供者中刪除數據(允許其他應用刪除你應用的數據時重寫) * @param uri * @param selection 條件語句 * @param selectionArgs 參數 * @return */ publicint delete(Uri uri, String selection, String[]selectionArgs); /** * 更新內容提供者已存在的數據(允許其他應用更新你應用的數據時重寫) * @param uri * @param values 更新的數據 * @param selection 條件語句 * @param selectionArgs 參數 * @return */ publicint update(Uri uri, ContentValues values, String selection, String[] selectionArgs); /** * 返回數據給調用者(允許其他應用從你的應用中獲取數據時重寫) * @param uri * @param projection 列名 * @param selection 條件語句 * @param selectionArgs 參數 * @param sortOrder 排序 * @return */ public Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs,String sortOrder) ; /** * 用於返回當前Uri所代表數據的MIME類型 *如果操作的數據為集合類型(多條數據),那么返回的類型字符串應該為vnd.android.cursor.dir/開頭 * 例如要得到所有person記錄的Uri為content://com.bravestarr.provider.personprovider/person, * 那么返回的MIME類型字符串應該為"vnd.android.cursor.dir/person" * 如果操作的數據為單一數據,那么返回的類型字符串應該為vnd.android.cursor.item/開頭 * 例如要得到id為10的person記錄的Uri為content://com.bravestarr.provider.personprovider/person/10, * 那么返回的MIME類型字符串應該為"vnd.android.cursor.item/person" * @param uri */ public String getType(Uri uri)