请选择 进入手机版 | 继续访问电脑版
JAVEN

Service服务基础介绍(二)绑定服务bindservice

所在版块: 课堂笔记 2016-04-28 16:32   [复制链接] 查看: 1436|回复: 2
本帖最后由 yangjw 于 2016-4-28 17:17 编辑

  • 屁话一堆
对于android菜鸟来说,平时使用service不多,也不知道怎么去用service。更不知道什么时候使用startService,什么时候使用bindService?在面试的时候,如果碰到关于activity和service怎么通信的问题的时候就蒙圈了。

  • Bound类型service使用的场景
当程序中的activity或者其他组件需要与service进行交互的时候(即需要双向通信),可以使用Bound类型的服务。


  • 介绍
Bound类型的服务是客户端-服务器模式的服务。bound服务允许组件(比如activity)对其进行绑定、发送请求、接收响应、甚至进行进程间通信(IPC)。 bound服务一般只在为其它应用程序组件服务期间才是存活的,而不会一直在后台保持运行。

Bound类型的服务是通过和activity之间建立IBinder接口进行通信。建立IBinder接口有3中方式:
  • 继承Binder类
  • 使用Messenger
  • 使用AIDL
接下来,通过这3种方式,介绍bound类型的服务的基本使用。


  • 继承Binder类,实现绑定服务。(只能在同一个进程通信)
首先说明一下使用步骤,分3步:
1.在你的服务中,创建一个Binder的实例,其中实现以下三者之一:
◦包含了可供客户端调用的公共方法
◦返回当前Service实例,其中包含了可供客户端调用的公共方法。
◦或者,返回内含服务类的其它类的一个实例,服务中包含了可供客户端调用的公共方法。
2.从回调方法onBind()中返回Binder的该实例。
3.在客户端中,在回调方法onServiceConnected()中接收Binder并用所提供的方法对绑定的服务进行调用。


以下是一个使用Binder通信的示例,实在自定义Service内部实现一个Binder对象来为Activity的访问提供通信支持。Binder相当于是Service的一个门卫,来访者需要访问Service的什么内容,必须通过Binder这个门卫来传达:

  1. public class MyBoundService extends Service {
  2.     private final MyBinder myBinder = new MyBinder();
  3.     private Random random = new Random();
  4.     @Nullable
  5.     @Override
  6.     public IBinder onBind(Intent intent) {
  7.         //返回Binder对象
  8.         return myBinder;
  9.     }
  10.     //创建一个Bindler子类,通过此类暴露一些Service的内容,给其他组件使用。
  11.     //比如此处向外暴露的就是Service对象本身。
  12.     public final class MyBinder extends Binder {

  13.         MyBoundService getService() {
  14.             return MyBoundService.this;
  15.         }
  16.     }
  17.     //模拟数据,一个随机数
  18.     public int getData() {
  19.         return random.nextInt(100);
  20.     }
  21. }
复制代码
接下来是一个绑定Service的activity,代码如下:
  1. public class MainActivity extends AppCompatActivity {

  2.     private MyBoundService mBoundService;
  3.     private boolean isBound;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.activity_main);

  8.     }

  9.     public void click(View view) {
  10.         switch (view.getId()) {
  11.             case R.id.service_bind_btn:
  12.                 //按下按钮的时候获取Service返回的数据
  13.                 Toast.makeText(MainActivity.this, "服务数据:"+mBoundService.getData(), Toast.LENGTH_SHORT).show();
  14.                 break;
  15.         }
  16.     }

  17.     @Override
  18.     protected void onStart() {
  19.         super.onStart();
  20.         bindService();
  21.     }

  22.     @Override
  23.     protected void onStop() {
  24.         super.onStop();
  25.         if (isBound) {
  26.             unbindService(serviceConnection);
  27.             isBound = false;
  28.         }
  29.     }

  30.     private void bindService() {
  31.         Intent intent = new Intent(this,MyBoundService.class);
  32.         //参数一:intent对象
  33.         //参数二:ServiceConnection对象,用于监听绑定是否成功
  34.         //参数三:绑定模式。BIND_AUTO_CREATE表示如果Service不存在会自动创建
  35.         bindService(intent,serviceConnection,BIND_AUTO_CREATE);
  36.     }

  37.     //ServiceConnection是一个用于监听服务是否成功绑定的接口
  38.     ServiceConnection serviceConnection = new ServiceConnection() {
  39.         //绑定成功,接受到MyBoundService的onBind方法返回的Binder对象
  40.         //参数二:就是MyBoundService返回的Binder对象
  41.         @Override
  42.         public void onServiceConnected(ComponentName name, IBinder service) {
  43.             //强制类型转换,获的MyBinder对象
  44.             MyBoundService.MyBinder myBinder = (MyBoundService.MyBinder) service;
  45.             //通过MyBinder获取MyBoundService对象本身
  46.             mBoundService = myBinder.getService();
  47.             isBound = true;
  48.         }

  49.         @Override
  50.         public void onServiceDisconnected(ComponentName name) {
  51.             isBound = false;
  52.         }
  53.     };
  54. }
复制代码
上述就是一个完整的通过Binder、ServiceConnection完成的一个Bound类型的服务,并且可以在ServiceConnection的onServiceConnected方法中获得Service返回的MyBinder对象,然后通过MyBinder对象进行通信。

  • 通过Messenger,实现绑定服务(可以跨进程)
基本使用步骤:

1、服务实现一个Handler ,用于客户端每次调用时接收回调。
2、此Handler用于创建一个Messenger对象(它是一个对Handler的引用)。
3、此Messenger对象创建一个IBinder,服务在onBind()中把它返回给客户端。
4、客户端用IBinder将Messenger(引用服务的Handler)实例化,客户端用它向服务发送消息对象Message。
5、服务接收Handler中的每个消息Message——确切的说,是在handleMessage()方法中接收。

以下是代码示例:
1、Service的代码,完成了上述步骤中的1、2、3步。
  1. public class MessengerService extends Service {
  2.     /** 发送给服务的用于显示信息的指令*/
  3.     static final int MSG_SAY_HELLO = 1;

  4.     /**
  5.      * 从客户端接收消息的Handler
  6.      */
  7.     class IncomingHandler extends Handler {
  8.         @Override
  9.         public void handleMessage(Message msg) {
  10.             switch (msg.what) {
  11.                 case MSG_SAY_HELLO:
  12.                     Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
  13.                     break;
  14.                 default:
  15.                     super.handleMessage(msg);
  16.             }
  17.         }
  18.     }

  19.     /**
  20.      * 向客户端公布的用于向IncomingHandler发送信息的Messager
  21.      */
  22.     final Messenger mMessenger = new Messenger(new IncomingHandler());

  23.     /**
  24.      * 当绑定到服务时,我们向Messager返回接口,
  25.      * 用于向服务发送消息
  26.      */
  27.     @Override
  28.     public IBinder onBind(Intent intent) {
  29.         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
  30.         return mMessenger.getBinder();
  31.     }
  32. }
复制代码
2、activity中的代码,完成了使用步骤中的4、5步。
  1. public class ActivityMessenger extends Activity {
  2.     /** 用于和服务通信的Messenger*/
  3.     Messenger mService = null;

  4.     /** 标识我们是否已绑定服务的标志 */
  5.     boolean mBound;

  6.     /**
  7.      * 与服务的主接口进行交互的类
  8.      */
  9.     private ServiceConnection mConnection = new ServiceConnection() {
  10.         public void onServiceConnected(ComponentName className, IBinder service) {
  11.             // 与服务建立联接后将会调用本方法,
  12.             // 给出用于和服务交互的对象。
  13.             // 我们将用一个Messenger来与服务进行通信,
  14.             // 因此这里我们获取到一个原始IBinder对象的客户端实例。
  15.             mService = new Messenger(service);
  16.             mBound = true;
  17.         }

  18.         public void onServiceDisconnected(ComponentName className) {
  19.             // 当与服务的联接被意外中断时——也就是说服务的进程崩溃了,
  20.             // 将会调用本方法。
  21.             mService = null;
  22.             mBound = false;
  23.         }
  24.     };

  25.     public void sayHello(View v) {
  26.         if (!mBound) return;
  27.         // 创建并向服务发送一个消息,用到了已约定的'what'值
  28.         Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
  29.         try {
  30.             mService.send(msg);
  31.         } catch (RemoteException e) {
  32.             e.printStackTrace();
  33.         }
  34.     }

  35.     @Override
  36.     protected void onCreate(Bundle savedInstanceState) {
  37.         super.onCreate(savedInstanceState);
  38.         setContentView(R.layout.main);
  39.     }

  40.     @Override
  41.     protected void onStart() {
  42.         super.onStart();
  43.         // Bind to the service
  44.         bindService(new Intent(this, MessengerService.class), mConnection,
  45.             Context.BIND_AUTO_CREATE);
  46.     }

  47.     @Override
  48.     protected void onStop() {
  49.         super.onStop();
  50.         // Unbind from the service
  51.         if (mBound) {
  52.             unbindService(mConnection);
  53.             mBound = false;
  54.         }
  55.     }
  56. }
复制代码
以上是一个利用Messenger完成的从Service到Activity的通信。如果要同时做到Activity向Service通信,可以同样在Activity中创建一个Handler,然后利用此Handler创建一个Messenger对象,最后将Messenger对象,通过send方法发送给Service。比如:
  1. @Override
  2.         public void onServiceConnected(ComponentName name, IBinder service) {
  3.             Log.d("androidxx","-->" + service);
  4.             messenger = new Messenger(service);
  5.             Message message = new Message();
  6.             message.obj = activityMessenger;//activityMessenger是在Activity中创建的。
  7.             try {
  8.                 messenger.send(message);
  9.             } catch (RemoteException e) {
  10.                 e.printStackTrace();
  11.             }
  12.         }
复制代码



  • 注意
1、建议不要在Activity的onResume和onPause中绑定和解绑定,这样太频繁,会降低系统工作效率。

2、当ActivityA第一次绑定了Service会执行onBind方法,之后ActivityB再次绑定同一个Service的时候,不会重复执行onBind方法,但是会返回一个Binder对象。
3、不要再onBind方法中执行耗时操作
4、如果不需要返回结果的使用startService,如果需要返回结果的使用bindService。
5、Binder是在同一个进程内部通信,Messenger可以跨进程通信

将AIDL的使用介绍放到下一篇【Service服务基础介绍(三)】介绍。

回复

使用道具 举报

承影

  • TA的每日心情
    慵懒
    2016-6-2 10:37
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2016-5-12 13:06:43 | 显示全部楼层
    回复

    使用道具 举报

    承影

  • TA的每日心情
    慵懒
    2016-6-2 10:37
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2016-5-12 13:07:38 | 显示全部楼层
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    我的博客

    QQ|Archiver|手机版|小黑屋|课堂笔记  

    GMT+8, 2019-3-21 10:30 , Processed in 0.088289 second(s), 38 queries .

    快速回复 返回列表