Android服务Service(二)

1)前言

本文是接着上篇没有介绍完的Android服务Service写的,主要是想对Bound式服务做一个总结,从学Android到现在,我很少用到Bound式服务,倒是Started式服务用得不少(可能太菜),借着这个机会,结合官方文档案例对Bound式服务做一个全面的了解。

2)基本用法

一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。

客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。

多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().

当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.

创建绑定服务,必须提供IBinder接口,有三种方式定义这个接口:

  • 1) 实现Binder类

如果这个service只是为当前应用服务,并且运行在相同的进程里,创建的接口必须继承Binder类,并且在onBind()方法中返回。客户可以通过它得到Binder对象,通过这个对象可以直接访问共有函数。

当service仅仅为自己的应用服务,这是首选技术。

  • 2) 使用Messenger

如果需要接口在不同的进程间使用,可以用Messenger 为service类创建接口。用这种方式, service对处理不同的Message 对象定义了一个Handler. 这个Handler是Messenger的基础,可以与客户分享IBinder,允许客户用message发送命令到service上。补充点,客户端可以自定义Messenger,因此service可以发送消息回来。

这是在进程间通信最简单的方式。因为Messenger队列所有的请求发生在一个线程上,因此不需要考虑service的线程安全。

  • 3) 使用AIDL

AIDL (Android Interface Definition Language) 可以把对象分解成系统能够识别的单元,已达到在进程间通信的能力。在前面的技术中,使用的messenger,实际上是以AIDL作为基础的结构。如上所述,Messenger在一个线程中创建了所有客户请求的一个队列。如果你想service能够同时处理多个请求,那么就可以直接用AIDL. 在这种案例中,service 必须要有处理多线程的能力,并且是线程安全的。

要想直接使用AIDL,必须创建定义程序的接口文件,后缀是.aidl。Android SDK工具可以通过这个文件生成一个实现了这个接口和处理IPC的抽象类,自定义的service需要继承自这个抽象类。

这种方式暂且不讨论

下面分别看下具体三种使用方法

3)实现Binder类

1、 在你的服务类中,创建一个满足下面条件的Binder实现类:
包含一个public方法,以便客户端可以调用
在一个public方法中返回当前服务实例给客户端使用

2、 在onBind()方法中,返回Binder对象实例
3、 在客户端,从onServiceConnected()回调方法接收Binder对象,并调用绑定服务中提供的方法。

下面来看下代码

//服务端

public class BoundTest extends Service {

    private static final String TAG = "chen";

    private IBinder iBinder = new LocalBinder();
    private Random mGenerator = new Random();

    public class LocalBinder extends Binder{
        public BoundTest getService(){
            return BoundTest.this;
        }
    }

    public int getRandomNumber() {
        return mGenerator.nextInt(100);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return iBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestory");
    }
}

我们可以看见在服务端LocalBinder是一个内部类,其继承了Binder,里面有个公共方法,返回该服务的实例。并且有一个getRandomNumber()测试方法,供客户端调用。

//客户端
public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_bound;
    private Button btn_unbound;
    private Button btn_getrandom;

    private BoundTest mService;

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

        btn_bound = (Button) findViewById(R.id.btn_bound);
        btn_unbound = (Button) findViewById(R.id.btn_unbound);
        btn_getrandom = (Button) findViewById(R.id.btn_getrandom);

        btn_bound.setOnClickListener(this);
        btn_unbound.setOnClickListener(this);
        btn_getrandom.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = null;
        switch (view.getId()){
            case R.id.btn_bound:
                intent = new Intent(MainActivity.this, BoundTest.class);
                //绑定服务
                bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbound:
                intent = new Intent(MainActivity.this, BoundTest.class);
                //解绑服务
                unbindService(mConnection);
                break;
            case R.id.btn_getrandom:
                int number = mService.getRandomNumber();
                btn_getrandom.setText("获取随机数"+number);
                break;
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {

        //绑定成功回调
        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            BoundTest.LocalBinder binder = (BoundTest.LocalBinder) service;
            mService = binder.getService();   //获取Binder对外提供的接口
        }

        //绑定失败回调
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
        }
    };

}

//布局:
<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.chen.demo.MainActivity">

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

    <Button
        android:layout_marginTop="20dp"
        android:id="@+id/btn_unbound"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解绑"
        />

    <Button
        android:layout_marginTop="20dp"
        android:id="@+id/btn_getrandom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取随机数"
        />

</LinearLayout>

我们在客户端通过bindService()绑定服务,通过unbindService()解绑服务,其中bindService()需要三个参数意思分别是:

第一个变量是通过Intent指定要绑定的service.
第二个参数是 ServiceConnection 对象.
第三个参数是设置绑定的选项。通常是BIND_AUTO_CREATE,当service不在运行时,会自动创建。其他值有BIND_DEBUG_UNBIND 和BIND_NOT_FOREGROUND, 或者是0(没有任何意义).

而unbindService(),需要一个参数ServiceConnection

我们看下运行结果:

这里写图片描述

结果是最后一个Button的Text后面的数字

4)使用Messenger

如果service需要与远程的进程通讯,可以用Messenger为service提供一个接口。这种技术可以处理进程间的通讯。

下面是使用messenger的简介:

1)service 要实现Handler,它可以收到每一个client调用的回调。
2)Handler用于创建Messenger对象。 (which is a reference to the Handler).
3)Messenger创建一个IBinder,client调用onBind()时,IBinder要返回给client的
4)Clients 通过IBinder实例化Messenger(that references the service’s Handler),Messenger为了client发送Message对象到service。
5)service 通过Handler收到每一个Message, 在 handleMessage() 方法明确的处理.

利用这种方式,service中没有方法可一个被Client调用。client通过传递消息(messages)到service的Handler中。

我们简单看下服务端代码

//服务端
public class MessengerService extends Service {

    private static final String TAG = "chen";

    public static final int MSG_SAY_HELLO = 1;

    public class IncomingHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    }

    final Messenger mMessenger = new Messenger(new IncomingHandler());

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return mMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestory");
    }
}

注意:Handler 的handleMessage()方法收到Message,并且根据Message的what变量 确定需要做什么。

Client的需要实现的是,基于返回的IBinder创建Messenger对象,并且通过send()发送Message给service的Handler。

//客户端
public class MessengerActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_bound;
    private Button btn_unbound;
    private Button btn_getrandom;

    Messenger mService = null;

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

        btn_bound = (Button) findViewById(R.id.btn_bound);
        btn_unbound = (Button) findViewById(R.id.btn_unbound);
        btn_getrandom = (Button) findViewById(R.id.btn_getrandom);

        btn_bound.setOnClickListener(this);
        btn_unbound.setOnClickListener(this);
        btn_getrandom.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = null;
        switch (view.getId()){
            case R.id.btn_bound:
                intent = new Intent(MessengerActivity.this, MessengerService.class);
                //绑定服务
                bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbound:
                //解绑服务
                unbindService(mConnection);
                break;
            case R.id.btn_getrandom:
                Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
                try {
                    mService.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }

    private ServiceConnection mConnection = new ServiceConnection() {

        //绑定成功回调
        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            mService = new Messenger(service);
        }

        //绑定失败回调
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
        }
    };
}

注意: 这个例子没有体现service是如何响应client。如果想service响应client,需要在client里面创建一个Messenger。当client收到onServiceConnected()回调,就会发送Message到service,send()方法的Message变量replyTo包括客户端的Messenger,从而实现双向通讯。

看下运行结果:

这里写图片描述

这个Toast是服务端打印的结果。

5)生命周期管理

当service没有被任何的client绑定,android系统会杀死它(除非中途被其他的组件调用了onStartCommand())。按照这种原理, 绑定service是不需要管理它的生命周期的-android系统会根据绑定原则自动管理service。

然而,如果选择onStartCommand()方法实现,就必须明确的停止service,因为服务当前状态被认为是started。在这种案例下,service一直运行直到调用stopSelf()或者其他的组件调用stopService()方法,不管他绑定任何clients.这里的意思是说:当一个绑定service通过onStartCommand()启动,需要stopSelf()和stopService()方法来停止它,即使是中间绑定其他的客户端。

补充点,如果service已经启动并且接受了client的绑定,那么当系统调用onUnbind()方法时,如果想client下次绑定service的时候调用onRebind(),可以选择返回true,(而不是重新调用onBind()). onRebind() 返回 void, 但是client在onServiceConnected()还是接受IBinder. 下面的图阐明了上面的逻辑。

这里写图片描述

6)最后

服务基本内容也就这么多,还有一个AIDL没有介绍,下次准备结合Android Studio详细介绍下

7) Ref

1 )Android 官方文档
2 )http://blog.163.com/cazwxy_12/blog/static/898763720122106483898/
3 )http://blog.csdn.net/luhuajcdd/article/details/8756541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值