Android 四大組件

Android四大組件 --- Activity

Activity生命周期

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

生命周期圖
  • 啟動activity:系統(tǒng)先調(diào)用onCreate()抛寝,然后調(diào)用onStart()壮莹,最后調(diào)用onResume()方法,activity進(jìn)入運行狀態(tài)参歹。

  • activity其他activity覆蓋其上(DialogActivity)或者鎖屏:系統(tǒng)會調(diào)用onPause()方法,暫停當(dāng)前activity的執(zhí)行薄货。

  • 當(dāng)前activity由被覆蓋狀態(tài)回到前臺或者解鎖屏:系統(tǒng)會調(diào)用onResume()方法,再次進(jìn)入運行狀態(tài)搪桂。

  • 當(dāng)前Activity轉(zhuǎn)到新的Activity界面或按Home鍵回到主屏略步,自身退居后臺:系統(tǒng)會先調(diào)用onPause方法描扯,然后調(diào)用onStop方法,進(jìn)入停滯狀態(tài)趟薄。

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

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

  • 用戶退出當(dāng)前Activity:系統(tǒng)先調(diào)用onPause方法钦购,然后調(diào)用onStop方法檐盟,最后調(diào)用onDestory方法褂萧,結(jié)束當(dāng)前Activity

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

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

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

  • activity是否可見來說囊扳,onstart()onStop()是配對的吩翻,從activity是否在前臺來說,onResume()onPause()是配對的锥咸。

  • activityonPause狭瞎,然后新activity在啟動

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

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

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

生命周期圖
系統(tǒng)配置發(fā)生改變以后,activity會銷毀引谜,其onPause牍陌,onStoponDestory均會被調(diào)用员咽,由于activity是在異常情況下終止的毒涧,系統(tǒng)會調(diào)用onSaveInstance來保存當(dāng)前activity狀態(tài),這個方法的調(diào)用時機(jī)是在onStop之前贝室。與onPause沒有既定的時序關(guān)系契讲,當(dāng)activity重新創(chuàng)建后,系統(tǒng)會調(diào)用onRestoreInstanceState滑频,并且把activity銷毀時onSaveInstanceState方法保存的Bundle對象作為參數(shù)同時傳遞給onRestoreInstanceState和onCreate方法捡偏。onRestoreInstanceState()onStart()方法后回調(diào)。

同時峡迷,在onSaveInstanceStateonRestoreInstanceState方法中银伟,系統(tǒng)自動為我們做了一些恢復(fù)工作,如:文本框(EditeText)中用戶輸入的數(shù)據(jù)绘搞,ListView滾動的位置等彤避,這些view相關(guān)的狀態(tài)系統(tǒng)都能夠默認(rèn)為我們恢復(fù)】春迹可以查看view源碼忠藤,和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: onPause
04-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)存不足導(dǎo)致低優(yōu)先級的activity被殺死
    這里的情況和前面的情況1數(shù)據(jù)存儲和恢復(fù)是完全一致的尖阔,activity按照優(yōu)先級從高到低可以分為如下三種:
    (1)前臺activity---正在和用戶交互的activity,優(yōu)先級最高
    (2)可見但非前臺activity---比如activity中彈出了一個對話框榨咐,導(dǎo)致activity可見但是位于后臺無法和用戶直接交互介却。
    (3)后臺activity---已經(jīng)被暫停的activity,比如執(zhí)行了onStop块茁,優(yōu)先級最低齿坷。

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

Activity與Fragment生命周期關(guān)系

創(chuàng)建過程:


創(chuàng)建過程

銷毀過程:


銷毀過程

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永淌,singleTopsingleTask佩耳,singleInstance

  • standard模式:在這種模式下遂蛀,activity默認(rèn)會進(jìn)入啟動它的activity所屬的任務(wù)棧中注意:在非activity類型的context(如ApplicationContext)并沒有所謂的任務(wù)棧干厚,所以不能通過ApplicationContext去啟動standard模式的activity李滴。
  • singleTop模式:棧頂復(fù)用模式。如果新activity位于任務(wù)棧的棧頂?shù)臅r候蛮瞄,activity不會被重新創(chuàng)建所坯,同時它的onNewIntent方法會被回調(diào)。 注意:這個activity的onCreate挂捅,onStart芹助,onResume不會被回調(diào),因為他們并沒有發(fā)生改變籍凝。
  • singleTask模式:棧內(nèi)復(fù)用模式周瞎。只要activity在一個棧中存在苗缩,那么多次啟動此activity不會被重新創(chuàng)建單例饵蒂,系統(tǒng)會回調(diào)onNewIntent。比如activityA酱讶,系統(tǒng)首先會尋找是否存在A想要的任務(wù)棧退盯,如果沒有則創(chuàng)建一個新的任務(wù)棧,然后把a(bǔ)ctivityA壓入棧泻肯,如果存在任務(wù)棧渊迁,然后再看看有沒有activityA的實例,如果實例存在灶挟,那么就會把A調(diào)到棧頂并調(diào)用它的onNewIntent方法琉朽,如果不存在則把它壓入棧。
  • singleInstance模式:單實例模式稚铣。這種模式的activity只能單獨地位于一個任務(wù)棧中箱叁。由于站內(nèi)復(fù)用特性墅垮,后續(xù)的請求均不會創(chuàng)建新的activity實例。

注意:默認(rèn)情況下耕漱,所有activity所需的任務(wù)棧的名字為應(yīng)用的包名算色,可以通過給activity指定TaskAffinity屬性來指定任務(wù)棧,**這個屬性值不能和包名相同螟够,否則就沒有意義 ** 。

Android四大組件 --- Service

本地服務(wù)(LocalService)

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

兩種啟動方式

第一種啟動方式:

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

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

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

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

特點
一旦服務(wù)開啟就跟調(diào)用者(開啟者)沒有任何關(guān)系了做鹰。開啟者退出了,開啟者掛了鼎姐,服務(wù)還在后臺長期的運行钾麸,開啟者不能調(diào)用服務(wù)里面的方法。

第二種啟動方式

采用bind的方式開啟服務(wù)
使用service的步驟:

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

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

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

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

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

示例
定義一個類繼承service

//本地service不涉及進(jìn)程間通信
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);
    }

    //綁定服務(wù)時調(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);
    }

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

    //服務(wù)掛了
    @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

public class CustomActivity extends AppCompatActivity {

    private Button startService, unbindService;
    private MyService.MyBinder myBinder;
    private ServiceConnection serviceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom);

        startService = (Button) findViewById(R.id.service_start);
        unbindService = (Button) findViewById(R.id.unbind_service);

        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                startService(new Intent(CustomActivity.this, MyService.class));
                serviceConnection = new MyServiceConnection();
                bindService(new Intent(CustomActivity.this, MyService.class), serviceConnection, Context.BIND_AUTO_CREATE);
            }
        });
        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(serviceConnection);
            }
        });

    }

    class MyServiceConnection implements ServiceConnection {

        //這里的第二個參數(shù)IBinder就是Service中的onBind方法返回的
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("MyService", "onServiceConnected");
            myBinder = (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("MyService", "onServiceDisconnected");
        }
    }
}

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鍵關(guān)閉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

遠(yuǎn)程服務(wù)

調(diào)用者和service不在同一個進(jìn)程中囚巴,service在單獨的進(jìn)程中的main線程原在,是一種垮進(jìn)程通信方式。學(xué)習(xí)地址

綁定遠(yuǎn)程服務(wù)的步驟:

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

IntentService

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

  • Service不會專門啟動一條單獨的進(jìn)程审残,Service與它所在應(yīng)用位于同一個進(jìn)程中;
  • Service也不是專門一條新線程斑举,因此不應(yīng)該在Service中直接處理耗時的任務(wù)搅轿;

IntentService特征:

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

Android四大組件 --- BroadcastReceiver

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

發(fā)送廣播

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

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

生命周期

步驟:
1传蹈,自定義一個類繼承BroadcastReceiver
2押逼,重寫onReceive方法
3,在manifest.xml中注冊

注意BroadcastReceiver生命周期很短
如果需要在onReceiver完成一些耗時操作惦界,應(yīng)該考慮在Service中開啟一個新線程處理耗時操作挑格,不應(yīng)該在BroadcastReceiver中開啟一個新的線程,因為BroadcastReceiver生命周期很短沾歪,在執(zhí)行完onReceiver以后就結(jié)束漂彤,如果開啟一個新的線程,可能出現(xiàn)BroadcastRecevier退出以后線程還在,而如果BroadcastReceiver所在的進(jìn)程結(jié)束了挫望,該線程就會被標(biāo)記為一個空線程立润,根據(jù)Android的內(nèi)存管理策略,在系統(tǒng)內(nèi)存緊張的時候媳板,會按照優(yōu)先級桑腮,結(jié)束優(yōu)先級低的線程,而空線程無異是優(yōu)先級最低的蛉幸,這樣就可能導(dǎo)致BroadcastReceiver啟動的子線程不能執(zhí)行完成破讨。

示例

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("fuck","intent-action : " + intent.getAction());
        if(intent.getAction().equals("test")){
            Toast.makeText(context,"fuck",Toast.LENGTH_LONG).show();
        }
    }

}

注冊

        //廣播接收器
        <receiver android:name=".broadcast.MyBroadcastReceiver">

            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                <action android:name="test"/>//這里自定義一個廣播動作
            </intent-filter>

        </receiver>

廣播還可以通過動態(tài)注冊:

registerReceiver(new MyBroadcastReceiver(),new IntentFilter("test"));

一定要加上這個權(quán)限(坑)

<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結(jié)束前,移除廣播接收器若锁。
    靜態(tài)注冊是常駐型搁骑,也就是說當(dāng)應(yīng)用程序關(guān)閉后,如果有信息廣播來又固,程序也會被系統(tǒng)調(diào)用自動運行仲器。
  • 當(dāng)廣播為有序廣播時:
    1 優(yōu)先級高的先接收
    2 同優(yōu)先級的廣播接收器,動態(tài)優(yōu)先于靜態(tài)
    3 同優(yōu)先級的同類廣播接收器仰冠,靜態(tài):先掃描的優(yōu)先于后掃描的乏冀,動態(tài):先注冊的優(yōu)先于后注冊的。
  • 當(dāng)廣播為普通廣播時:
    1 無視優(yōu)先級洋只,動態(tài)廣播接收器優(yōu)先于靜態(tài)廣播接收器
    2 同優(yōu)先級的同類廣播接收器辆沦,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的识虚。

小結(jié):

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

注意

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

Android四大組件 --- ContentProvider

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

使用系統(tǒng)的ContentProvider

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

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

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

自定義ContentProvider

系統(tǒng)的contentprovider在與我們交互的時候,只接受了一個Uri的參數(shù)刻获,然后根據(jù)我們的操作返回給我們結(jié)果蜀涨。系統(tǒng)到底是如何根據(jù)一個Uri就能夠提供給我們準(zhǔn)確的結(jié)果呢?只有自己親自實現(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方法應(yīng)該是內(nèi)容提供者創(chuàng)建的時候所執(zhí)行的一個回調(diào)方法逊移,負(fù)責(zé)數(shù)據(jù)庫的創(chuàng)建和更新操作。這個方法只有我們在程序中獲取ContentResolver實例之后準(zhǔn)備訪問共享數(shù)據(jù)的時候龙填,才會被執(zhí)行胳泉。
  • gettype方法是獲取我們通過參數(shù)傳遞進(jìn)去的Uri的MIME類型,這個類型是什么觅够,后面會有實例說明胶背。

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

1钳吟,以路徑名為結(jié)尾,這種Uri請求的是整個表的數(shù)據(jù)窘拯,如: content://com.demo.androiddemo.provider/tabl1 標(biāo)識我們要訪問tabl1表中所有的數(shù)據(jù)
2红且,以id列值結(jié)尾,這種Uri請求的是該表中和其提供的列值相等的單條數(shù)據(jù)涤姊。 content://com.demo.androiddemo.provider/tabl1/1 標(biāo)識我們要訪問tabl1表中_id列值為1的數(shù)據(jù)暇番。

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

ContentProvider詳解

五種布局

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

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

        <View android:id="@+id/strut"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_centerHorizontal="true"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_alignRight="@id/strut"
            android:layout_alignParentLeft="true"
            android:text="Left"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@id/strut"
            android:layout_alignParentRight="true"
            android:text="Right"/>

</RelativeLayout>

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

            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"

這樣的一些屬性來代替。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纲辽,一起剝皮案震驚了整個濱河市颜武,隨后出現(xiàn)的幾起案子璃搜,更是在濱河造成了極大的恐慌,老刑警劉巖鳞上,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件这吻,死亡現(xiàn)場離奇詭異,居然都是意外死亡因块,警方通過查閱死者的電腦和手機(jī)橘原,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門籍铁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涡上,“玉大人,你說我怎么就攤上這事拒名》岳ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵增显,是天一觀的道長雁佳。 經(jīng)常有香客問我,道長同云,這世上最難降的妖魔是什么糖权? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮炸站,結(jié)果婚禮上星澳,老公的妹妹穿的比我還像新娘。我一直安慰自己旱易,他們只是感情好禁偎,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阀坏,像睡著了一般如暖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忌堂,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天盒至,我揣著相機(jī)與錄音,去河邊找鬼士修。 笑死枷遂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的李命。 我是一名探鬼主播登淘,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼封字!你這毒婦竟也來了黔州?” 一聲冷哼從身側(cè)響起耍鬓,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎流妻,沒想到半個月后牲蜀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡绅这,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年涣达,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片证薇。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡度苔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浑度,到底是詐尸還是另有隱情寇窑,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布箩张,位于F島的核電站甩骏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏先慷。R本人自食惡果不足惜饮笛,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望论熙。 院中可真熱鬧福青,春花似錦、人聲如沸赴肚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誉券。三九已至指厌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踊跟,已是汗流浹背踩验。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留商玫,地道東北人箕憾。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像拳昌,于是被迫代替她去往敵國和親袭异。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容