Android学习七之Service(三)

 上次上心理学课的时候,老师讲到沟通,沟通的一个必要前提是心平气和,可是昨天我真的特别气愤发火,现在的大学生怎么变成这样了!并不是我这个人很保守或是怎样,不喜欢别人女生还要提出那种无耻的要求,学校里又不是红灯区!


好吧,算我说了一些废话。


上回说到要Service有两种:Started 和 Bound,已经学过了Started,因为文档里专门拿出一页来介绍Bound Service,

我估计这个Bound Service 更常用。

首先打开文档:
http://developer.android.com/guide/topics/fundamentals/bound-services.html


1,什么是Bound Service?

Bound Service是在C/S模式下作为服务端(Server)存在,Bound Service允许其他组件绑定这个服务,并且发送请求,接受响应,甚至进行进程间通信(IPC),Bound Service通常依赖于其他应用程序组件,并且不会无限期运行下去。
(有一点我声明一下,就是这些名词我没法翻译,每个人的理解都不一样,我干脆就不翻译了,知道是这么个意思就行了。)

2,基础知识

要创建一个Bound Service:

首先需要继承Service或其子类,这样才算是一个Service

其次需要覆写onBind()方法,这样才算是一个Bound Service

打开API文档:


在Service这个基类里这个方法是抽象方法,需要返回一个实现了IBinder接口的类的对象,这个接口就是声明了客户端可以和Service进行通信。到下面找到更为详细的解释:


这个返回的IBinder对象着实需要花点时间去理解,要实现一个Bound Service,最重要的方法就是这个。文档里提到一点:

 

Multiple clients can connect to the service at once. However, the system calls your service's onBind() method to retrieve the IBinder only when the first client binds. The system then delivers the same IBinder to any additional clients that bind, without calling onBind() again.
可以有多个客户端同时连接这个Service,但是onBind()方法只会调用一次,返回的也只会有一个IBinder对象,所有连接到这个Service的客户端都是得到这个相同的IBinder对象。


要绑定一个Service,客户端可以调用

 boolean bindService (Intent service, ServiceConnection conn, int flags)
这是android.content.Context类中的方法,Service继承Context。这个方法中需要传入一个Intent 意图、ServiceConnection  连接、int 标识位,还是直接拿文档的过来吧。

如果成功绑定了Service,那么会立即返回true,否则是false。
方法的参数里有个ServiceConnection对象,这个ServiceConnction是什么呢?因为我没下载到源代码,只能看文档

这是一个接口,接口里定义了两个方法:onServiceConnected()和onServiceDisconnected();从文档里可以看出这个接口是孤零零的,只有一个类实现了它。我们基本上是要自己实现这个接口,并且实现这两个方法。

下面到最实用的部分:
3.,创建Bound Service的方法
       直接看代码吧
public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}


因为onBind()方法需要返回一个IBinder对象,需要自己对应一个类实现IBinder,有两种办法可以定义这个类:
     1,继承Binder类
找到Binder

在自己定义的类LocalBinder中定义了一个方法:getService()。


再看一下客户端的代码:

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute) */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call were something that might hang, then this request should
            // occur in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

 从onServiceConnected()回调方法中拿到了Service,并赋值给了局部变量,在onStart()方法中调用bindService()绑定Service。

从新理一下:
 1,在自定义的Service中创建一个IBinder实例
 2,在onBind()返回这个实例
 3,在客户端中先拿到IBinder实例,在调用他提供的getService()方法(自己定义的)拿到Service
 4,在onStart()方法中调用bindService()实现绑定

2,用一个Messenger
如果Service需要进行远程进程通信,那么需要一个Messenger为Service提供一个接口
先找到Messenger

下面有一些方法:


如果使用Messenger,
先看代码:
public class MessengerService extends Service {
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    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);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

在这个Service中有个内部类,IncomingHandler继承Handle,并且覆写了handleMessage()方法。这有牵扯到一个问题:什么是Handle?
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue

今天重点不是这个Handler.
在这个类中定义了一个Messenger变量,并且通过构造函数传入一个Handler 对象初始化了。
在onBind()方法中,用Messenger的getBinder()方法返回了一个IBinder对象。

再看客户端代码:
public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

我用红色标记了一些代码,
在客户端中先创建一个Messenger,在onServiceConnected()方法中进行赋值。在功能代码sayHello()中先创建一个Message,再调用send()方法发出这个Message。
最后在onStop()方法进行了解绑定,用unbindService()方法,传入一个ServiceConnection作为参数。

稍微读了一下上面代码的人都会发现里面有一个标识位: boolean mBound
在onStop()和onServiceDisconnected()方法中mBound=false; 
在onServiceConnected()方法中mBound=true;

再总结一下要创建一个Bound Service在客户端(client)需要做哪些事:

1,实现ServiceConnection,实现接口中的两个方法。
2,调用bindService()方法。
3,onServiceConnected()方法中需要通过一些定义好的方法取得Service。
4,调用unbindService()方法解除绑定。

最后把Bound Service的生命周期介绍完,然后吃饭去,再直接去上课

在看那个图之前,我觉得应该可以参照Activity的生命周期把Bound Service的生命周期想象一下,虽然会有一些不同。


我忘了,没有把onRebind()方法说一下。
我个人觉得这个图实在是讲的太详细了,当然在API里对Service的生命周期也是很详细的文字描述。


不过显然是图形更好理解。

下次我打算把Content Providers学完,我记得是会用到Note Pad的例子



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值