亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android中bindService基本使用方法概述

2020-04-11 11:11:07
字體:
來源:轉載
供稿:網友

Android中有兩種主要方式使用Service,通過調用Context的startService方法或調用Context的bindService方法,本文只探討純bindService的使用,不涉及任何startService方法調用的情況。如果想了解startService相關的使用,請參見《Android中startService基本使用方法概述》。

bindService啟動服務的特點

相比于用startService啟動的Service,bindService啟動的服務具有如下特點:
1. bindService啟動的服務在調用者和服務之間是典型的client-server的接口,即調用者是客戶端,service是服務端,service就一個,但是連接綁定到service上面的客戶端client可以是一個或多個。這里特別要說明的是,這里所提到的client指的是組件,比如某個Activity。
2. 客戶端client(即調用bindService的一方,比如某個Activity)可以通過IBinder接口獲取Service的實例,從而可以實現在client端直接調用Service中的方法以實現靈活的交互,并且可借助IBinder實現跨進程的client-server的交互,這在純startService啟動的Service中是無法實現的。
3. 不同于startService啟動的服務默認無限期執行(可以通過Context的stopService或Service的stopSelf方法停止運行),bindService啟動的服務的生命周期與其綁定的client息息相關。當client銷毀的時候,client會自動與Service解除綁定,當然client也可以通過明確調用Context的unbindService方法與Service解除綁定。當沒有任何client與Service綁定的時候,Service會自行銷毀(通過startService啟動的除外)。
4. startService和bindService二者執行的回調方法不同:startService啟動的服務會涉及Service的的onStartCommand回調方法,而通過bindService啟動的服務會涉及Service的onBind、onUnbind等回調方法。

bindService代碼示例

使用bindService主要分兩種情形:
1. Service的調用者client與Service在同一個App中;
2. Service的調用者client是App1中的一個Activity,而Service是App2中的Service,client與service分屬兩個App,這種情形下主要用于實現跨進程的通信。

為了簡單起見,本文只討論第一種情形,即Service的調用者client與Service在同一個App中,該情形也是我們在實際開發中用到最多的情形。如果想了解通過bindService在兩個不同的進程中讓客戶端與Service通信,可參見另一篇博文《Android中通過Messenger與Service實現進程間雙向通信》。

下面我們通過一個例子演示一下第一種情形下bindService的基本使用流程。

首先我們有一個TestService,該類繼承自Service,其是client-server接口中的server端。我們在其主要的生命周期回調方法中都加入了輸出語句。TestService代碼如下:

 

package com.ispring.startservicedemo;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;import java.util.Random;public class TestService extends Service {  public class MyBinder extends Binder{    public TestService getService(){      return TestService.this;    }  }  //通過binder實現調用者client與Service之間的通信  private MyBinder binder = new MyBinder();  private final Random generator = new Random();  @Override  public void onCreate() {    Log.i("DemoLog","TestService -> onCreate, Thread: " + Thread.currentThread().getName());    super.onCreate();  }  @Override  public int onStartCommand(Intent intent, int flags, int startId) {    Log.i("DemoLog", "TestService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());    return START_NOT_STICKY;  }  @Override  public IBinder onBind(Intent intent) {    Log.i("DemoLog", "TestService -> onBind, Thread: " + Thread.currentThread().getName());    return binder;  }  @Override  public boolean onUnbind(Intent intent) {    Log.i("DemoLog", "TestService -> onUnbind, from:" + intent.getStringExtra("from"));    return false;  }  @Override  public void onDestroy() {    Log.i("DemoLog", "TestService -> onDestroy, Thread: " + Thread.currentThread().getName());    super.onDestroy();  }  //getRandomNumber是Service暴露出去供client調用的公共方法  public int getRandomNumber(){    return generator.nextInt();  }}

在該App中,除了TestService,還有兩個Activity: ActivityA和ActivityB,它們都是Service的調用者,即client-server接口中的client。

ActivityA是App的啟動界面,界面如下:

ActivityA的代碼如下:

package com.ispring.startservicedemo;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;public class ActivityA extends Activity implements Button.OnClickListener {  private TestService service = null;  private boolean isBound = false;  private ServiceConnection conn = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder binder) {      isBound = true;      TestService.MyBinder myBinder = (TestService.MyBinder)binder;      service = myBinder.getService();      Log.i("DemoLog", "ActivityA onServiceConnected");      int num = service.getRandomNumber();      Log.i("DemoLog", "ActivityA 中調用 TestService的getRandomNumber方法, 結果: " + num);    }    @Override    public void onServiceDisconnected(ComponentName name) {      isBound = false;      Log.i("DemoLog", "ActivityA onServiceDisconnected");    }  };  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_a);    Log.i("DemoLog", "ActivityA -> onCreate, Thread: " + Thread.currentThread().getName());  }  @Override  public void onClick(View v) {    if(v.getId() == R.id.btnBindService){      //單擊了“bindService”按鈕      Intent intent = new Intent(this, TestService.class);      intent.putExtra("from", "ActivityA");      Log.i("DemoLog", "----------------------------------------------------------------------");      Log.i("DemoLog", "ActivityA 執行 bindService");      bindService(intent, conn, BIND_AUTO_CREATE);    }else if(v.getId() == R.id.btnUnbindService){      //單擊了“unbindService”按鈕      if(isBound){        Log.i("DemoLog", "----------------------------------------------------------------------");        Log.i("DemoLog", "ActivityA 執行 unbindService");        unbindService(conn);      }    }else if(v.getId() == R.id.btnStartActivityB){      //單擊了“start ActivityB”按鈕      Intent intent = new Intent(this, ActivityB.class);      Log.i("DemoLog", "----------------------------------------------------------------------");      Log.i("DemoLog", "ActivityA 啟動 ActivityB");      startActivity(intent);    }else if(v.getId() == R.id.btnFinish){      //單擊了“Finish”按鈕      Log.i("DemoLog", "----------------------------------------------------------------------");      Log.i("DemoLog", "ActivityA 執行 finish");      this.finish();    }  }  @Override  protected void onDestroy() {    super.onDestroy();    Log.i("DemoLog", "ActivityA -> onDestroy");  }}

通過單擊ActivityA上的“start ActivityB”可以啟動ActivityB,ActivityB的界面如下:

ActivityB的代碼如下:

package com.ispring.startservicedemo;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;public class ActivityB extends Activity implements Button.OnClickListener {  private TestService service = null;  private boolean isBound = false;  private ServiceConnection conn = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder binder) {      isBound = true;      TestService.MyBinder myBinder = (TestService.MyBinder)binder;      service = myBinder.getService();      Log.i("DemoLog", "ActivityB onServiceConnected");      int num = service.getRandomNumber();      Log.i("DemoLog", "ActivityB 中調用 TestService的getRandomNumber方法, 結果: " + num);    }    @Override    public void onServiceDisconnected(ComponentName name) {      isBound = false;      Log.i("DemoLog", "ActivityB onServiceDisconnected");    }  };  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_b);  }  @Override  public void onClick(View v) {    if(v.getId() == R.id.btnBindService){      Intent intent = new Intent(this, TestService.class);      intent.putExtra("from", "ActivityB");      Log.i("DemoLog", "----------------------------------------------------------------------");      Log.i("DemoLog", "ActivityB 執行 bindService");      bindService(intent, conn, BIND_AUTO_CREATE);    }else if(v.getId() == R.id.btnUnbindService){      if(isBound){        Log.i("DemoLog", "----------------------------------------------------------------------");        Log.i("DemoLog", "ActivityB 執行 unbindService");        unbindService(conn);      }    }else if(v.getId() == R.id.btnFinish){      //單擊了“Finish”按鈕      Log.i("DemoLog", "----------------------------------------------------------------------");      Log.i("DemoLog", "ActivityB 執行 finish");      this.finish();    }  }  @Override  public void onDestroy(){    super.onDestroy();    Log.i("DemoLog", "ActivityB -> onDestroy");  }}

我們暫時不點擊上面的按鈕,先看一下TestService和ActivityA的代碼。

調用者(客戶端client)要想和Service進行交互,那么Service和調用者必須都要做好準備。

我們先看Service要做的工作
使用bindService將client與server聯系在一起的關鍵是binder,在TestService中,我們在其中寫了一個內部類MyBinder,該類有個公共方法getService,通過該方法我們可以獲取包含MyBinder的TestService。如果想要自己的Service支持bindService啟動方式,就必須在Service的onBind中返回一個IBinder類型的實例。在示例中,我們實例化了一個MyBinder的實例binder作為TestService的字段,并且將其作為onBind的返回值。
我們總結一下如果想讓Service支持bindService調用方式,Service需要做以下事情:
1. 在Service的onBind方法中返回IBinder類型的實例。
2. onBind方法返回的IBinder的實例需要能夠返回Service實例本身或者通過binder暴露出Service公共方法。通常情況下,最簡單明了的做法就是將binder弄成Service的內部類,然后在binder中加入類似于getService之類的方法返回包含binder的Service,這樣client可以通過該方法得到Service實例。

我們已經知道了Service需要做的事情,我們接下來看一下調用者需要做的工作。
在我們的示例中,調用者(也就是客戶端client)是ActivityA,我們在其中初始化了一個ServiceConnection類型的實例,需要重寫其onServiceConnected方法以及onServiceDisconnected方法。我們需要將這個ServiceConnection類型的實例作為參數傳給bindService方法,當Service還沒有創建的時候,Android會先創建Service的實例,然后執行Service的onBind方法,得到IBinder類型的實例,將該方法作為參數傳入client端的ServiceConnection的onServiceConnected方法中,onServiceConnected方法的執行表明client端可以獲取到Service的IBinder類型的實例,然后將IBinder轉換為自己實際的Binder類型,然后可以通過其直接獲取Service的實例或者通過Binder直接執行公共方法,這取決于Service中Binder的具體實現。在本例中,在onServiceConnected方法中,調用者ActivityA通過binder的getService方法獲取到了與其對應的Service,然后我們就可以直接調用Service的公共方法以達到使用Service的目的,這樣client與Service之間就通過IBinder建立了連接,從而進行交互。當client與Service失去連接時會觸發onServiceDisconnected方法。
我們總結一下client端要做的事情:
1. 創建ServiceConnection類型的實例,并重寫其onServiceConnected方法和onServiceDisconnected方法。
2. 當Android執行onServiceConnected回調方法時,我們可以通過IBinder實例得到Service的實例對象或直接調用binder的公共方法,這樣就實現了client與Service的連接。
3. 當Android執行onServiceDisconnected回調方法時,表示client與Service之間斷開了連接,我們在此處要寫一些斷開連接后需要做的處理。

在知道了如何讓client與Service進行交互之后,我們運行我們的App,觀察各個回調方法的執行過程,我們有三個測試流程。

測試流程A

該測試涉及到ActivityA,但不涉及ActivityB.
首先我們點擊ActivityA中的“bindService”按鈕,然后點擊”unbindService”按鈕,輸出結果如下所示:

首先,通過上面的代碼我們可以看到Service中執行的回調方法都是執行在主線程中的。
當我們調用bindService方法時,我們需要將Intent、ServiceConnection等實例傳入,Intent包含了我們要綁定的Service,ServiceConnection我們在上面提到過,實現了其onServiceConnected方法和onServiceDisconnected方法。 在調用了bindService之后,由于Service此時還不存在,那么Android就會首先創建一個TestService的實例,并執行其onCreate回調方法,onCreate方法在其生命周期中只會被調用一次。然后會調用Service的onBind方法,該方法只有在第一次bindService調用后才會執行,onBind執行后會返回一個IBinder類型的實例,此時Android會將該IBinder實例存起來,這個IBinder實例是對所有client共享的。當下次其他的client執行bindService的時候,不會再執行onBind方法,因為我們之前已經得到了一個IBinder實例,Android會直接使用這個IBinder實例。 在得到了IBinder實例之后,Android會執行client端ServiceConnection中的onServiceConnected方法,在該方法中我們會得到IBinder實例,并通過該IBinder實例得到了TestService實例,這樣我們的客戶端ActivityA就通過IBinder與TestService建立了連接,我們就可以調用TestService的公共方法,比如調用其getRandomNumber方法獲得隨機數。

總結一下調用bindService之后發生的事情:
client 執行 bindService ->
如果Service不存在,Service 執行 onCreate ->
如果沒有執行過onBind,Service 執行 onBind ->
client的實例ServiceConnection 執行 onServiceConnected

在執行了bindService之后,一共有一個client連接到了TestService,即ActivityA,每次client在調用了unbindService方法之后,該client會與Service解除綁定,在與某個client解除綁定之后,Service會檢測是否還有其他的client與其連接綁定,如果沒有其他任何client與其處于連接狀態,那么Service會執行onUnbind方法,然后執行onDestroy方法,最終銷毀自己。當ActivityA執行unbindService的時候,唯一的一個client與TestService解除了綁定的關系,TestService就執行了onUnbind方法,進而執行onDestroy方法。

總結一下調用unbindService之后發生的事情:
client 執行 unbindService ->
client 與 Service 解除綁定連接狀態 ->
Service 檢測是否還有其他client與其連接,如果沒有 ->
Service 執行onUnbind ->
Service 執行onDestroy

測試流程B

我們在測試完第一種流程后,關掉App,重啟App,進行第二種測試流程。
該測試也只涉及ActivityA,不涉及ActivityB。首先先點擊ActivityA中的“bindService”按鈕,然后點擊”Finish”按鈕,輸出結果如下圖所示:

在該測試中,我們首先通過點擊”bindService”按鈕,使得ActivityA綁定了TestService,但是我們沒有調用unbindService,而是直接通過調用“Finish”按鈕讓ActivityA直接銷毀,通過上面的輸出結果我們可以看到,在ActivityA銷毀的時候,執行了ActivityA的onDestroy回調方法,之后TestService依次執行了onUnbind、onDestroy回調方法,TestService銷毀。client與Service通過bindService連接起來之后,如果client銷毀,那么client會自動與Service解除綁定,相當于在destroy之前會執行unbindService,在ActivityA銷毀之后,ActivityA與Service解除了綁定,此時再沒有client與Service處于連接綁定狀態,這樣Service就會執行onUnbind回調方法,表示沒有client和我玩了,最后執行onDestroy回調方法。

測試流程C

我們在之前的兩次測試流程中都只涉及ActivtityA,本測試流程會同時涉及ActivityA以及ActivityB。
首先關掉App,重啟App,按照以下步驟測試:
1. 點擊ActivityA中的”bindService”按鈕
2. 點擊ActivityA中的”start ActivityB”按鈕,界面切換到ActivityB
3. 點擊ActivityB中的”bindService”按鈕
4. 點擊ActivityB中的”unbindService”按鈕
5. 點擊ActivityB中的”Finish”按鈕
6. 點擊ActivityA中的”unbindService”按鈕

LogCat輸出結果如下:

下面我們依次分析每一步產生的影響,以便于完整地理解通過bindService啟動的Service的生命周期:

點擊ActivityA中的”bindService”按鈕
由于初始情況下TestService實例不存在,也就是TestService沒有運行。第一次調用bindService會實例化TestService,然后會執行其onBind方法,得到IBinder類型的實例,然后將其作為參數傳入ActivityA的ServiceConnection的onServiceConnected方法中,標志著ActivityA與TestService建立了綁定連接,此時只有ActivityA這一個客戶端client與TestService綁定。

點擊ActivityA中的”start ActivityB”按鈕,界面切換到ActivityB

點擊ActivityB中的”bindService”按鈕
由于TestService已經處于運行狀態,所以ActivityB調用bindService時,不會重新創建TestService的實例,所以也不會執行TestService的onCreate回調方法,由于在ActivityA執行bindService的時候就已經執行了TestService的onBind回調方法而獲取IBinder實例,并且該IBinder實例在所有的client之間是共享的,所以當ActivityB執行bindService的時候,不會執行其onBind回調方法,而是直接獲取上次已經獲取到的IBinder實例。并將其作為參數傳入ActivityB的ServiceConnection的onServiceConnected方法中,標志著ActivityB與TestService建立了綁定連接,此時有兩個客戶單client(ActivityA和ActivityB)與TestService綁定。

點擊ActivityB中的”unbindService”按鈕
ActivityB執行了unbindService之后,ActivityB就與TestService解除了綁定。當沒有任何client與Service處于綁定連接狀態的時候,TestService才會執行onUnbind方法、onDestroy方法。但是由于此時還有ActivityA這個client與TestService處于綁定連接中,所以不會執行Service的onBind及onDestroy回調方法。

點擊ActivityB中的”Finish”按鈕
執行了ActivityB的finish方法后,ActivityB銷毀了,界面返回到ActivityA

點擊ActivityA中的”unbindService”按鈕
ActivityA執行unbindService之后,ActivityA與TestService就解除綁定了,這樣就沒有客戶端client與TestService相連,這時候Android會銷毀TestService,在銷毀前會先執行TestService的onUnbind方法,然后才會執行其onDestroy方法,這樣TestService就銷毀了。

bindService生命周期流程圖

這里特別要說明的是,本文所提到的client指的是組件Component,比如某個Activity。如果在某一個Activity中,多次調用bindService方法連接Service,那么對于Service來說,這個Activity也只是一個client,而不是多個client。

最后我們將bindService啟動的Service的生命周期總結為如下的流程圖:

希望本文對大家了解bindService的使用有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美黑人国产人伦爽爽爽| 26uuu日韩精品一区二区| 国产主播喷水一区二区| 精品中文字幕在线观看| 疯狂欧美牲乱大交777| 精品露脸国产偷人在视频| 成人免费高清完整版在线观看| 亚洲成人激情在线观看| 日韩激情第一页| 国产精品视频yy9099| 狠狠久久亚洲欧美专区| 国产精品91在线| 伊人一区二区三区久久精品| 亚洲aaaaaa| 国产精品久久久久77777| 久久久久久久久久久网站| 国产最新精品视频| 国产乱人伦真实精品视频| 国产精品一区二区久久精品| 最近2019年手机中文字幕| 欧美日韩激情网| 欧美精品videosex极品1| 国外成人性视频| 国产精品久久久久久亚洲调教| 欧美精品xxx| 国产精欧美一区二区三区| 久久激情视频久久| 国内精品久久影院| 中文日韩电影网站| 97国产成人精品视频| 亚洲欧洲日产国产网站| 国产精品爽爽爽爽爽爽在线观看| 亚洲美女久久久| 久久人91精品久久久久久不卡| 亚洲欧美成人网| 成人黄在线观看| 欧美亚洲伦理www| 国产精品美女主播在线观看纯欲| 欧美第一淫aaasss性| 欧美日韩成人精品| 91探花福利精品国产自产在线| 在线观看国产欧美| 不卡在线观看电视剧完整版| 92看片淫黄大片欧美看国产片| 亚洲大胆人体视频| 色先锋资源久久综合5566| 久久影院在线观看| 成人午夜在线视频一区| 国产成+人+综合+亚洲欧美丁香花| 精品国产老师黑色丝袜高跟鞋| 亚洲尤物视频网| 亚洲欧美日韩一区在线| 国产成人短视频| 日韩精品中文字幕在线播放| 欧美电影免费播放| 亚洲精品一区在线观看香蕉| 热门国产精品亚洲第一区在线| 国产视频999| www.久久久久久.com| 国产精品久久久久免费a∨| 久青草国产97香蕉在线视频| 国产日韩中文在线| 亚洲精品资源美女情侣酒店| 久久精品国产69国产精品亚洲| 亚洲高清一区二| 91在线国产电影| 国产亚洲成av人片在线观看桃| 久久久久久久久电影| 成人97在线观看视频| 欧美激情a在线| 欧美有码在线视频| 国产精品美女视频网站| 国产精品扒开腿做| 亚洲欧美一区二区三区情侣bbw| 成人黄色激情网| 国产区亚洲区欧美区| 欧美第一淫aaasss性| 久久精品久久久久久国产 免费| 91麻豆国产精品| 美女国内精品自产拍在线播放| 欧美成人黑人xx视频免费观看| 国产欧美日韩高清| 久青草国产97香蕉在线视频| 97热精品视频官网| 日韩在线小视频| 日韩网站免费观看高清| 国产成人在线一区二区| 久久免费少妇高潮久久精品99| 亚洲а∨天堂久久精品喷水| 久久成人国产精品| 久久久久久美女| 青青精品视频播放| 久久乐国产精品| 国产精品视频免费观看www| 51视频国产精品一区二区| 2025国产精品视频| 欧美成人网在线| 国产欧美日韩亚洲精品| 91免费看片在线| 国产精品自拍偷拍| 国产精品视频白浆免费视频| 91大神福利视频在线| 日韩欧美成人网| 国产成人精品综合久久久| 欧美插天视频在线播放| 欧美激情精品久久久久久大尺度| 97视频在线观看播放| 久久精品美女视频网站| 中文字幕在线观看亚洲| 亚洲精品国精品久久99热一| 中文欧美日本在线资源| 欧美日韩免费观看中文| 一区二区三区在线播放欧美| 成人在线视频福利| 性亚洲最疯狂xxxx高清| 国产精品aaaa| 中文字幕自拍vr一区二区三区| x99av成人免费| 中文字幕亚洲二区| 亚洲欧美激情精品一区二区| 亚洲精品美女在线| 国产亚洲欧洲黄色| 国产三级精品网站| 国产精品青青在线观看爽香蕉| 亚洲综合视频1区| 亚洲美女视频网站| 日韩av电影手机在线观看| 亚洲精品有码在线| 日韩在线观看网站| 久久久久久久激情视频| 97在线视频国产| 九九热在线精品视频| 久久人人爽人人爽爽久久| 91香蕉电影院| 亚洲美女视频网站| 亚洲性夜色噜噜噜7777| 亚洲国产精久久久久久久| 亚洲精品视频中文字幕| 亚洲人在线观看| 亚洲最大福利视频网站| 97**国产露脸精品国产| 欧美另类极品videosbest最新版本| 成人免费看片视频| xvideos亚洲人网站| 日韩亚洲综合在线| 国产精品一区二区av影院萌芽| 国产91精品在线播放| 日韩在线www| 成人啪啪免费看| 一区二区三区四区视频| 国产成人免费av电影| 国产精品极品美女粉嫩高清在线| 伊人亚洲福利一区二区三区| 亚洲午夜未删减在线观看| 清纯唯美日韩制服另类| 成人黄色av网| 精品国产一区二区三区久久狼黑人| 91爱爱小视频k| 欧美超级免费视 在线| 一区二区三区视频观看| 国产精品久久久久久久久久久久久| 欧美日韩在线另类| 国产精品爱啪在线线免费观看| 国产成人精品午夜|