標籤:super 後退 intent 四種 boolean png ext.get nes 解釋
以前一直是在各大網站,論壇上面看各種技術點和知識點,都是需要用什麼技術點,就去找相關的文章,從來沒有自己動手寫過;
從今天開始,我為自己定下一個目標,將andorid中用到的技術點和知識點都一條條的寫下來,方便自己以後在工作中遇到類似問題,能快速的找到解決方案------此貼均會有很多知識內容為摘錄整理,和博主自己的一些理解和看法,僅供參考,有錯誤的地方歡迎大神指點。
直入主題,說到android就不得說android的四大組件
andorid中的四大組件
1.Activity (不解釋)
2.Service (服務)
3.Broadcast Receiver (廣播接收者)
4.Content Provider (內容提供者)
一、Activity基礎介紹
首先貼上一張Activity的生命週期圖(圖片來至百度)
1.啟動Activity:系統會先調用onCreate(建立)方法,然後調用onStart(啟動)方法,最後調用onResume(使用者可操作)。
2.當前Activity被其他Activity覆蓋其上或被鎖屏:系統會調用onPause方法,暫停當前Activity的執行。
3.當前Activity由被覆蓋狀態回到前台或解鎖屏:系統會調用onResume方法,再次進入運行狀態。
4.當前Activity轉到新的Activity介面或按Home鍵回到主屏,自身退居後台:系統會先調用onPause方法,然後調用onStop方法,進入停滯狀態。
5.使用者後退回到此Activity:系統會先調用onRestart方法,然後調用onStart方法,最後調用onResume方法,再次進入運行狀態。
6.當前Activity處於被覆蓋狀態或者後台不可見狀態,即第2步和第4步,系統記憶體不足,殺死當前Activity,而後使用者退回當前Activity:再次調用onCreate方法、onStart方法、onResume方法,進入運行狀態。
7.使用者退出當前Activity:系統先調用onPause方法,然後調用onStop方法,最後調用onDestory方法,結束當前Activity。
此為Activity最基礎的生命週期介紹,後續還會單獨寫一篇Activity 的詳解 介紹四種啟動模式,以及各種菜單設定
----------------------------------------------------
二 、Service
Service是運行在後台,不和使用者互動應用組件。每個Service必須在manifest中 通過<service>來聲明。可以通過contect.startservice和contect.bindserverice來啟動。
Service可以在和多場合的應用中使用,比如播放多媒體的時候使用者啟動了其他Activity這個時候程式要在後台繼續播放,比如檢測SD卡上檔案的變化,再或者在後台記錄你地理資訊位置的改變等等,總之服務嘛,總是藏在後頭的。
Service和其他的應用組件一樣,運行在進程的主線程中。這就是說如果service需要很多耗時或者阻塞的操作,需要在其子線程中實現。
Service的兩種模式(startService()/bindService()不是完全分離的)
本地服務 Local Service 用於應用程式內部。
它可以啟動並運行,直至有人停止了它或它自己停止。在這種方式下,它以調用Context.startService()啟動,而以調用Context.stopService()結束。它可以調用Service.stopSelf() 或 Service.stopSelfResult()來自己停止。不論調用了多少次startService()方法,你只需要調用一次stopService()來停止服務。
用於實現應用程式自己的一些耗時任務,比如查詢升級資訊,並不佔用應用程式比如Activity所屬線程,而是單開線程後台執行,這樣使用者體驗比較好。
遠程服務 Remote Service 用於android系統內部的應用程式之間。
它可以通過自己定義並暴露出來的介面進行程式操作。用戶端建立一個到服務物件的串連,並通過那個串連來調用服務。串連以調用Context.bindService()方法建立,以調用 Context.unbindService()關閉。多個用戶端可以綁定至同一個服務。如果服務此時還沒有載入,bindService()會先載入它。
可被其他應用程式複用,比如天氣預報服務,其他應用程式不需要再寫這樣的服務,調用已有的即可。
三 、Broadcast Receiver BroadcastReceiver 廣播接收者,主要用於非同步接收廣播 ·正常廣播 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:
- <uses-permission android:name="android.permission.RECEIVE_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次。
監聽通話狀態需要加上許可權:
- <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
複製代碼 ===========
小結:
1. 對於sendBroadCast的intent對象,需要設定其action name;
2. 推薦使用顯式指明receiver,在設定檔AndroidManifest.xml指明;
3. 一個receiver可以接收多個action;
4. 每次接收廣播都會重建一個接收廣播的對象,再次調用onReceive;
5. 在BroadCast 中盡量不要處理太多邏輯問題,建議複雜的邏輯交給Activity 或者 Service 去處理。
--------------------------------------------
四、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"。
第三部分是路徑名,用來表示將要操作的資料。可以看作網址中細分的內容路徑。
---------------------------------
Android 基礎-給有java基礎的初學者(四大組件)