Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android四大組件--android service詳解

android四大組件--android service詳解

編輯:關於Android編程

一、android service簡介

1、Android中的服務和windows中的服務是類似的東西,服務一般沒有用戶操作界面,它運行於系統中不容易被用戶發覺,可以使用它開發如監控之類的程序。

2、在Android中,Activity主要負責前台頁面的展示,Service主要負責需要長期運行的任務。例如,一個從service播放音樂的音樂播放器,應被設置為前台運行,因為用戶會明確地注意它的運行.在狀態欄中的通知可能會顯示當前的歌曲並且允許用戶啟動一個activity來與音樂播放器交互。

3、在我們實際開發中,就會常常遇到Activity與Service之間的通信,我們一般在Activity中啟動後台Service,通過Intent來啟動,Intent中我們可以傳遞數據給Service,而當我們Service執行某些操作之後想要更新UI線程,我們應該怎麼做呢?接下來我就介紹兩種方式來實現Service與Activity之間的通信問題。

二.Android Service的實現
服務主要有以下兩種形式:
1. Start
通過調用應用程序組件(例如Activity)的startService()方法來啟動一個服務.一旦啟動,服務就會在後台一直運行,即使應用程序組件此時被關閉.通常,已經啟動的服務會處理一些單一功能,並且也不需要返回結果給調用者.例如,在網絡上下載或上傳文件.當服務的工作處理結束,才會自己關閉服務.
2. Bound
通過調用應用程序組件的bindService()方法來綁定一個服務.已綁定的服務會提供一個客戶端-服務端交互接口.該接口主要用來與應用程序交互,發送請求,獲取結果,甚至通過IPC來訪問進程.只要一個程序組件綁定服務就會運行綁定服務,多個應用程序組件可以同時時間綁定一個服務.當所有的應用程序組件都解除綁定,該綁定服務器就會被銷毀.
下面我們分別對"Started Service"和"Bound Servie"作一個介紹.

三、創建和配置service

1、要創建一個service,你必須創建一個Service類(或某個已存在的子類)的子類.在你的實現中,你應覆寫一些處理有關service生命期的關鍵方面的回調方法並且提供一個能讓組件綁定到service的機制(如果需要).你應覆寫的最重要的回調方法是:


onStartCommand()
  系統在其它組件比如activity通過調用startService()請求service啟動時調用這個方法.一旦這個方法執行,service就啟動並且在後台長期運行.如果你實現了它,你需要負責在service完成任務時停止它,通過調用stopSelf()或stopService().(如果你只想提供綁定,你不需實現此方法).


OnBind()
  當組件調用bindService()想要綁定到service時(比如想要執行進程間通訊)系統調用此方法.在你的實現中,你必須提供一個返回一個IBinder來以使客戶端能夠使用它與service通訊,你必須總是實現這個方法,但是如果你不允許綁定,那麼你應返回null.


OnCreate()
  系統在service第一次創建時執行此方法,來執行只運行一次的初始化工作(在調用它方法如onStartCommand()或onBind()之前).如果service已經運行,這個方法不會被調用.


OnDestroy()
  系統在service不再被使用並要銷毀時調用此方法.你的service應在此方法中釋放資源,比如線程,已注冊的偵聽器,接收器等等.這是service收到的最後一個調用.
  如果一個組件通過調用startService()啟動一個service(最終導致onStartCommand()被調用),之後service會保持運行,直到它通過stopSelf()停止自己或另外的組件調用stopService()停止它.

  如果一個組件調用bindService()來創建service(onStartCommand()不會被調用),那麼service只是運行在綁定期間.一旦service從所有的客戶端解除綁定,系統就會殺了它.

2、在manifest中聲明一個service
  跟activity以及其它組件一樣,你必須在你的應用的manifest文件中聲明所有的service.
  要聲明你的service,添加一個元素作為元素的兒子.例如:

  
  ...  
    
        
      
                
                
       
    
 
PS:

就像一個activity,一個service可以定義intent過濾器來使得其它組件使用明確的intent調用自己.通過聲明intent過濾器,你設備上的任意應用中的組件都可以通過給startService()傳遞匹配的intent來啟動你的sevice.
如果你打算只在本應用內使用自己的service,那麼你不需指定任何intent過濾器.不使用intent過濾器,你必須使用一個明確指定service的類名的intent來啟動你的service.
3、開始一個Service

服務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啟動服務。這兩個方法都可以啟動Service,但是它們的使用場合有所不同。

使用startService()方法啟用服務,訪問者與服務之間沒有關連,即使訪問者退出了,服務仍然運行。

使用bindService()方法啟用服務,訪問者與服務綁定在了一起,訪問者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點。

采用Context.startService()方法啟動服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。

如果service沒有提供綁定功能,傳給startService()的intent是應用組件與service之間唯一的通訊方式.然而,如果你希望service回發一個結果,那麼啟動這個service的客戶端可以創建一個用於廣播(使用getBroadcast())的PendingIntent然後放在intent中傳給service,service然後就可以使用廣播來回送結果.

PS:兩種方式啟動服務的區別:

通過startService()和stopService()啟動關閉服務。適用於服務和訪問者之間沒有交互的情況。如果服務和訪問者之間需要方法調用或者傳遞參數,側需要使用bindService()和unbindService()方法啟動關閉服務。

采用Context.bindService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接著調用onBind()方法,這個時候訪問者和服務綁定在一起。

如果訪問者要與服務進行通信,那麼,onBind()方法必須返回Ibinder對象。如果訪問者退出了,系統就會先調用服務的onUnbind()方法,接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法並不會導致多次創建服務及綁定(也就是說onCreate()和onBind()方法並不會被多次調用)。如果訪問者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()-->onDestroy()方法。

4、停止一個service

一個"啟動的"service必須管理其自己的生命期.這表示,系統不會停止或銷毀這種service,除非內存不夠用了並且service在onStartCommand()返回後會繼續運行.所以,service必須調用stopSelf()停止自己或由另一個組件調用stopService()來停止它.

  一旦通過stopSelf()或stopService()發出了停止請求,系統就會盡可能快地銷毀service.

  然而,同時使用 startService 與 bindService 要注意到,Service 的終止,需要unbindService與stopService同時調用,才能終止 Service,不管 startService 與 bindService 的調用順序,如果先調用 unbindService 此時服務不會自動終止,再調用 stopService 之後服務才會停止,如果先調用 stopService 此時服務也不會終止,而再調用 unbindService 或者 之前調用 bindService 的 Context 不存在了(如Activity 被 finish 的時候)之後服務才會自動停止;

  注意:你的應用在完成工作後停止它所有的service是非常重要的.這可以避免浪費系統資源和消耗電量.如果需要,其它的組件可以調用stopService()停止service.即使你為service啟用了綁定,你也必須自己停止service,甚至它收到了對onStartCommand()的調用也這樣.


四、服務的生命周期回調方法

服務的生命周期跟啟動服務的方法有關:
1、當采用Context.startService()方法啟動服務,與之有關的生命周期方法
onCreate()--> onStart()--> onDestroy()
onCreate()該方法在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()或bindService()方法,服務也只被創建一次。
onStart() 只有采用Context.startService()方法啟動服務時才會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方法盡管不會多次創建服務,但onStart() 方法會被多次調用。
onDestroy()該方法在服務被終止時調用。

2、 當采用Context.bindService()方法啟動服務,與之有關的生命周期方法
onCreate()--> onBind() --> onUnbind() --> onDestroy()
onBind()只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。
onUnbind()只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務解除綁定時被調用。

如果先采用startService()方法啟動服務,然後調用bindService()方法綁定到服務,再調用unbindService()方法解除綁定,最後調用bindService()方法再次綁定到服務,觸發的生命周期方法如下:
onCreate()-->onStart()-->onBind()-->onUnbind()[重載後的方法需返回true-->onRebind()

下面這張流程圖很好的诠釋了"startService()"和"bindService()"兩個方法調用的生命周期。

\


PS:

一個service的生命期比一個activity要簡單得多.然而,你依然需要密切關注你的service是如何被創建又是如何被銷毀的,因為一個service可以運行於後台而用戶看不到它.
 service的生命期—從它被創建到它被銷毀—有兩條路可走:

一個"啟動的"service
  在其它組件調用startService()時創建.然後service就長期運行並且必須調用stopSelf()自己停止自己.另一個組件也可以調用stZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcFNlcnZpY2UoKcC0zaPWucv8o661sXNlcnZpY2XNo9a5uvOjrM+1zbO+zc/6u9nL/KOuPGJyPgo8YnI+CtK7uPaw87aotcRzZXJ2aWNlPGJyPgqhoaGhtbHB7dK7uPbX6bz+KNK7uPa/zbuntssptffTw2JpbmRTZXJ2aWNlKCnKsbS0vaijrsi7uvO/zbuntsvNqLn90ru49klCaW5kZXK907/a0+tzZXJ2aWNlzajQxaOuv827p7bLv8nS1LX308N1bmJpbmRTZXJ2aWNlKCnNo9a5zajQxaOutuC49r/Nu6e2y7/J0tSw87aotb3NrNK7uPZzZXJ2aWNlsqLH0rWxy/nT0LXEv827p7bLtry94rP9sPO2qLrzo6zPtc2zvs3P+rvZtfTV4rj2c2VydmljZaOuKHNlcnZpY2Wyu9DozaPWudfUvLqjrik8YnI+Cjxicj4KoaGhodXiwb3M9cK3sqKyu8rHzerIq7fWwOu1xKOu0rK+zcrHo6zE48rHv8nS1LDztqi1vdPDc3RhcnRTZXJ2aWNlKCnG9LavtcRzZXJ2aWNltcSjrsD9yOejrNK7uPa688yo0vTA1nNlcnZpY2XU2s2ouf20q8jr1rjD99KqsqW3xbXE0vTA1rXEaW50ZW50wLS199PDc3RhcnRTZXJ2aWNlKCm688b0tq+jrtauuvOjrLWx08O7p8/rttSypbfFxve9+NDQ0rvQqbLZ1/e78tKqu/HIobWxx7C46Mf6tcTQxc+iyrGjrNK7uPZhY3Rpdml0eb/J0tTNqLn9tffTw2JpbmRTZXJ2aWNlKCmw87aotb1zZXJ2aWNlo67U2rTLx+m/9s/Co6xzdG9wU2VydmljZSgpu/JzdG9wU2VsZigpsru74dXm1f21xM2j1rlzZXJ2aWNlo6yz/bfHy/nT0LXEv827p7bLtrzIoc/7sPO2qMHLo648YnI+CjwvcD4KPHA+PGJyPgo8L3A+CjxwPjxzdHJvbmc+zuWhorS0vajSu7j2sPO2qLXEU2VydmljZTwvc3Ryb25nPjwvcD4KPHA+MaGi0qq0tL2o0ru49rDztqi1xHNlcnZpY2WjrMTjsdjQ68q1z9a72LX3t723qG9uQmluZCgpo6y7udKq1NrG5NbQt7W72NK7uPZJQmluZGVyo6zV4rj2SUJpbmRlcrao0uXBy9Prc2VydmljZc2o0ba1xL3Tv9qjrsbky/zTptPD1+m8/r7Nv8nS1NTa1q6687X308NiaW5kU2VydmljZSgpwLS908rV1eK49r3Tv9qyor+qyry199PDc2VydmljZbXEt723qKOuc2VydmljZda71NrT0NOm08PX6bz+sPO2qLW9y/zKsbLFu+7XxaOsy/nS1LWxw7vT0NfpvP6w87aotb3L/Mqxo6zPtc2zvs274WtpbGzL/CjE47K70OjIpc2j1rnSu7j2sPO2qLXEc2VydmljZaOsuPrTw29uU3RhcnRDb21tYW5kKCnG9LavtcRzZXJ2aWNlsrvSu9H5KaOuPGJyPgoyoaLSqrS0vajSu7j2sPO2qLXEc2VydmljZaOsytfPyNKq1/a1xL7Nyse2qNLlv827p7bLyOe6ztPrc2VydmljZc2o0ba1xL3Tv9qjrtXiuPa907/asdjQ68rHSUJpbmRlcrXE0ru49sq1z9ajrLKix9Kx2NDrsbu72LX3t723qG9uQmluZCgpt7W72KOu0ru1qb/Nu6e2y73TytW1vUlCaW5kZXKjrMv8vs2/ydLUv6rKvNPrc2VydmljZb340NC9u7ulo648YnI+CjOhorbguPa/zbuntsu/ydLU0rvG8LDztqi1vdK7uPZzZXJ2aWNlo661sdK7uPa/zbuntsvN6rPJ0+tzZXJ2aWNltcS9u7ulo6zL/LX308N1bmJpbmRTZXJ2aWNlKCnAtL3is/2w87aoo67Su7WpsrvU2dPQyM66zr/Nu6e2y7Dztqi1vXNlcnZpY2WjrM+1zbO+zWtpbGzV4rj2c2VydmljZaOuPC9wPgo8cD7PwsPmysfI57rOvajBosv8o7o8YnI+Cjxicj4KMaGi1NrE47XEc2VydmljZdbQo6y0tL2o0ru49kJpbmRlcsq1wP2jrMzhuanS1M/CyP3W1rmmxNzWrtK7o7o8YnI+Cjxicj4KICAgQmluZGVysPy6rNK70Km/ybmpv827p7bLtffTw7XEuau/qre9t6ijrjxicj4KPGJyPgogICC3tbvYtbHHsLXEU2VydmljZcq1wP2jrMv8vt/T0NK70Km/zbuntsu/ydLUtffTw7XEuau/qre9t6ijrjxicj4KPGJyPgogICC78tXfo6y3tbvYwe3Su7j2wOC1xMq1wP2jrNXiuPbA4L7f09C/zbuntsu/ybX308O1xLmrv6q3vbeosqLN0Lnc09pzZXJ2aWNlo648YnI+Cjxicj4KMqGi1Nq72LX3t723qG9uQmluZCgp1tC3tbvY1eK49kJpbmRlcrXEyrXA/aOuPGJyPgo8YnI+CjOhotTav827p7bLo6y007vYtfe3vbeob25TZXJ2aWNlQ29ubmVjdGVkKCnW0L3TytXV4rj2QmluZGVysqLKudPDo7HW0Mv5yva1xLmrv6q3vbeotffTw7DztqhzZXJ2aWNlo648YnI+CjwvcD4KPHA+PGJyPgo8L3A+CjxwPsD9yOejus/Cw+bV4rj2c2VydmljZczhuanIw7/Nu6e2y82ouf3Su7j2QmluZGVyyrXP1rX308NzZXJ2aWNl1tC1xLe9t6i1xLmmxNyjujwvcD4KPHByZSBjbGFzcz0="brush:java;">public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * 這裡定義吧一個Binder類,用在onBind()有方法裡,這樣Activity那邊可以獲取到 * 在 Local Service 中我們直接繼承 Binder 而不是 IBinder,因為 Binder 實現了 IBinder 接口,這樣我們可以少做很多工作。 */ public class LocalBinder extends Binder { LocalService getService() { // 返回本service的實例到客戶端,於是客戶端可以調用本service的公開方法 return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /**客戶端所要調用的方法*/ public int getRandomNumber() { return mGenerator.nextInt(100); } }下面是一個綁定到LocalService並且在按鈕按下時調用getRandomNumber()的actvity的例子:

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // 綁定到類LocalService的實例
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 從service解除綁定
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** 當按鈕按下時調用(在layout文件中定義的button並用android:onClick 屬性指定響應到本方法) */
    public void onButtonClick(View v) {
        if (mBound) {
            // 調用LocalService的一個方法
            // 然而,如果這個調用中有掛起操作,那麼這個請求應發
            // 生在另一個線程來避免拉低activity的性能.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** 定義service綁定的回調,傳給bindService() 的*/
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            //我們已經綁定到了LocalService,把IBinder進行強制類型轉換並且獲取LocalService實例.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}
上面的例子展示了客戶端如何使用一個ServiceConnection的實例和onServiceConnected()方法綁定到service.

PS:

1、應用組件(客戶端)可以調用bindService()綁定到一個service.Android系統之後調用service的onBind()方法,它返回一個用來與service交互的IBinder.

2、綁定是異步的.bindService()會立即返回,它不會返回IBinder給客戶端.要接收IBinder,客戶端必須創建一個ServiceConnection的實例並傳給bindService().ServiceConnection包含一個回調方法,系統調用這個方法來傳遞要返回的IBinder.

3、從你的客戶端綁定到一個service,你必須:

1)實現ServiceConnection.
你的實現必須重寫兩個回調方法:
onServiceConnected()
系統調用這個來傳送在service的onBind()中返回的IBinder.
OnServiceDisconnected()
Android系統在同service的連接意外丟失時調用這個.比如當service崩潰了或被強殺了.當客戶端解除綁定時,這個方法不會被調用.
2)調用bindService(),傳給它ServiceConnection的實現.
3)當系統調用你的onServiceConnected()方法時,你就可以使用接口定義的方法們開始調用service了.
4)要與service斷開連接,調用unbindService().
  當你的客戶端被銷毀,它將從service解除綁定,但是你必須總是在你完成與service的交互時或當你的activity暫停於是service在不被使用時可以關閉此兩種情況下解除綁定.(下面會討論更多在適當的時候綁定和解除綁定的問題.

4、使用這個ServiceConnection,客戶端可以綁定到一個service,通過把它傳給bindService().例如:

Intentintent = new Intent(this, LocalService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

第一個bindService()的參數是一個明確指定了要綁定的service的Intent.

第二個參數是ServiceConnection對象.

第三個參數是一個標志,它表明綁定中的操作.它一般應是BIND_AUTO_CREATE,這樣就會在service不存在時創建一個.其它可選的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定時設為0即可.


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved