文章主要是講Android開發的四大組件,本文主要分爲html
文章源自:http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.htmlandroid
1、Activity詳解
2、Service詳解
3、Broadcast Receiver詳解
4、Content Provider詳解
外加一個重要組件 intent的詳解。
1、Activity詳解
Activty的生命週期的也就是它所在進程的生命週期。sql
一個Activity的啓動順序:
onCreate()——>onStart()——>onResume()
當另外一個Activity啓動時:
第一個Activity onPause()——>第二個Activity onCreate()——>onStart()——>onResume()
——>第一個Activity onStop()
當返回到第一個Activity時:
第二個Activity onPause() ——> 第一個Activity onRestart()——>onStart()——>onResume()
——>第二個Activity onStop()——>onDestroy()
一個Activity的銷燬順序:
(狀況一)onPause()——><Process Killed>
(狀況二)onPause()——>onStop()——><Process Killed>
(狀況三)onPause()——>onStop()——>onDestroy()
每個活動( Activity )都處於某一個狀態,對於開發者來講,是沒法控制其應用程序處於某一個狀態的,這些均由系統來完成。
可是當一個活動的狀態發生改變的時候,開發者能夠經過調用 onXX() 的方法獲取到相關的通知信息。
在實現 Activity 類的時候,經過覆蓋( override )這些方法便可在你須要處理的時候來調用。
數據庫
一個應用程序的優先級是受最高優先級的Activity影響的。當決定某個應用程序是否要終結去釋放資源,Android內存管理使用棧來決定基於Activity的應用程序的優先級。
Activity的加載模式受啓動Activity的Intent對象中設置的Flag和manifest文件中Activity的元素的特性值交互控制。
下面是影響加載模式的一些特性
核心的Intent Flag有:app
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
核心的特性有:異步
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
四種加載模式的區別
所屬task的區別
通常狀況下,「standard」和」singleTop」的activity的目標task,和收到的Intent的發送者在同一個task內,就至關於誰調用它,它就跟誰在同一個Task中。
除非Intent包括參數FLAG_ACTIVITY_NEW_TASK。若是提供了FLAG_ACTIVITY_NEW_TASK參數,會啓動到別的task裏。
「singleTask」和」singleInstance」 老是把要啓動的activity做爲一個task的根元素,他們不會被啓動到一個其餘task裏。
是否容許多個實例
「standard」和」singleTop」能夠被實例化屢次,而且是能夠存在於不一樣的task中;這種實例化時一個task能夠包括一個activity的多個實例;
「singleTask」和」singleInstance」則限制只生成一個實例,而且是task的根元素。
singleTop 要求若是建立intent的時候棧頂已經有要建立的Activity的實例,則將intent發送給該實例,而不建立新的實例。
是否容許其它activity存在於本task內
「singleInstance」獨佔一個task,其它activity不能存在那個task裏;
若是它啓動了一個新的activity,無論新的activity的launch mode 如何,新的activity都將會到別的task裏運行(如同加了FLAG_ACTIVITY_NEW_TASK參數)。
而另外三種模式,則能夠和其它activity共存。
是否每次都生成新實例
「standard」對於每個啓動Intent都會生成一個activity的新實例;
「singleTop」的activity若是在task的棧頂的話,則不生成新的該activity的實例,直接使用棧頂的實例,不然,生成該activity的實例。
好比:
如今task棧元素爲A-B-C-D(D在棧頂),這時候給D發一個啓動intent,若是D是 「standard」的,則生成D的一個新實例,棧變爲A-B-C-D-D。
若是D是singleTop的話,則不會生產D的新實例,棧狀態仍爲A-B-C-D
若是這時候給B發Intent的話,無論B的launchmode是」standard」 仍是 「singleTop」 ,都會生成B的新實例,棧狀態變爲A-B-C-D-B。
「singleInstance」是其所在棧的惟一activity,它會每次都被重用。
「singleTask」 若是在棧頂,則接受intent,不然,該intent會被丟棄,可是該task仍會回到前臺。 當已經存在的activity實例處理新的intent時候,會調用onNewIntent()方法,若是收到intent生成一個activity實例,那麼用戶能夠經過back鍵回到上一個狀態;若是是已經存在的一個activity來處理這個intent的話,用戶不能經過按back鍵返回到這以前的狀態。
-----------------------------------
2、Service詳解
service能夠在和多場合的應用中使用,好比播放多媒體的時候用戶啓動了其餘Activity這個時候程序要在後臺繼續播放,好比檢測SD卡上文件的變化,再或者在後臺記錄你地理信息位置的改變等等,總之服務嘛,老是藏在後頭的。
Service是在一段不定的時間運行在後臺,不和用戶交互應用組件。每一個Service必須在manifest中 經過<service>來聲明。能夠經過contect.startservice和contect.bindserverice來啓動。
Service和其餘的應用組件同樣,運行在進程的主線程中。這就是說若是service須要不少耗時或者阻塞的操做,須要在其子線程中實現。
service的兩種模式(startService()/bindService()不是徹底分離的):
ide
本地服務 Local Service 用於應用程序內部。
它能夠啓動並運行,直至有人中止了它或它本身中止。在這種方式下,它以調用Context.startService()啓動,而以調用Context.stopService()結束。它能夠調用Service.stopSelf() 或 Service.stopSelfResult()來本身中止。不論調用了多少次startService()方法,你只須要調用一次stopService()來中止服務。
用於實現應用程序本身的一些耗時任務,好比查詢升級信息,並不佔用應用程序好比Activity所屬線程,而是單開線程後臺執行,這樣用戶體驗比較好。
遠程服務 Remote Service 用於android系統內部的應用程序之間。
它能夠經過本身定義並暴露出來的接口進行程序操做。客戶端創建一個到服務對象的鏈接,並經過那個鏈接來調用服務。鏈接以調用Context.bindService()方法創建,以調用 Context.unbindService()關閉。多個客戶端能夠綁定至同一個服務。若是服務此時尚未加載,bindService()會先加載它。
可被其餘應用程序複用,好比天氣預報服務,其餘應用程序不須要再寫這樣的服務,調用已有的便可。
使用context.startService() 啓動Service是會會經歷:
context.startService() ->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop
若是Service尚未運行,則android先調用onCreate()而後調用onStart();若是Service已經運行,則只調用onStart(),因此一個Service的onStart方法可能會重複調用屢次。
stopService的時候直接onDestroy,若是是調用者本身直接退出而沒有調用stopService的話,Service會一直在後臺運行。該Service的調用者再啓動起來後能夠經過stopService關閉Service。
因此調用startService的生命週期爲:onCreate --> onStart(可屢次調用) --> onDestroy
使用使用context.bindService()啓動Service會經歷:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
onBind將返回給客戶端一個IBind接口實例,IBind容許客戶端回調服務的方法,好比獲得Service運行的狀態或其餘操做。這個時候把調用者(Context,例如Activity)會和Service綁定在一塊兒,Context退出了,Srevice就會調用onUnbind->onDestroy相應退出。
因此調用bindService的生命週期爲:onCreate --> onBind(只一次,不可屢次綁定) --> onUnbind --> onDestory。
在Service每一次的開啓關閉過程當中,只有onStart可被屢次調用(經過屢次startService調用),其餘onCreate,onBind,onUnbind,onDestory在一個生命週期中只能被調用一次。
而啓動service,根據onStartCommand的返回值不一樣,有兩個附加的模式:
1. START_STICKY 用於顯示啓動和中止service。
2. START_NOT_STICKY或START_REDELIVER_INTENT用於有命令須要處理時才運行的模式。
服務不能本身運行,須要經過調用Context.startService()或Context.bindService()方法啓動服務。這兩個方法均可以啓動Service,可是它們的使用場合有所不一樣。
1. 使用startService()方法啓用服務,調用者與服務之間沒有關連,即便調用者退出了,服務仍然運行。
若是打算採用Context.startService()方法啓動服務,在服務未被建立時,系統會先調用服務的onCreate()方法,接着調用onStart()方法。
若是調用startService()方法前服務已經被建立,屢次調用startService()方法並不會致使屢次建立服務,但會致使屢次調用onStart()方法。
採用startService()方法啓動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
2. 使用bindService()方法啓用服務,調用者與服務綁定在了一塊兒,調用者一旦退出,服務也就終止,大有「不求同時生,必須同時死」的特色。
onBind()只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,屢次調用Context.bindService()方法並不會致使該方法被屢次調用。
採用Context.bindService()方法啓動服務時只能調用onUnbind()方法解除調用者與服務解除,服務結束時會調用onDestroy()方法。
看看官方給出的比較流程示意圖:
官方文檔告訴咱們,一個service能夠同時start而且bind,在這樣的狀況,系統會一直保持service的運行狀態若是service已經start了或者BIND_AUTO_CREATE標誌被設置。若是沒有一個條件知足,那麼系統將會調用onDestory方法來終止service.全部的清理工做(終止線程,反註冊接收器)都在onDestory中完成。
擁有service的進程具備較高的優先級
官方文檔告訴咱們,Android系統會盡可能保持擁有service的進程運行,只要在該service已經被啓動(start)或者客戶端鏈接(bindService)到它。當內存不足時,須要保持,擁有service的進程具備較高的優先級。
1. 若是service正在調用onCreate,onStartCommand或者onDestory方法,那麼用於當前service的進程則變爲前臺進程以免被killed。
2. 若是當前service已經被啓動(start),擁有它的進程則比那些用戶可見的進程優先級低一些,可是比那些不可見的進程更重要,這就意味着service通常不會被killed.
3. 若是客戶端已經鏈接到service (bindService),那麼擁有Service的進程則擁有最高的優先級,能夠認爲service是可見的。
4. 若是service可使用startForeground(int, Notification)方法來將service設置爲前臺狀態,那麼系統就認爲是對用戶可見的,並不會在內存不足時killed。
若是有其餘的應用組件做爲Service,Activity等運行在相同的進程中,那麼將會增長該進程的重要性。
本地service
1.不需和Activity交互的本地服務函數
public class LocalService extends Service { private static final String TAG = "LocalService"; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return null; } @Override public void onCreate() { Log.i(TAG, "onCreate"); super.onCreate(); } @Override public void onDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); } @Override public void onStart(Intent intent, int startId) { Log.i(TAG, "onStart"); super.onStart(intent, startId); } }
Activity:ui
public class ServiceActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.servicedemo); ((Button) findViewById(R.id.startLocalService)).setOnClickListener( new View.OnClickListener(){ @Override public void onClick(View view) { // TODO Auto-generated method stub startService(new Intent("com.demo.SERVICE_DEMO")); } }); ((Button) findViewById(R.id.stopLocalService)).setOnClickListener( new View.OnClickListener(){ @Override public void onClick(View view) { // TODO Auto-generated method stub stopService(new Intent("com.demo.SERVICE_DEMO")); } }); } }
在AndroidManifest.xml添加:this
<service android:name=".LocalService"> <intent-filter> <action android:name="com.demo.SERVICE_DEMO" /> <category android:name="android.intent.category.default" /> </intent-filter> </service>
不然啓動服務時會提示new Intent找不到"com.demo.SERVICE_DEMO"。
對於這類不需和Activity交互的本地服務,是使用startService/stopService的最好例子。
運行時能夠發現第一次startService時,會調用onCreate和onStart,在沒有stopService前,不管點擊多少次startService,都只會調用onStart。而stopService時調用onDestroy。再次點擊stopService,會發現不會進入service的生命週期的,即不會再調用onCreate,onStart和onDestroy。
而onBind在startService/stopService中沒有調用。
2.本地服務和Activity交互
對於這種case,官方的sample(APIDemo\app.LocalService)是最好的例子:
/** * This is an example of implementing an application service that runs locally * in the same process as the application. The {@link LocalServiceController} * and {@link LocalServiceBinding} classes show how to interact with the * service. * * <p>Notice the use of the {@link NotificationManager} when interesting things * happen in the service. This is generally how background services should * interact with the user, rather than doing something more disruptive such as * calling startActivity(). */ public class LocalService extends Service { private NotificationManager mNM; /** * Class for clients to access. Because we know this service always * runs in the same process as its clients, we don't need to deal with * IPC. */ public class LocalBinder extends Binder { LocalService getService() { return LocalService.this; } } @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. We put an icon in the status bar. showNotification(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("LocalService", "Received start id " + startId + ": " + intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; } @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.local_service_started); // Tell the user we stopped. Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); } @Override public IBinder onBind(Intent intent) { return mBinder; } // This is the object that receives interactions from clients. See // RemoteService for a more complete example. private final IBinder mBinder = new LocalBinder(); /** * Show a notification while this service is running. */ private void showNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.local_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceController.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent); // Send the notification. // We use a layout id because it is a unique number. We use it later to cancel. mNM.notify(R.string.local_service_started, notification); } }
這裏能夠發現onBind須要返回一個IBinder對象。也就是說和上一例子LocalService不一樣的是,
1. 添加了一個public內部類繼承Binder,並添加getService方法來返回當前的Service對象;
2. 新建一個IBinder對象--new那個Binder內部類;
3. onBind方法返還那個IBinder對象。
Activity:
/** * <p>Example of binding and unbinding to the {@link LocalService}. * This demonstrates the implementation of a service which the client will * bind to, receiving an object through which it can communicate with the service.</p> */ public class LocalServiceBinding extends Activity { private boolean mIsBound; private LocalService mBoundService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.local_service_binding); // Watch for button clicks. Button button = (Button)findViewById(R.id.bind); button.setOnClickListener(mBindListener); button = (Button)findViewById(R.id.unbind); button.setOnClickListener(mUnbindListener); } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. mBoundService = ((LocalService.LocalBinder)service).getService(); // Tell the user about this for our demo. Toast.makeText(LocalServiceBinding.this, R.string.local_service_connected, Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. mBoundService = null; Toast.makeText(LocalServiceBinding.this, R.string.local_service_disconnected, Toast.LENGTH_SHORT).show(); } }; private OnClickListener mBindListener = new OnClickListener() { public void onClick(View v) { // Establish a connection with the service. We use an explicit // class name because we want a specific service implementation that // we know will be running in our own process (and thus won't be // supporting component replacement by other applications). bindService(new Intent(LocalServiceBinding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } }; private OnClickListener mUnbindListener = new OnClickListener() { public void onClick(View v) { if (mIsBound) { // Detach our existing connection. unbindService(mConnection); mIsBound = false; } } }; }
明顯看出這裏面添加了一個名爲ServiceConnection類,並實現了onServiceConnected(從IBinder獲取Service對象)和onServiceDisconnected(set Service to null)。
而bindService和unbindService方法都是操做這個ServiceConnection對象的。
AndroidManifest.xml裏添加:
這裏沒什麼特別的,由於service沒有須要什麼特別的action,因此只是聲明service而已,而activity和普通的沒差異。
運行時,發現調用次序是這樣的:
bindService:
1.LocalService : onCreate
2.LocalService : onBind
3.Activity: onServiceConnected
unbindService: 只是調用onDestroy
可見,onStart是不會被調用的,而onServiceDisconnected沒有調用的緣由在上面代碼的註釋有說明。
------------------------
3、Broadcast Receiver詳解
BroadcastReceiver 用於異步接收廣播Intent。主要有兩大類,用於接收廣播的:
·正常廣播 Normal broadcasts(用 Context.sendBroadcast()發送)是徹底異步的。它們都運行在一個未定義的順序,一般是在同一時間。這樣會更有效,但意味着receiver不能包含所要使用的結果或停止的API。
·有序廣播 Ordered broadcasts(用 Context.sendOrderedBroadcast()發送)每次被髮送到一個receiver。所謂有序,就是每一個receiver執行後能夠傳播到下一個receiver,也能夠徹底停止傳播--不傳播給其餘receiver。 而receiver運行的順序能夠經過matched intent-filter 裏面的android:priority來控制,當priority優先級相同的時候,Receiver以任意的順序運行。
要注意的是,即便是Normal broadcasts,系統在某些狀況下可能會恢復到一次傳播給一個receiver。 特別是receiver可能須要建立一個進程,爲了不繫統超載,只能一次運行一個receiver。
Broadcast Receiver 並無提供可視化的界面來顯示廣播信息。可使用Notification和Notification Manager來實現可視化的信息的界面,顯示廣播信息的內容,圖標及震動信息。
生命週期
一個BroadcastReceiver 對象只有在被調用onReceive(Context, Intent)的纔有效的,當從該函數返回後,該對象就無效的了,結束生命週期。
所以從這個特徵能夠看出,在所調用的onReceive(Context, Intent)函數裏,不能有過於耗時的操做,不能使用線程來執行。對於耗時的操做,請start service來完成。由於當獲得其餘異步操做所返回的結果時,BroadcastReceiver 可能已經無效了。
發送廣播
事件的廣播比較簡單,構建Intent對象,可調用sendBroadcast(Intent)方法將廣播發出。另外還有sendOrderedBroadcast(),sendStickyBroadcast()等方法,請查閱API Doc。
1.new Intent with action name
Intent intent = new Intent(String action);
或者 只是new Intent, 而後
intent.setAction(String action);
2.set data等準備好了後,in activity,
sendBroadcast(Intent); // 發送廣播
接收廣播
經過定義一個繼承BroadcastReceiver類來實現,繼承該類後覆蓋其onReceiver方法,並在該方法中響應事件。
public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // get data from SMS intent Bundle bundle = intent.getExtras(); if (bundle != null){ // get message by "pdus" Object[] objArray = (Object[]) bundle.get("pdus"); // rebuild SMS SmsMessage[] messages = new SmsMessage[objArray.length]; for (int i=0; i < objArray.length; i++){ messages[i] = SmsMessage.createFromPdu((byte[])objArray[i]); StringBuilder str = new StringBuilder("from: "); str.append(messages[i].getDisplayOriginatingAddress()); str.append("\nmessage:\n"); str.append(messages[i].getDisplayMessageBody()); Toast.makeText(context, str.toString(), Toast.LENGTH_LONG) .show(); } } } }
複製代碼
註冊Receiver
註冊有兩種方式:
1. 靜態方式,在AndroidManifest.xml的application裏面定義receiver並設置要接收的action。
<receiver android:name=".SMSReceiver"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
2. 動態方式, 在activity裏面調用函數來註冊,和靜態的內容差很少。一個形參是receiver,另外一個是IntentFilter,其中裏面是要接收的action。
public class HelloDemo extends Activity { private BroadcastReceiver receiver; @Override protected void onStart() { super.onStart(); receiver = new CallReceiver(); registerReceiver(receiver, new IntentFilter("android.intent.action.PHONE_STATE")); } @Override protected void onStop() { unregisterReceiver(receiver); super.onStop(); } }
一個receiver能夠接收多個action的,便可以有多個intent-filter,須要在onReceive裏面對intent.getAction(action name)進行判斷。
我的推薦使用靜態註冊方式,由系統來管理receiver,並且程序裏的全部receiver,能夠在xml裏面一目瞭然。而動態註冊方式,隱藏在代碼中,比較難發現。
並且動態註冊,須要特別注意的是,在退出程序前要記得調用Context.unregisterReceiver()方法。通常在activity的onStart()裏面進行註冊, onStop()裏面進行註銷。官方提醒,若是在Activity.onResume()裏面註冊了,就必須在Activity.onPause()註銷。
Permission權限
要接收某些action,須要在AndroidManifest.xml裏面添加相應的permission。例如接收SMS:
下面給出動態註冊的接收來電的廣播處理的CallReceiver的代碼:
一種方式是直接讀取intent.getStringExtra("incoming_number")來獲取來電號碼:
public class CallReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); switch(teleManager.getCallState()){ case TelephonyManager.CALL_STATE_RINGING: //響鈴 Toast.makeText(context, "Ringing: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show(); break; case TelephonyManager.CALL_STATE_OFFHOOK: //接聽 Toast.makeText(context, "OffHook: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show(); break; case TelephonyManager.CALL_STATE_IDLE: //掛斷 Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG).show(); break; } } }
在運行時,發現除了響鈴時能夠獲取來電號碼,接聽和掛斷都不能成功獲取的,顯示爲null。
另外一種方式是經過PhoneStateListener的onCallStateChanged來監聽狀態的變化:
public class CallReceiver extends BroadcastReceiver { private Context m_context; @Override public void onReceive(Context context, Intent intent) { m_context = context; TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); teleManager.listen(new PhoneStateListener(){ @Override public void onCallStateChanged(int state, String incomingNumber) { switch(state){ case TelephonyManager.CALL_STATE_RINGING: //響鈴 Toast.makeText(m_context, "Ringing: " + incomingNumber, Toast.LENGTH_LONG) .show(); break; case TelephonyManager.CALL_STATE_OFFHOOK: //接聽 Toast.makeText(m_context, "OffHook: " + incomingNumber, Toast.LENGTH_LONG) .show(); break; case TelephonyManager.CALL_STATE_IDLE: //掛斷 Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG) .show(); break; } }}, PhoneStateListener.LISTEN_CALL_STATE); } }
運行時也發現incomingNumber在接聽和掛斷時獲取爲blank。
由於這裏監聽的是通話的狀態變化,因此這個receiver會被調用3次。
監聽通話狀態須要加上權限:
===========
小結:
1. 對於sendBroadCast的intent對象,須要設置其action name;
2. 推薦使用顯式指明receiver,在配置文件AndroidManifest.xml指明;
3. 一個receiver能夠接收多個action;
4. 每次接收廣播都會從新生成一個接收廣播的對象,再次調用onReceive;
5. 在BroadCast 中儘可能不要處理太多邏輯問題,建議複雜的邏輯交給Activity 或者 Service 去處理。
--------------------------------------------
4、Content Provider詳解
ContentProvider(內容提供者)是Android中的四大組件之一。主要用於對外共享數據,也就是經過ContentProvider把應用中的數據共享給其餘應用訪問,其餘應用能夠經過ContentProvider對指定應用中的數據進行操做。ContentProvider分爲系統的和自定義的,系統的也就是例如聯繫人,圖片等數據。
android中對數據操做包含有:
file, sqlite3, Preferences, ContectResolver與ContentProvider前三種數據操做方式都只是針對本應用內數據,程序不能經過這三種方法去操道別的應用內的數據。
android中提供ContectResolver與ContentProvider來操道別的應用程序的數據。
使用方式:
一個應用實現ContentProvider來提供內容給別的應用來操做,
一個應用經過ContentResolver來操道別的應用數據,固然在本身的應用中也能夠。
如下這段是Google Doc中對ContentProvider的大體概述:
內容提供者將一些特定的應用程序數據供給其它應用程序使用。內容提供者繼承於ContentProvider 基類,爲其它應用程序取用和存儲它管理的數據實現了一套標準方法。然而,應用程序並不直接調用這些方法,而是使用一個 ContentResolver 對象,調用它的方法做爲替代。ContentResolver能夠與任意內容提供者進行會話,與其合做來對全部相關交互通信進行管理。
1.ContentProvider
Android提供了一些主要數據類型的ContentProvider,好比音頻、視頻、圖片和私人通信錄等。可在android.provider包下面找到一些Android提供的ContentProvider。經過得到這些ContentProvider能夠查詢它們包含的數據,固然前提是已得到適當的讀取權限。
主要方法:
public boolean onCreate() 在建立ContentProvider時調用
public Cursor query(Uri, String[], String, String[], String) 用於查詢指定Uri的ContentProvider,返回一個Cursor
public Uri insert(Uri, ContentValues) 用於添加數據到指定Uri的ContentProvider中
public int update(Uri, ContentValues, String, String[]) 用於更新指定Uri的ContentProvider中的數據
public int delete(Uri, String, String[]) 用於從指定Uri的ContentProvider中刪除數據
public String getType(Uri) 用於返回指定的Uri中的數據的MIME類型
*若是操做的數據屬於集合類型,那麼MIME類型字符串應該以vnd.android.cursor.dir/開頭。
例如:要獲得全部person記錄的Uri爲content://contacts/person,那麼返回的MIME類型字符串爲"vnd.android.cursor.dir/person"。
*若是要操做的數據屬於非集合類型數據,那麼MIME類型字符串應該以vnd.android.cursor.item/開頭。
例如:要獲得id爲10的person記錄的Uri爲content://contacts/person/10,那麼返回的MIME類型字符串應爲"vnd.android.cursor.item/person"。
2.ContentResolver
當外部應用須要對ContentProvider中的數據進行添加、刪除、修改和查詢操做時,可使用ContentResolver類來完成,要獲取ContentResolver對象,可使用Context提供的getContentResolver()方法。
ContentResolver cr = getContentResolver();
ContentResolver提供的方法和ContentProvider提供的方法對應的有如下幾個方法。
public Uri insert(Uri uri, ContentValues values) 用於添加數據到指定Uri的ContentProvider中。
public int delete(Uri uri, String selection, String[] selectionArgs) 用於從指定Uri的ContentProvider中刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用於更新指定Uri的ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用於查詢指定Uri的ContentProvider。
3.Uri
Uri指定了將要操做的ContentProvider,其實能夠把一個Uri看做是一個網址,咱們把Uri分爲三部分。
第一部分是"content://"。能夠看做是網址中的"http://"。
第二部分是主機名或authority,用於惟一標識這個ContentProvider,外部應用須要根據這個標識來找到它。能夠看做是網址中的主機名,好比"blog.csdn.net"。
第三部分是路徑名,用來表示將要操做的數據。能夠看做網址中細分的內容路徑。
---------------------------------