Android中Service使用bindService

前面已经对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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.hh.servicedemo.MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="BinderService绑定"/>

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="BinderService解绑"/>

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="跳转到BinderActivityB"/>

    <Button
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="finish"/>


</LinearLayout>


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之间调用这里就不做介绍了,有兴趣的自己可以去研究一下


发布了51 篇原创文章 · 获赞 31 · 访问量 14万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览