第三天

四大組件之
        Activity的生命周期,啟動
        Intent和intentFilter
        Service的生命周期,兩種編程方式
        BroadcastReceiver 廣播接收者
        ContentProvider內容提供者
--------------------------------------------------------------------------------
什么是Activity 
        a,布滿整個窗口或者懸浮于其他窗口上的交互界面
        b,一個應用程序中通常有一個或多個Activity構成
        b,每個Activity都必須在AndroidManifest.xml中進行申明
        c,多個Activity是通過棧進行管理,當前的活動的Activity在棧頂
        d,在程序中自定義的Activity必須繼承基類Activity
        c,Activity有自己的生命周期,并且在不同的生命周期中會調用不同的函數(shù)
    創(chuàng)建方法:
        1.定義一個Activity的子類
        2.重寫onCreate()
        3.定義一個布局視圖    
        4.將布局視圖關聯(lián)給活動(界面)
        5.注冊活動子類到清單文件
    四大組件之Activity的生命周期
        class 人類{
            出生方法(){}
            
            上幼兒方法(){}
            
            上小學(){}
            
            上中學(){}
            
            上大學(){}
            
            工作1(){}
            工作2(){}
            
            找對象(){}
            成家(){}
            
            去世(){}
            
        }


onCreate(): Activity開始被創(chuàng)建的時候被調用,
            主要完成的任務:創(chuàng)建ui視圖,綁定數(shù)據(jù)到list中

onStart(): 當Activity變成可視化的時候被調用,可見了,但還不是可交互的從后臺切換到前臺也會調用
           此方法中可以去維護一些顯示在Activity上的資源,比如可以注冊一個BroadcastReceiver,
           用于監(jiān)控對UI產(chǎn)生影響的狀態(tài)變化
           比如ui上的內容發(fā)生變化,可以通過個BroadcastReceiver去廣播
                       
onResume: 獲取到與用戶交互的焦點,也可以認為是apk正在running
          在這里可以做一些動畫的播放,打開獨占設備(比如相機)

onPause: 失去用戶交互的焦點,但是視圖還在,比如另外一個Activity切換到前臺并獲取到焦點時
          (一個對話框出現(xiàn),或者是休眠)
          在這個方法中執(zhí)行停止動畫等比較耗CPU的操作,或者將需要永久化存儲的數(shù)據(jù)進行保存,
          因為有可能不會回來了

onResume和onPause會經(jīng)常切換,所以里面的內容盡量的是輕量級的,以避免導致用戶等待

onStop:表示當前Activity完全被其他的視圖給占用了

onDestrory: 整個Activity完全銷毀的時候,該方法中應該完成釋放資源的操作

        3個階段和7個方法
            開始階段:onCreate, onStart, onResume
            重新獲取焦點: onRestart(); onStart();onResume;
            關閉Activity: onPause, onStop,onDestory

        Activity獲得與失去焦點的循環(huán):
            onPause->onResume->onPause
        Activity可見與不可見的循環(huán)
            onStart->onRestart->onResume->onPause->onStop

        整個生命周期:onCreate-->onDestory
            可視周期:
                onStart->onStop
            焦點周期:
                onResume->onPause
            在 activity 被停止后重新啟動時(調用打開過的應用程序)調用該方法。
                其后續(xù)會調用 onStart 方法   
                onRestart()
        總共7個
        -------------------------------------------------
        activity創(chuàng)建(onCreate)->可視化(onStart)->獲取焦點(onResume)
                |
                來了一個電話
        onPause(失去焦點)->onStop(失去視圖)
                |
                接完電話,返回到app
        onRestart(重新開始,針對恢復activity)->onStart(可視化)->onResum(獲取焦點)
                |
                退出activity
        onPause(失去焦點)->onStop(失去視圖)->onDestroy(毀滅)
        
        按下返回按鍵:onPause()->onStop()->onDestory()
        長按Home鍵,彈出最近打開過的應用程序
        按Home鍵:onPause()->onStop()
        onRestart():啟動一個另外一個Activity后,由另外一個Activity返回時
=============================================================================== 
    啟動Activity的方式:
    1,startActivity();
        a,啟動一個自定義的Activity(顯示的啟動)
            Intent intent = new Intent();                           //創(chuàng)建一個Intent對象   
            intent.setClass(activity1.this, activity2.class);   //描述起點和目標   
            startActivity(intent);                                     //開始跳轉
        b,啟動系統(tǒng)的Activity
            String telString = "tel:13800138000";
            final Uri telUri = Uri.parse(telString);
            String data = "http://www.google.com";
            final Uri webUri = Uri.parse(data);

            Intent intent = new Intent(Intent.ACTION_VIEW, webUri);
            startActivity(intent);
        
        
    2,啟動另外一個Activity并返回結果--實質也是通過Bundle實現(xiàn)
        startActivityForResult(Intent, int requestCode);----------> 
            參數(shù)2:requestCode請求碼,由程序員自行定義,用于標識請求來源
                    例如:一個Activity有兩個按鈕,點擊這兩個按鈕會打開不同的Activity
                    不管哪個Activity關閉后,系統(tǒng)都會調用前面Activity的onActivityResult()
                    如果需要獲取不同的Activity返回來的數(shù)據(jù),那么可以通過該請求碼進行識別
        onActivityResult(int requestCode, int resultCode, Intent)<-----------------
                     ----setResult(Int resultCode);
            requestCode:用于區(qū)分到底是哪個請求
            resultCode: 結果碼
            Intent:包含Bundle,里面有跟多信息
        另外一個:
           Intent data=new Intent();  
            data.putExtra("bookname", str_bookname);  
            data.putExtra("booksale", str_booksale);  
                setResult(20, data); // 

    3,啟動activity的時候傳遞數(shù)據(jù): intent作為中介(也可以理解為容器)
        a,攜帶Bundle
            1,構建Bundle
            2,填入數(shù)據(jù)
                bundle.putInt("鍵", 值); //普通數(shù)據(jù)
                budle.putSerialize("鍵",對象);
            3,將Bundle加入到Intent
                putExtra(Bundle) 
                
        b,鍵值對
            putExtra("鍵", 值);
        c,獲取數(shù)據(jù)
            Intent intent = getIntent();
    關閉Activity:
        a,關閉當前的activity
            finish();
        b,關閉以startActivityForResult()方法啟動的Activity
            finishActivity(int requestCode);

========================================================================
intent的作用和使用
    什么是intent?
    a,為一個信息的載體,用于應用間的交互與通訊,對應用中一次操作的動作、動作涉及數(shù)據(jù)、附加數(shù)據(jù)進行
        描述,Android則根據(jù)此Intent的描述,負責找到對應的組件,將Intent傳遞給調用的組件,并完成
        組件的調用
    b,Intent不僅可用于應用程序之間,也可用于應用程序內部的Activity/Service之間的交互
        比如啟動另外一個Activity,另外一個Service,還可以發(fā)送廣播給BoardcastReciver
        
    c,intent的屬性--表示要做什么,帶了一些什么信息
        Intent主要有以下四個重要屬性,它們分別為:
        0,Component name:表示該intent是交給哪個具體的Component組件的(該對象是可選的,同時也可以不用intent-filter)
            在代碼中需要如下操作:
                ComponentName comp = new ComponentName(xxx類.this, 另一個Activity的this);
                Intent  intent = new Intent();
                intent.setComponent(comp);
                StartActivity(Intent);
        
        Action 和Category,在啟動的組件中需要有intent-filter
        1,Action:值為一個字符串,它代表了系統(tǒng)中已經(jīng)定義了一系列常用的動作
            a,系統(tǒng)自帶的常量:ACTION_CALL,ACTION_EDIT
            b,自定義的字符串,一般格式:"包名.類名.特定的字符"
        
        2,Category:組件的類別,用于描述哪一類的組件可以處理該Intent,也是一個字符串,為Action添加的附加信息,通常會和Action結合使用
            一個Intent只能指定一個Action,但可以指定多個Category
                    CATEGORY_DEFAULT :默認的category
                    CATEGORY_LAUNCHER:決定應用程序是否顯示在程序列表里,表示在luncher中可否啟動該組件
                    CATEGORY_BROWSABLE :在網(wǎng)頁上點擊圖片或鏈接時,系統(tǒng)會考慮將此目標Activity列入可選列表,
                                    供用戶選擇以打開圖片或鏈接。比如有個網(wǎng)頁鏈接,你的系統(tǒng)裝了很多瀏覽器,此時會列舉出多個打開方式
                    
            
        3,Data:Android中采用指向數(shù)據(jù)的一個URI來表示,如在聯(lián)系人應用中,
            對于不同的動作,其URI數(shù)據(jù)的類型是不同的(可以設置type屬性指定特定類型數(shù)據(jù)),
            如ACTION_EDIT指定Data為文件URI,打電話為tel:URI,訪問網(wǎng)絡為http:URI,
            而由content provider提供的數(shù)據(jù)則為content: URIs。一個指向某聯(lián)系人的URI可能為:content://contacts/1。 
        4,Extras:Extras屬性主要用于傳遞目標組件所需要的額外的數(shù)據(jù)。通過putExtras()方法設置。常用于在多個Action之間進行數(shù)據(jù)交換
                public void invokeWebSearch(View view) {  
                        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);  
                        intent.putExtra(SearchManager.QUERY, "android");    //關鍵字  
                        startActivity(intent);  
                }  
        以上一般比較重要的是:
            action 
            data (both URI and data type) 
            category

    Intent被解析的過程:顯示intent和隱式intent
        顯示intent:明確指定需要啟動或者觸發(fā)的組件的類名,常用于啟動當前應用程序的不同組件
                類似與找人: 找章子怡
        隱式intent:指定需要啟動或者觸發(fā)的組件應滿足怎樣的條件,常用于啟動其他應用程序中的組件
                也就是說系統(tǒng)會對intent進行解析,解析出它的條件
                然后再在系統(tǒng)中查找與之匹配的目標組件
                而被調用或目標組件需要通過intentfilter來聲明自己滿足條件
                類似與找人: 穿紅衣服的女孩
    Intent-filter:組件的意圖過濾器,
        a,其實是一個對象,但是一般不會直接去創(chuàng)建,都是在AndroidManifest.xml中存在
        b,一個組件中可以有多個Intent-filter,可以根據(jù)過濾不同的intent而采取不同的處理
        c,過濾的時候會過濾三個域:action,data,category,任何intent必須成功經(jīng)過這三道過濾,缺一不可
        Action test:至少有一個
            <intent-filter . . . >
                <action android:name="com.example.project.SHOW_CURRENT" />
                <action android:name="com.example.project.SHOW_RECENT" />
                <action android:name="com.example.project.SHOW_PENDING" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            必須添加一個android.intent.category.DEFAULT


        c,隱式的啟動:
            在intent添加過濾器intentfilter
            <activity  <!--被啟動的Activity -->
                android:name="com.example.android.tst.SecondActivity"
                android:label="@string/title_activity_main" > 
                <intent-filter> 
                <action android:name="com.example.android.tst.SecondActivity"/> 
                <category android:name="android.intent.category.DEFAULT" /> 
                </intent-filter> 
            </activity>

            啟動方法:
                Intent intent=new Intent("com.example.android.tst.SecondActivity");
                //或者如下操作
                //intent.setAction( "com.example.android.tst.SecondActivity");
                //intent.addCategory(Intent.CATEGORY_DEFAULT);
                startActivity(intent);
                解釋:
                發(fā)送了這個intent之后,android會去系統(tǒng)里保存的MainManifest.xml里查找符
                合這兩個屬性的activity,

                任何一個需要隱式啟動的Activity都必須要有這項:
                    <category android:name="android.intent.category.DEFAULT"/>
==========================================================================
Service在Android中和Activity是屬于同一級別上的組件
            Activity儀表不凡,迷倒萬千少女
            Service身強力壯,但是在后臺做一些搬運工的力氣活

            后臺運行
Service的特性:
            1, 擁有后臺運行的特性,比如將屏幕關閉后,繼續(xù)運行
            2,不是一個獨立的進程,除非特別指定(存在于一個進程中)
            3,它不是一個線程
            4,服務是一種    應用程告訴系統(tǒng)它想在后臺要做的某個事情    的工具,并將功能提供(暴露)給其它應用程序

Service的應用場合:
        從播放列表播放音樂,播放器有一些activities來叫用戶選定歌曲并開始播放。但是,播放本身不需要activity處理,因為用戶希望關閉activity
        后歌曲會繼續(xù)播放。因此media player 的activity 會啟動一個service
    

Service和Thread的區(qū)別:
        1,Thread 是程序執(zhí)行的最小單元,它是分配CPU的基本單位,而Service是一個組件,你也可以認為是應用程序的一個插件
                這個插件能完成后臺的操作
        2,Service其實是運行在主線程中的,如果需要執(zhí)行復雜耗時的操作,必須在Service中再創(chuàng)建一個Thread來執(zhí)行任務
        3,Service的優(yōu)先級高于后臺掛起的Activity,當然,也高于Activity所創(chuàng)建的Thread,因此,系統(tǒng)可能在內存不足的時候優(yōu)先殺死后臺
                的Activity或者Thread,而不會輕易殺死Service組件,即使被迫殺死Service,也會在資源可用時重啟被殺死的Service
        4,Thread只是一個用來執(zhí)行后臺任務的工具類,它可以在Activity中被創(chuàng)建,也可以在Service中被創(chuàng)建。
            所以不需要去疑惑使用Service還是Thread,而是應該討論在什么地方創(chuàng)建Thread。

Service的兩種啟動方式:
            context.startService()-- 對應于Local Service(本地服務,調用和實現(xiàn)在同一個進程)
                        依附在主進程上而不是獨立的進程,這樣在一定程度上節(jié)約了資源,另外Local服務因為是在同一進程因此不需要IPC
                        主進程被Kill后,服務便會終止。
            context.bindService()-- 對應于Remote Service(遠程服務,調用和實現(xiàn)不在同一個進程)
                        由于是獨立的進程,因此在Activity所在進程被Kill的時候,該服務依然在運行,不受其他進程影響,有利于為多個進程
                        提供服務具有較高的靈活性。該服務是獨立的進程,會占用一定資源,并且使用AIDL進行IPC稍微麻煩一點
    
Service的生命周期:
        本地服務:
                啟動一個Service的過程
                            context.startService() ->onCreate()->onStartCommand()->Servicerunning
                
                            startService()在Activity中啟動服務,實際是并實例化了一個Service實例
                            onCreate()  進行一些服務的初始化工作,比如可以創(chuàng)建一個線程用于播放音樂
                            onStartCommand():服務正常運行時,能夠處理Intent,如果多多次啟動服務,該方法會被調用
                                                在以前的版本該方法為onStart();onStartCommand()內部會被調用,已經(jīng)過時了
                
                停止一個Service的過程:
                            context.stopService() ->onDestroy() ->Service stop 
                            
                            Activity調用這即使結束了自己的生命周期,只要沒有使用stopService方法停止這個服務,服務仍會運行
        遠程服務: 遠程服務其實就是給外部apk提供各種接口
                啟動一個Service的過程
                        context.bindService()-->onCreate()-->onBind()-->Servicerunning

                                onBind():當綁定成功時,該方法被調用,并且需要返回一個binder接口的實例
                                        如果重復綁定,該方法只會執(zhí)行一次
                停止一個Service的過程:
                        context.unbindService()-->onUnBinde()-->onDestroy()-->Service stop 
                        
                        bindService模式下服務是與調用者生死與共的,在綁定結束之后,一旦調用者被銷毀,服務也就立即終止,
                        就像江湖上的一句話:不求同生,但愿同死,當然羅,如果要繼續(xù)用服務,再bind就好了, 服務會跟著運行起來的


aidl: 實際是一個工具,幫我們自定生成一些代碼,完成進程調度的細節(jié)代碼
只需要定義好service段和調用端直接的接口就可以了

package com.hq.service;

interface IService{  //一定要文件的名字保持一致,文件名一定要是aidl的后綴
    int add(int a, int b);
    int sub(int a, int b);

}


1,在服務端里實現(xiàn)接口:
    public class MyService extends Service{
        
        public IBinder onBind(Intent arg0)
        {
            // TODO Auto-generated method stub
            Log.i(TAG, "------onBind--------");
            //如果需要綁定成功,就一定要返回一個binder的子類
            return new IServiceImpl();
        }

        // 實現(xiàn)用戶提供的接口,定義一個內部類
        public class IServiceImpl  extends IService.Stub{
                public int add(int a, int b) throws RemoteException
                {
                    // TODO Auto-generated method stub
                    return a+b;
                }

                @Override
                public int sub(int a, int b) throws RemoteException
                {
                    // TODO Auto-generated method stub
                    return a-b;
                }
        }
    
    }

2,在client中進行調用:
    bindService(intent3, serviceConnection, Service.BIND_AUTO_CREATE); //啟動服務
    //參數(shù)2: 當綁定成功之后,需要做的事情:
    private ServiceConnection serviceConnection = new ServiceConnection(){
        public void onServiceConnected(ComponentName name, IBinder iBinder){
                //通過IService中將ibider統(tǒng)一的接口轉換成自己定義的接口對象
                serviceManager = IService.Stub.asInterface(iBinder);
                serviceManager.add(34, 56) //直接調用
        }
    }


MediaPlayer media;
media = MediaPlayer.create(MyService.this,R.raw.nobody);
media.start();
media.stop();
------------------------------------------------------------------------------------------------------------------------------------
BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統(tǒng)和應用中的廣播
    廣播體現(xiàn)在方方面面,例如
            當開機完成后系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能實現(xiàn)開機啟動服務的功能;
            當網(wǎng)絡狀態(tài)改變時系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能及時地做出提示和保存數(shù)據(jù)等操作;
            當電池電量改變時,系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能在電量低時告知用戶及時保存進度,等等。

廣播的發(fā)送:
    普通廣播:
            對于多個接收者來說是完全異步的,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對于這種廣播,
            接收者無法終止廣播,  即無法阻止其他接收者的接收動作。
            sendBroadcast(intent);
            abortBroadcast();
    有序廣播:
        它每次只發(fā)送到優(yōu)先級較高的接收者那里,然后由優(yōu)先級高的接受者再傳播到優(yōu)先級低的接收者那里,優(yōu)先級高的接收者有能力終止這個廣播
        sendOrderedBroadcast(intent, "george.permission.MY_BROADCAST_PERMISSION");
                參數(shù)中有個權限,所以
                        在AndroidMainfest.xml中定義一個權限:
                            <permission android:protectionLevel="normal"
                                            android:name="george.permission.MY_BROADCAST_PERMISSION" />
                        
                        如果要發(fā)送廣播,必須要獲取到這個權限:
                            <uses-permission android:name="george.permission.MY_BROADCAST_PERMISSION" />

過濾器的配置:
        1,靜態(tài):在AndroidManifest.xml文件中配置,這種方式的注冊是常駐型的,也就是說當應用關閉后,
                        如果有廣播信息傳來,MyBroadCastReceiver也會被系統(tǒng)調用而自動運行

                <receiver android:name="com.hq.component.broadcast.MyBroadCastReceiver" >
                    <intent-filter android:priority="999" >
                        <action android:name="broadcast.MyBroadCastReceiver" />

                        <category android:name="android.intent.category.DEFAULT" />
                    </intent-filter>
                </receiver>
        2,動態(tài):在代碼中動態(tài)的指定廣播地址并注冊,通常我們是在Activity或Service注冊一個廣播
                    不是常駐型的,也就是說廣播會跟隨程序的生命周期

                private ThirdBroadCastReceiver receiver = null;
                //新建一個廣播接收器
                receiver = new ThirdBroadCastReceiver();
                //新建一個過濾器
                IntentFilter filter = new IntentFilter();
                filter.addAction("broadcast.MyBroadCastReceiver");
                filter.setPriority(997);
                //為廣播接受器注冊一個過濾器
                registerReceiver(receiver, filter);


廣播的接收:
        普通廣播:
                intent.getExtras();
        有序廣播:
                接受
                    String extraStr = getResultExtras(true).getString("passMsg");
                繼續(xù)傳播:
                    // 給下個廣播接受者傳遞廣播
                    Bundle bundle = new Bundle();
                    bundle.putString("passMsg", intentStr + "from @SecondBroadCastReceiver");
                    setResultExtras(bundle);
                停止傳播:
                    abortBroadcast();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容