Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中Service使用bindService

Android中Service使用bindService

編輯:關於Android編程

前面已經對Service的startServer方式啟動一個服務了解過了,現在來看一下Service的另一種啟動方式→bindServer

bindServer使用場景

1、在同個app之間調用(即是同一個進程中)

2、在不同app之間調用(即是跨進程間通信)

 

同個app間調用(只有一次啟動該服務)

BinderActicityA

 

public class BinderActicityA extends Activity implements View.OnClickListener {
    private Button btn1;
    private Button btn2;
    private Button btn3;
    private Button btn4;
    private BindService bindService = null;
    private boolean isBound = false;

    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isBound = true;
            BindService.MyBinder binder = (BindService.MyBinder) service;
            bindService = binder.getService();
            int num = bindService.getRandomNumber();
            Log.v("hjz","numA="+num);
        }

        //client 和service連接意外丟失時,會調用該方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v("hjz","onServiceDisconnected  A");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder_main);
        findLayoutView();
        setLister();
        initData();

    }

    private void findLayoutView() {
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);
        btn3 = (Button) findViewById(R.id.btn3);
        btn4 = (Button) findViewById(R.id.btn4);
    }

    private void setLister() {
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn3.setOnClickListener(this);
        btn4.setOnClickListener(this);
    }

    private void initData() {

    }

    @Override
    public void onClick(View v) {
        Intent intent = null;
        switch (v.getId()){
            case R.id.btn1:
                intent = new Intent(BinderActicityA.this, BindService.class);
                intent.putExtra("from", "ActivityA");
                bindService(intent,conn,BIND_AUTO_CREATE);
                break;
            case R.id.btn2:
                if (isBound){
                    isBound = false;
                    Log.v("hjz","ActicityA is unbindService");
                    unbindService(conn);
                }
                break;
            case R.id.btn3:
                intent = new Intent(this, BinderActivityB.class);
                startActivity(intent);
                break;
            case R.id.btn4:
                this.finish();
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i("hjz", "ActivityA -> onDestroy");
    }
}

 

xml

 


 

BinderService

 

public class BindService extends Service {

    public class MyBinder extends Binder{

        public BindService getService(){
            return BindService.this;
        }
    }
    //通過binder實現了 調用者(client)與 service之間的通信
    private MyBinder binder = new MyBinder();

    private final Random generator = new Random();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("hjz","BindService -> onCreate, Thread: " + Thread.currentThread().getName());
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("hjz", "BindService -> onBind, Thread: " + Thread.currentThread().getName());
        return binder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("hjz", "BindService -> onUnbind, from:" + intent.getStringExtra("from"));
        return false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("hjz", "BindService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.i("hjz", "BindService -> onDestroy, Thread: " + Thread.currentThread().getName());
        super.onDestroy();
    }

    //在Service中暴露出去的方法,供client調用
    public int getRandomNumber(){
        return generator.nextInt();
    }
}
\

 

點擊BinderService綁定,再點擊BinderService解綁,最後點擊finish,打印日志

 

07-09 11:46:49.360 29714-29714/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 11:46:49.360 29714-29714/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 11:46:49.380 29714-29714/com.hh.servicedemo V/hjz: numA=1859239539
07-09 11:46:50.650 29714-29714/com.hh.servicedemo V/hjz: ActicityA is unbindService
07-09 11:46:50.650 29714-29714/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 11:46:50.650 29714-29714/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main
07-09 11:46:52.290 29714-29714/com.hh.servicedemo I/hjz: ActivityA -> onDestroy

點擊BinderService綁定,再點擊finish

 

07-09 11:48:07.260 29714-29714/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 11:48:07.260 29714-29714/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 11:48:07.270 29714-29714/com.hh.servicedemo V/hjz: numA=-341510490
07-09 11:48:09.290 29714-29714/com.hh.servicedemo I/hjz: ActivityA -> onDestroy
07-09 11:48:09.310 29714-29714/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 11:48:09.310 29714-29714/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main

 

先從BinderService來分析,從打印可以看出,先調用onCreate,接著在調用onBind方法,你會發現使用binderStart來啟動,onStartCommand這方法不調用;在Service中執行順序:

1、先得到相應的binder對象,可以在Service內部用內部類得到相應的binder,如下所示:

 

 public class MyBinder extends Binder{

        public BindService getService(){
            return BindService.this;
        }
    }
    //通過binder實現了 調用者(client)與 service之間的通信
    private MyBinder binder = new MyBinder();
2、在onBind方法中返回IBinder實例,返回實例可以是Service實例本身 或者 通過binder暴露出Service公共方法。通常情況下,就是講binder弄成Service內部類,然後在binder中創建一個類似getService的方法並返回包含binder的Service對象,如上面那種情況,這樣client(客戶端)可以通過該方法得到相應的Service實例

 

接著 調用者(client客戶端)執行的流程

1、先創建ServiceConnetion實例,並重寫其方法,如下面所示:

 

//創建ServiceConnection類型的實例
    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isBound = true;
            BindService.MyBinder binder = (BindService.MyBinder) service;
            bindService = binder.getService();
            int num = bindService.getRandomNumber();
            Log.v("hjz","numA="+num);
        }

        //client 和service連接意外丟失時,會調用該方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v("hjz","onServiceDisconnected  A");
        }
    };
這是因為使用bindServer中使用到該對象,bindServer源碼

 

@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {//調用bindServer,發現第二個傳參就是ServiceConnection對象
        return mBase.bindService(service, conn, flags);
    }

2、當執行了onServiceConnected回調時,我們可以通過IBinder實例得到Service實例對象 或 直接調用binder公共方法,這樣就實現了client和service的連接

 

3、client和Service解除綁定時,onServiceDisconnected並不會被調用;onServiceDisconnected被調用的情況是發生在client和Service連接意外丟失時,這時client和Service一定是斷開連接了。

 

同個app間調用(多次調用該服務)

BinderAcivityB

 

public class BinderActivityB extends Activity implements View.OnClickListener {
    private Button btn1;
    private Button btn2;
    private Button btn4;

    private BindService bindService = null;
    private boolean isBound = false;

    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isBound = true;
            BindService.MyBinder binder = (BindService.MyBinder) service;
            bindService = binder.getService();
            int num = bindService.getRandomNumber();
            Log.v("hjz","numB="+num);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v("hjz","onServiceDisconnected  B");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder_b);
        findLayoutView();
        setLister();
        initData();

    }

    private void findLayoutView() {
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);
        btn4 = (Button) findViewById(R.id.btn4);
    }

    private void setLister() {
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn4.setOnClickListener(this);
    }

    private void initData() {

    }

    @Override
    public void onClick(View v) {
        Intent intent = null;
        switch (v.getId()){
            case R.id.btn1:
                intent = new Intent(BinderActivityB.this, BindService.class);
                intent.putExtra("from", "ActivityB");
                bindService(intent,conn,BIND_AUTO_CREATE);
                break;
            case R.id.btn2:
                if (isBound){
                    isBound = false;
                    Log.v("hjz","ActicityB is unbindService");
                    unbindService(conn);
                }
                break;
            case R.id.btn4:
                this.finish();
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i("hjz", "ActivityB -> onDestroy");
    }
}
在binderA中, 點擊 binderA綁定→跳轉BinderAcitivityB→binderB綁定→binderB解綁→BinderB finish→BinderA解綁→BinderA finish 的日志

 

 

07-09 13:16:10.030 8593-8593/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 13:16:10.030 8593-8593/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 13:16:10.050 8593-8593/com.hh.servicedemo V/hjz: numA=665064614
07-09 13:16:13.650 8593-8593/com.hh.servicedemo V/hjz: numB=1116469133
07-09 13:16:16.550 8593-8593/com.hh.servicedemo V/hjz: ActicityB is unbindService
07-09 13:16:18.680 8593-8593/com.hh.servicedemo I/hjz: ActivityB -> onDestroy
07-09 13:16:22.920 8593-8593/com.hh.servicedemo V/hjz: ActicityA is unbindService
07-09 13:16:22.930 8593-8593/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 13:16:22.950 8593-8593/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main
07-09 13:16:25.660 8593-8593/com.hh.servicedemo I/hjz: ActivityA -> onDestroy

從打印日志中發現

在client(客戶端)調用Service【同一個Service】情況下:

如果Service不存在,Service執行順序是onCreate→onBind,接著client創建ServiceConnection實例並執行onServiceConnected這個方法。

如果Service已處於運行狀態【說明在此之前已經在其他地方啟動過該Service】,由於之前執行過的onBind回調獲取IBinder實例,該IBinder實例在所有的client(客戶端)之間是共享的,所以第二次執行onBind回調,直接使用上次已經獲取的IBinder實例,並將其傳入到與之對應的onServiceConnected方法中,標志著連接已經建立了起來,這時就有兩個或者多個client(客戶端)和Service綁定了。

client(客戶端)執行unbindServie的流程:

client與Service解除綁定時,Service先檢測是否還與其他client(客戶端)與其連接→

如果沒有,Service執行onUnbind方法,然後在執行onDestroy方法

如果有,Service不會執行onUnbind和onDestroy方法(從打印的日志中可以得出這樣結論)

 

點擊 binderA綁定→跳轉BinderAcitivityB→binderB綁定→binderB解綁→BinderB finish→BinderA finish 的日志

 

07-09 13:19:58.340 8297-8297/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 13:19:58.360 8297-8297/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 13:19:58.360 8297-8297/com.hh.servicedemo V/hjz: numA=2026321547
07-09 13:20:02.190 8297-8297/com.hh.servicedemo V/hjz: numB=-1586530569
07-09 13:20:04.140 8297-8297/com.hh.servicedemo V/hjz: ActicityB is unbindService
07-09 13:20:05.820 8297-8297/com.hh.servicedemo I/hjz: ActivityB -> onDestroy
07-09 13:20:07.080 8297-8297/com.hh.servicedemo I/hjz: ActivityA -> onDestroy
07-09 13:20:07.110 8297-8297/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 13:20:07.110 8297-8297/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main

結論:當client與Service通過bindServer連接起來之後,如果client(客戶端)執行(onDestroy)銷毀,那麼client會自動與Service解除綁定。

 

點擊 binderA綁定→跳轉BinderAcitivityB→binderB綁定→BinderB finish→BinderA解綁→BinderA finish 的日志
07-09 13:17:40.320 8297-8297/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 13:17:40.320 8297-8297/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 13:17:40.340 8297-8297/com.hh.servicedemo V/hjz: numA=-1117645606
07-09 13:17:43.460 8297-8297/com.hh.servicedemo V/hjz: numB=1774346322
07-09 13:17:44.770 8297-8297/com.hh.servicedemo I/hjz: ActivityB -> onDestroy
07-09 13:17:56.780 8297-8297/com.hh.servicedemo V/hjz: ActicityA is unbindService
07-09 13:17:56.780 8297-8297/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 13:17:56.780 8297-8297/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main
07-09 13:17:58.060 8297-8297/com.hh.servicedemo I/hjz: ActivityA -> onDestroy

點擊 binderA綁定→跳轉BinderAcitivityB→binderB綁定→BinderB finish→BinderA finish 的日志

 

07-09 13:21:22.890 8297-8297/com.hh.servicedemo I/hjz: BindService -> onCreate, Thread: main
07-09 13:21:22.890 8297-8297/com.hh.servicedemo I/hjz: BindService -> onBind, Thread: main
07-09 13:21:22.900 8297-8297/com.hh.servicedemo V/hjz: numA=1947324308
07-09 13:21:26.630 8297-8297/com.hh.servicedemo V/hjz: numB=-1343649013
07-09 13:21:27.730 8297-8297/com.hh.servicedemo I/hjz: ActivityB -> onDestroy
07-09 13:21:29.040 8297-8297/com.hh.servicedemo I/hjz: ActivityA -> onDestroy
07-09 13:21:29.060 8297-8297/com.hh.servicedemo I/hjz: BindService -> onUnbind, from:ActivityA
07-09 13:21:29.060 8297-8297/com.hh.servicedemo I/hjz: BindService -> onDestroy, Thread: main

上面的日志打印,下面用一張圖來總結一下client和Service操作流程:

\

 

在不同app之間調用這裡就不做介紹了,有興趣的自己可以去研究一下

 

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