Android四大組件【轉】

Android四大組件 --- Activity

Activity生命周期

生命周期:onCreate() -> onStart() - > onResume() -> onPause() -> onStop() -> onDestroy()

Paste_Image.png
  • 啟動activity:系統(tǒng)先調(diào)用onCreate(),然后調(diào)用onStart(),最后調(diào)用onResume()方法,activity進入運行狀態(tài)。
  • activity被其他activity覆蓋其上(DialogActivity)或者鎖屏:系統(tǒng)會調(diào)用onPause()方法,暫停當前activity的執(zhí)行。
  • 當前activity由被覆蓋狀態(tài)回到前臺或者解鎖屏:系統(tǒng)會調(diào)用onResume()方法,再次進入運行狀態(tài)。
  • 當前Activity轉到新的Activity界面或按Home鍵回到主屏,自身退居后臺:系統(tǒng)會先調(diào)用onPause方法,然后調(diào)用onStop方法,進入停滯狀態(tài)。

  • 用戶后退回到此Activity:系統(tǒng)會先調(diào)用onRestart方法,然后調(diào)用onStart方法,最后調(diào)用onResume方法,再次進入運行狀態(tài)。

  • 當前Activity處于被覆蓋狀態(tài)或者后臺不可見狀態(tài),即第2和第4步,系統(tǒng)內(nèi)存不足,殺死當前Activity,而后用戶退回當前Activity:再次調(diào)用onCreate方法、onStart方法、onResume方法,進入運行狀態(tài)。

  • 用戶退出當前Activity:系統(tǒng)先調(diào)用onPause方法,然后調(diào)用onStop方法,最后調(diào)用onDestory方法,結束當前Activity。

  • onRestart():表示activity正在重新啟動 ,一般情況下,當前activity從不可見重新變成可見狀態(tài)時,onRestart()就會被調(diào)用,這種情形一般是用戶行為所導致的,比如用戶按HOME鍵切換到桌面然后重新打開APP或者按back鍵。

  • onStart():activity可見了,但是還沒有出現(xiàn)在前臺,還無法和用戶交互。

  • onPause():表示activity正在停止,此時可以做一些存儲數(shù)據(jù),停止動畫等工作,注意不能太耗時,因為這會影響到新activity的顯示,onPause必須先執(zhí)行完,新的activity的onResume才會執(zhí)行。

  • 從activity是否可見來說,onstart()和onStop()是配對的,從activity是否在前臺來說,onResume()和onPause()是配對的。

  • 舊activity先onPause,然后新activity在啟動

注意:當activity中彈出dialog對話框的時候,activity不會回調(diào)onPause。然而當activity啟動dialog風格的activity的時候,此activity會回調(diào)onPause函數(shù)。

異常情況下的生命周期:比如當系統(tǒng)資源配置發(fā)生改變以及系統(tǒng)內(nèi)存不足時,activity就可能被殺死。

  • 情況1:資源相關的系統(tǒng)配置發(fā)生改變導致activity被殺死并重新創(chuàng)建比如說當前activity處于豎屏狀態(tài),如果突然旋轉屏幕,由于系統(tǒng)配置發(fā)生了改變,在默認情況下,activity就會被銷毀并且重新創(chuàng)建,當然我們也可以組織系統(tǒng)重新創(chuàng)建我們的activity。
Paste_Image.png

系統(tǒng)配置發(fā)生改變以后,activity會銷毀,其onPause,onStop,onDestory均會被調(diào)用,由于activity是在異常情況下終止的,系統(tǒng)會調(diào)用onSaveInstance來保存當activity狀態(tài),這個方法的調(diào)用時機是在onStop之前。與onPause沒有既定的時序關系,當activity重新創(chuàng)建后,系統(tǒng)會調(diào)用onRestoreInstanceState,并且把activity銷毀時onSaveInstanceState方法保存的Bundle對象作為參數(shù)同時傳遞給onRestoreInstanceState和onCreate方法。onRestoreInstanceState()onStart()方法后回調(diào)。

同時,在onSaveInstanceState和onRestoreInstanceState方法中,系統(tǒng)自動為我們做了一些恢復工作,如:文本框(EditeText)中用戶輸入的數(shù)據(jù),ListView滾動的位置等,這些view相關的狀態(tài)系統(tǒng)都能夠默認為我們恢復??梢圆榭磛iew源碼,和activity一樣,每個view都有onSaveInstanceState方法和onRestoreInstanceState方法。

生命周期日志打印:

04-11 09:44:57.350 11757-11757/cn.hotwoo.play:remote I/MainActivity: onCreate
04-11 09:44:57.354 11757-11757/cn.hotwoo.play:remote I/MainActivity: onStart
04-11 09:44:57.356 11757-11757/cn.hotwoo.play:remote I/MainActivity: onResume
04-11 09:44:57.425 11757-11757/cn.hotwoo.play:remote I/MainActivity: onCreateOptionsMenu
04-11 09:44:59.149 11757-11757/cn.hotwoo.play:remote I/MainActivity: onPause
04-11 09:44:59.151 11757-11757/cn.hotwoo.play:remote I/MainActivity: onSaveInstanceState
04-11 09:44:59.151 11757-11757/cn.hotwoo.play:remote I/MainActivity: onStop
04-11 09:44:59.151 11757-11757/cn.hotwoo.play:remote I/MainActivity: onDestroy
04-11 09:44:59.234 11757-11757/cn.hotwoo.play:remote I/MainActivity: onCreate
04-11 09:44:59.235 11757-11757/cn.hotwoo.play:remote I/MainActivity: onStart
04-11 09:44:59.236 11757-11757/cn.hotwoo.play:remote I/MainActivity: onRestoreInstanceState
04-11 09:44:59.237 11757-11757/cn.hotwoo.play:remote I/MainActivity: onResume
04-11 09:44:59.270 11757-11757/cn.hotwoo.play:remote I/MainActivity: onCreateOptionsMenu
04-11 10:02:32.320 11757-11757/cn.hotwoo.play:remote I/MainActivity: onPause04-11 10:02:32.516 11757-11757/cn.hotwoo.play:remote I/MainActivity: onStop
04-11 10:02:32.516 11757-11757/cn.hotwoo.play:remote I/MainActivity: onDestroy
  • 情況2:資源內(nèi)存不足導致低優(yōu)先級的activity被殺死
    這里的情況和前面的情況1數(shù)據(jù)存儲和恢復是完全一致的,activity
    按照優(yōu)先級從高到低可以分為如下三種:
    (1)前臺activity---正在和用戶交互的activity,優(yōu)先級最高
    (2)可見但非前臺activity---比如activity中彈出了一個對話框,導致activity可見但是位于后臺無法和用戶直接交互。
    (3)后臺activity---已經(jīng)被暫停的activity,比如執(zhí)行了onStop,優(yōu)先級最低。

防止重新創(chuàng)建activity:activity指定configChange屬性來不讓系統(tǒng)重新創(chuàng)建activity。android : configChanges = "orientation"

Activity與Fragment生命周期關系

創(chuàng)建過程:

Paste_Image.png

銷毀過程:

Paste_Image.png

Activity與menu創(chuàng)建先后順序

在activity創(chuàng)建完回調(diào)onResume后創(chuàng)建menu,回調(diào)onCreateOptionsMenu

04-05 00:35:03.452 2292-2292/cn.hotwoo.play:remote I/MainActivity: onCreate
04-05 00:35:03.453 2292-2292/cn.hotwoo.play:remote I/MainActivity: onStart
04-05 00:35:03.454 2292-2292/cn.hotwoo.play:remote I/MainActivity: onResume
04-05 00:35:03.482 2292-2292/cn.hotwoo.play:remote I/MainActivity: onCreateOptionsMenu

Activity的啟動模式

有四種啟動模式:standard,singleTop,singleTask,singleInstance

  • standard模式:在這種模式下,activity默認會進入啟動它的activity所屬的任務棧中。 注意:在非activity類型的context(如ApplicationContext)并沒有所謂的任務棧,所以不能通過ApplicationContext去啟動standard模式的activity。
  • singleTop模式:棧頂復用模式。如果新activity位于任務棧的棧頂?shù)臅r候,activity不會被重新創(chuàng)建,同時它的onNewIntent方法會被回調(diào)。 注意:這個activity的onCreate,onStart,onResume不會被回調(diào),因為他們并沒有發(fā)生改變。
  • singleTask模式:棧內(nèi)復用模式。只要activity在一個棧中存在,那么多次啟動此activity不會被重新創(chuàng)建單例,系統(tǒng)會回調(diào)onNewIntent。比如activityA,系統(tǒng)首先會尋找是否存在A想要的任務棧,如果沒有則創(chuàng)建一個新的任務棧,然后把activityA壓入棧,如果存在任務棧,然后再看看有沒有activityA的實例,如果實例存在,那么就會把A調(diào)到棧頂并調(diào)用它的onNewIntent方法,如果不存在則把它壓入棧。
  • singleInstance模式:單實例模式。這種模式的activity只能單獨地位于一個任務棧中。由于站內(nèi)復用特性,后續(xù)的請求均不會創(chuàng)建新的activity實例。

注意:默認情況下,所有activity所需的任務棧的名字為應用的包名,可以通過給activity指定TaskAffinity屬性來指定任務棧,**這個屬性值不能和包名相同,否則就沒有意義 **。


Android四大組件 --- Service

本地服務(LocalService)

調(diào)用者和service在同一個進程里,所以運行在主進程的main線程中。所以不能進行耗時操作,可以采用在service里面創(chuàng)建一個Thread來執(zhí)行任務。service影響的是進程的生命周期,討論與Thread的區(qū)別沒有意義。任何 Activity 都可以控制同一 Service,而系統(tǒng)也只會創(chuàng)建一個對應 Service 的實例

兩種啟動方式

第一種啟動方式:

通過start方式開啟服務.
使用service的步驟:

1,定義一個類繼承service
2,manifest.xml文件中配置service
3,使用context的startService(Intent)方法啟動service
4,不在使用時,調(diào)用stopService(Intent)方法停止服務

使用start方式啟動的生命周期:

onCreate() -- > onStartCommand() -- > onDestory()
注意:如果服務已經(jīng)開啟,不會重復回調(diào)onCreate()方法,如果再次調(diào)用context.startService()方法,service而是會調(diào)用onStart()或者onStartCommand()方法。停止服務需要調(diào)用context.stopService()方法,服務停止的時候回調(diào)onDestory被銷毀。

特點:一旦服務開啟就跟調(diào)用者(開啟者)沒有任何關系了。開啟者退出了,開啟者掛了,服務還在后臺長期的運行,開啟者不能調(diào)用服務里面的方法。

第二種啟動方式

采用bind的方式開啟服務
使用service的步驟:

1,定義一個類繼承Service
2,在manifest.xml文件中注冊service
3,使用context bindService(Intent,ServiceConnection,int)方法啟動service
4,不再使用時,調(diào)用unbindService(ServiceConnection)方法停止該服務

使用這種start方式啟動的service的生命周期如下:

onCreate() -- > onBind() --> onUnbind() -- > onDestory()

注意:綁定服務不會調(diào)用onStart()或者onStartCommand()方法

特點:bind的方式開啟服務,綁定服務,調(diào)用者掛了,服務也會跟著掛掉。綁定者可以調(diào)用服務里面的方法。

示例
定義一個類繼承service

//本地service不涉及進程間通信
public class MyService extends Service { 
    private String TAG = "MyService"; 
   
   @Override 
    public void onCreate() { 
    super.onCreate(); 
    Log.i(TAG,"onCreate");
   } 

    @Override 
    public void onStart(Intent intent, int startId) { 
    super.onStart(intent, startId); 
    Log.i(TAG,"onStart");
   } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
        Log.i(TAG,"onStartCommand"); 
        return super.onStartCommand(intent, flags, startId); 
    } //綁定服務時調(diào)用這個方法,返回一個IBinder對象 
    
    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) {     
        Log.i(TAG,"onBind"); 
        return new MyBinder(); 
    } 

    @Override 
    public boolean onUnbind(Intent intent) {         
        Log.i(TAG,"onUnbind"); 
        return super.onUnbind(intent); 
    }

// 停止服務,通過調(diào)用Context.unbindService(),別忘了service也繼承了Context類
// @Override
// public void unbindService(ServiceConnection conn) {
// super.unbindService(conn);
// Log.i(TAG,"unbindService");
// } 
//服務掛了 

    @Override 
     public void onDestroy() { 
        super.onDestroy(); Log.i(TAG,"onDestroy"); 
    } 

    public interface MyIBinder{ 
        void invokeMethodInMyService();
     } 

    public class MyBinder extends Binder implements MyIBinder{ 
        public void stopService(ServiceConnection serviceConnection){ 
            unbindService(serviceConnection);
         } 

    @Override 
    public void invokeMethodInMyService() { 
        for(int i =0; i <   20; i ++){ 
        System.out.println("service is opening"); 
    } 
  } 
}

在manifest.xml文件中注冊service

//Service 必須要注冊 
<service  android:name=".server.MyService" 
        android:exported="true"> 
        <intent-filter> 
            <action android:name="cn.hotwoo.play.server.MyService"/>     
            <category android:name="android.intent.category.default" /> 
        </intent-filter> 
</service>

綁定自定義的service


Paste_Image.png

Paste_Image.png

startService輸出日志:

04-01 19:56:09.846 22845-22845/cn.hotwoo.play I/MyService: onCreate
04-01 19:56:09.854 22845-22845/cn.hotwoo.play I/MyService: onStartCommand
04-01 19:56:09.854 22845-22845/cn.hotwoo.play I/MyService: onStart

bindService 輸出日志:

04-01 19:53:21.459 14704-14704/cn.hotwoo.play I/MyService: onCreate
04-01 19:53:21.460 14704-14704/cn.hotwoo.play I/MyService: onBind
04-01 19:53:21.461 14704-14704/cn.hotwoo.play I/MyService: onServiceConnected

點擊back鍵關閉activity或者調(diào)用Context.unbindService()方法后:

04-05 01:16:27.508 11427-11427/cn.hotwoo.play I/MyService: onUnbind
04-05 01:16:27.508 11427-11427/cn.hotwoo.play I/MyService: onDestroy

遠程服務

調(diào)用者和service不在同一個進程中,service在單獨的進程中的main線程,是一種垮進程通信方式。學習地址

綁定遠程服務的步驟:

  • 在服務的內(nèi)部創(chuàng)建一個內(nèi)部類,提供一個方法,可以間接調(diào)用服務的方法
  • 把暴露的接口文件的擴展名改為.aidl文件 去掉訪問修飾符
  • 實現(xiàn)服務的onbind方法,繼承Bander和實現(xiàn)aidl定義的接口,提供給外界可調(diào)用的方法
  • 在activity 中綁定服務。bindService()
  • 在服務成功綁定的時候會回調(diào) onServiceConnected方法 傳遞一個 IBinder對象
  • aidl定義的接口.Stub.asInterface(binder) 調(diào)用接口里面的方法

IntentService

IntentService是Service的子類,比普通的Service增加了額外的功能。先看Service本身存在兩個問題

  • Service不會專門啟動一條單獨的進程,Service與它所在應用位于同一個進程中;
  • Service也不是專門一條新線程,因此不應該在Service中直接處理耗時的任務;

IntentService特征:

  • 會創(chuàng)建獨立的worker線程來處理所有的Intent請求;
  • 會創(chuàng)建獨立的worker線程來處理onHandleIntent()方法實現(xiàn)的代碼,無需處理多線程問題;
  • 所有請求處理完成后,IntentService會自動停止,無需調(diào)用stopSelf()方法停止Service;
  • 為Service的onBind()提供默認實現(xiàn),返回null;
  • 為Service的onStartCommand提供默認實現(xiàn),將請求Intent添加到隊列中;

Android四大組件 --- BroadcastReceiver

廣播被分為兩種不同的類型:“普通廣播(Normal broadcasts)”和“有序廣播(Ordered broadcasts)”。普通廣播是完全異步的,可以在同一時刻(邏輯上)被所有接收者接收到,消息傳遞的效率比較高,但缺點是:接收者不能將處理結果傳遞給下一個接收者,并且無法終止廣播Intent的傳播;然而有序廣播是按照接收者聲明的優(yōu)先級別(聲明在intent-filter元素的android:priority屬性中,數(shù)越大優(yōu)先級別越高,取值范圍:-1000到1000。也可以調(diào)用IntentFilter對象的setPriority()進行設置),被接收者依次接收廣播。如:A的級別高于B,B的級別高于C,那么,廣播先傳給A,再傳給B,最后傳給C。A得到廣播后,可以往廣播里存入數(shù)據(jù),當廣播傳給B時,B可以從廣播中得到A存入的數(shù)據(jù)。
發(fā)送廣播

Context.sendBroadcast()
發(fā)送的是普通廣播,所有訂閱者都有機會獲得并進行處理。
Context.sendOrderedBroadcast()
發(fā)送的是有序廣播,系統(tǒng)會根據(jù)接收者聲明的優(yōu)先級別按順序逐個執(zhí)行接收者,前面的接收者有權終止廣播(BroadcastReceiver.abortBroadcast()),
如果廣播被前面的接收者終止,后面的接收者就再也無法獲取到廣播。對于有序廣播,前面的接收者可以將處理結果通過setResultExtras(Bundle)方法存放進結果對象,
然后傳給下一個接收者,通過代碼:Bundle bundle =getResultExtras(true))可以獲取上一個接收者存入在結果對象中的數(shù)據(jù)。
系統(tǒng)收到短信,發(fā)出的廣播屬于有序廣播。如果想阻止用戶收到短信,可以通過設置優(yōu)先級,
讓你們自定義的接收者先獲取到廣播,然后終止廣播,這樣用戶就接收不到短信了。

生命周期:如果一個廣播處理完onReceive 那么系統(tǒng)將認定此對象將不再是一個活動的對象,也就會finished掉它。
至此,大家應該能明白 Android 的廣播生命周期的原理。

Paste_Image.png

步驟:
1,自定義一個類繼承BroadcastReceiver
2,重寫onReceive方法

3,在manifest.xml中注冊

注意BroadcastReceiver生命周期很短
如果需要在onReceiver完成一些耗時操作,應該考慮在Service中開啟一個新線程處理耗時操作,不應該在BroadcastReceiver中開啟一個新的線程,因為BroadcastReceiver生命周期很短,在執(zhí)行完onReceiver以后就結束,如果開啟一個新的線程,可能出現(xiàn)BroadcastRecevier退出以后線程還在,而如果BroadcastReceiver所在的進程結束了,該線程就會被標記為一個空線程,根據(jù)Android的內(nèi)存管理策略,在系統(tǒng)內(nèi)存緊張的時候,會按照優(yōu)先級,結束優(yōu)先級低的線程,而空線程無異是優(yōu)先級最低的,這樣就可能導致BroadcastReceiver啟動的子線程不能執(zhí)行完成。

示例

Paste_Image.png

注冊

Paste_Image.png

廣播還可以通過動態(tài)注冊:
registerReceiver(new MyBroadcastReceiver(),new IntentFilter("test"));

一定要加上這個權限(坑)
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

注意:xml中注冊的優(yōu)先級高于動態(tài)注冊廣播。

發(fā)送廣播
Intent intent = new Intent("test"); sendBroadcast(intent);

靜態(tài)注冊和動態(tài)注冊區(qū)別

  • 動態(tài)注冊廣播不是常駐型廣播,也就是說廣播跟隨activity的生命周期。注意: 在activity結束前,移除廣播接收器。靜態(tài)注冊是常駐型,也就是說當應用程序關閉后,如果有信息廣播來,程序也會被系統(tǒng)調(diào)用自動運行。
  • 當廣播為有序廣播時:
1 優(yōu)先級高的先接收 
2 同優(yōu)先級的廣播接收器,動態(tài)優(yōu)先于靜態(tài) 
3 同優(yōu)先級的同類廣播接收器,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的。
  • 當廣播為普通廣播時:
1 無視優(yōu)先級,動態(tài)廣播接收器優(yōu)先于靜態(tài)廣播接收器 
2 同優(yōu)先級的同類廣播接收器,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的。

小結:

  • 在Android 中如果要發(fā)送一個廣播必須使用sendBroadCast 向系統(tǒng)發(fā)送對其感興趣的廣播接收器中。
  • 使用廣播必須要有一個intent 對象必設置其action動作對象
  • 使用廣播必須在配置文件中顯式的指明該廣播對象
  • 每次接收廣播都會重新生成一個接收廣播的對象
  • 在BroadCastReceiver中盡量不要處理太多邏輯問題,建議復雜的邏輯交給Activity 或者 Service 去處理
  • 如果在AndroidManifest.xml中注冊,當應用程序關閉的時候,也會接收到廣播。在應用程序中注冊就不產(chǎn)生這種情況了。

注意

當如果要進行的操作需要花費比較長的時間,則不適合放在BroadcastReceiver中進行處理。
引用網(wǎng)上找到的一段解釋:
在 Android 中,程序的響應( Responsive )被活動管理器( Activity Manager )和窗口管理器( Window Manager )這兩個系統(tǒng)服務所監(jiān)視。當 BroadcastReceiver 在 10 秒內(nèi)沒有執(zhí)行完畢,Android 會認為該程序無響應。所以在 BroadcastReceiver 里不能做一些比較耗時的操作,否側會彈出ANR ( Application No Response )的對話框。如果需要完成一項比較耗時的工作,應該通過發(fā)送Intent 給 Service ,由 Service 來完成。而不是使用子線程的方法來解決,因為 BroadcastReceiver 的生命周期很短(在 onReceive() 執(zhí)行后 BroadcastReceiver 的實例就會被銷毀),子線程可能還沒有結束BroadcastReceiver 就先結束了。如果 BroadcastReceiver 結束了,它的宿主進程還在運行,那么子線程還會繼續(xù)執(zhí)行。但宿主進程此時很容易在系統(tǒng)需要內(nèi)存時被優(yōu)先殺死,因為它屬于空進程(沒有任何活動組件的進程)。

Android四大組件 --- ContentProvider

contentprovider是android四大組件之一的內(nèi)容提供器,它主要的作用就是將程序的內(nèi)部的數(shù)據(jù)和外部進行共享,為數(shù)據(jù)提供外部訪問接口,被訪問的數(shù)據(jù)主要以數(shù)據(jù)庫的形式存在,而且還可以選擇共享哪一部分的數(shù)據(jù)。這樣一來,對于程序當中的隱私數(shù)據(jù)可以不共享,從而更加安全。contentprovider是android中一種跨程序共享數(shù)據(jù)的重要組件。

使用系統(tǒng)的ContentProvider

系統(tǒng)的ContentProvider有很多,如通話記錄,短信,通訊錄等等,都需要和第三方的app進行共享數(shù)據(jù)。既然是使用系統(tǒng)的,那么contentprovider的具體實現(xiàn)就不需要我們擔心了,使用內(nèi)容提供者的步驟如下

  • 獲取ContentResolver實例
  • 確定Uri的內(nèi)容,并解析為具體的Uri實例
  • 通過ContentResolver實例來調(diào)用相應的方法,傳遞相應的參數(shù),但是第一個參數(shù)總是Uri,它制定了我們要操作的數(shù)據(jù)的具體地址

可以通過讀取系統(tǒng)通訊錄的聯(lián)系人信息,顯示在Listview中來實踐這些知識。不要忘記在讀取通訊錄的時候,在清單文件中要加入相應的讀取權限。

自定義ContentProvider

系統(tǒng)的contentprovider在與我們交互的時候,只接受了一個Uri的參數(shù),然后根據(jù)我們的操作返回給我們結果。系統(tǒng)到底是如何根據(jù)一個Uri就能夠提供給我們準確的結果呢?只有自己親自實現(xiàn)一個看看了。

和之前提到的一樣,想重新自定義自己程序中的四大組件,就必須重新實現(xiàn)一個類,重寫這個類中的抽象方法,在清單文件中注冊,最后才能夠正常使用。

重新實現(xiàn)ContentProvider之后,發(fā)現(xiàn)我們重寫了6個重要的抽象方法

  • oncreate
  • query
  • update
  • insert
  • delete
  • gettype

大部分的方法在數(shù)據(jù)庫那里已經(jīng)見過了,他們內(nèi)部的邏輯可想而知都是對數(shù)據(jù)的增刪改查操作,其中這些方法的第一個參數(shù)大多都是Uri實例。其中有兩個方法比較特殊:

  • oncreate方法應該是內(nèi)容提供者創(chuàng)建的時候所執(zhí)行的一個回調(diào)方法,負責數(shù)據(jù)庫的創(chuàng)建和更新操作。這個方法只有我們在程序中獲取ContentResolver實例之后準備訪問共享數(shù)據(jù)的時候,才會被執(zhí)行。
  • gettype方法是獲取我們通過參數(shù)傳遞進去的Uri的MIME類型,這個類型是什么,后面會有實例說明。

內(nèi)容提供者首先要做的一個事情就是將我們傳遞過來的Uri解析出來,確定其他程序到底想訪問哪些數(shù)據(jù)。Uri的形式一般有兩種:

1,以路徑名為結尾,這種Uri請求的是整個表的數(shù)據(jù),如: content://com.demo.androiddemo.provider/tabl1 標識我們要訪問tabl1表中所有的數(shù)據(jù)

2,以id列值結尾,這種Uri請求的是該表中和其提供的列值相等的單條數(shù)據(jù)。 content://com.demo.androiddemo.provider/tabl1/1 標識我們要訪問tabl1表中_id列值為1的數(shù)據(jù)。

如果是內(nèi)容提供器的設計者,那么我們肯定知道這個程序的數(shù)據(jù)庫是什么樣的,每一張表,或者每一張表中的_id都應該有一個唯一的內(nèi)容Uri。我們可以將傳遞進來的Uri和我們存好的Uri進行匹配,匹配到了之后,就說明數(shù)據(jù)源已經(jīng)找到,便可以進行相應的增刪改查操作。

ContentProvider詳解

五種布局

RelativeLayout 實現(xiàn)平分父布局

Paste_Image.png

RelativeLayout 的子view的 layout_gravity屬性是沒有效果的,而是通過

Paste_Image.png

這樣的一些屬性來代替。

文/Lemon_95(簡書作者)
原文鏈接:http://www.itdecent.cn/p/51aaa65d5d25
著作權歸作者所有,轉載請聯(lián)系作者獲得授權,并標注“簡書作者”。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容