`
xiaonao880516
  • 浏览: 58000 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android Service那些不得不说的事-之二(Bound Service的实现方式)

阅读更多
To provide binding for service, you must implement the onBind() method. This method returns anIBinder object that defines the interface that clients can use to interact with the service.

三种不同的方式,说白了就是通过onBind()返回三种不同类型的IBinder object。
一、可以返回自定义的Binder(继承自Binder),并且在其中提供public methods that the client can call。
通常情况下,we returns the current Service instance, or an instance of another class hosted by the service with public methods theclient can call.
[html] view plaincopy
private final IBinder mBinder = new LocalBinder(); 
public class LocalBinder extends Binder { 
        LocalService getService() { 
            // Return this instance of LocalService so clients can call public methods 
            return LocalService.this; 
        } 
    } 
优点:

1. 使用简单,client在onServiceConnected()拿到Binder之后,可以直接cast到原本的类型,进行使用。

缺点:

1. 必须在同一个进程中使用,因为一般自定义的Binder不会按照IPC的要求实现Binder中的接口,如何支持IPC,请参看AIDL实现的Binder类。
注意:

1. 此种方法调用service的function时,就跟一个普通的函数调用一样,在当前线程执行,而不像IPC那样,service端的function都是在binder thread中执行。

三、使用AIDL,onBind()返回ServiceInterface.Stub mBinder = new ServiceInterface.Stub(){ }。

编译工具会根据.aidl文件生成一个.java文件,里面有AIDL实现的Binder类。例如,我们提供的.aild文件如下:

[html] view plaincopy
package com.baidu.test.aidl; 
import com.baidu.test.aidl.ClientInterface; 
 
interface ServiceInterface {   
    void register(ClientInterface client);   
    void serviceFun(); 
    void invokeClientCallBack(); 


系统帮我们生成的.java文件如下:
[html] view plaincopy
package com.baidu.test.aidl; 
 
public interface ServiceInterface extends android.os.IInterface { 
    public void register(com.baidu.test.aidl.ClientInterface client) throws android.os.RemoteException; 
    public void serviceFun() throws android.os.RemoteException; 
    public void invokeClientCallBack() throws android.os.RemoteException; 
 
    // ========================  Stub用在service端  ================================ 
    public static abstract class Stub extends android.os.Binder implements com.baidu.test.aidl.ServiceInterface { 
        private static final java.lang.String DESCRIPTOR = "com.baidu.test.aidl.ServiceInterface"; 
         
        static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 
        static final int TRANSACTION_serviceFun = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 
        static final int TRANSACTION_invokeClientCallBack = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); 
         
        public Stub() { 
            // from Binder, Convenience method for associating a specific interface with the Binder.  
            // After calling, queryLocalInterface() will return the given owner IInterface  
            // when the corresponding descriptor is requested.  
            <span style="color:#FF0000;"><strong>this.attachInterface(this, DESCRIPTOR);</strong></span>  
<pre name="code" class="html">            // public void attachInterface (IInterface owner, String descriptor) 
        } 
 
        public static com.baidu.test.aidl.ServiceInterface asInterface(android.os.IBinder obj) { 
            if ((obj==null)) { 
                return null; 
            } 
             
            //由于attachInterface()是在service调用的,所以client调用queryLocalInterface()会返回null,从而在client端使用的是Proxy。 
            <span style="color:#FF0000;"><strong>android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);</strong></span> 
            if (((iin!=null)&&(iin instanceof com.baidu.test.aidl.ServiceInterface))) { 
                return ((com.baidu.test.aidl.ServiceInterface)iin); 
            } 
             
            <span style="color:#FF0000;"><strong>return new com.baidu.test.aidl.ServiceInterface.Stub.Proxy(obj);</strong></span> 
        } 
         
        @Override // from IInterface 
        public android.os.IBinder asBinder() { 
            return this; 
        } 
     
        @Override // from Binder 
        // <span style="color:#FF0000;"><strong>service端的Stub实现了onTransact(),service在其中处理client发出的调用, 
</strong><span style="color:#000000;">        //</span><strong> 而client端用的Proxy就没有实现onTransact(),而只是调用了transact()。</strong></span> 
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 
            switch (code) { 
                case INTERFACE_TRANSACTION: 
                { 
                    reply.writeString(DESCRIPTOR); 
                    return true; 
                } 
                case TRANSACTION_register: 
                { 
                    data.enforceInterface(DESCRIPTOR); 
                    com.baidu.test.aidl.ClientInterface _arg0; 
                    _arg0 = com.baidu.test.aidl.ClientInterface.Stub.asInterface(data.readStrongBinder()); 
                    this.register(_arg0); 
                    reply.writeNoException(); 
                    return true; 
                } 
                case TRANSACTION_serviceFun: 
                { 
                    data.enforceInterface(DESCRIPTOR); 
                    this.serviceFun(); 
                    reply.writeNoException(); 
                    return true; 
                } 
                case TRANSACTION_invokeClientCallBack: 
                { 
                    data.enforceInterface(DESCRIPTOR); 
                    this.invokeClientCallBack(); 
                    reply.writeNoException(); 
                    return true; 
                } 
            } 
            return super.onTransact(code, data, reply, flags); 
        } 
         
        // ========================  Proxy用在client端  ================================ 
        private static class Proxy implements com.baidu.test.aidl.ServiceInterface { 
            private android.os.IBinder mRemote; 
             
            Proxy(android.os.IBinder remote) { 
                mRemote = remote; 
            } 
             
            @Override // from IInterface 
            public android.os.IBinder asBinder() { 
                return mRemote; 
            } 
             
            @Override // from IBinder, Get the canonical name of the interface supported by this binder. 
            public java.lang.String getInterfaceDescriptor() { 
                return DESCRIPTOR; 
            } 
             
            public void register(com.baidu.test.aidl.ClientInterface client) throws android.os.RemoteException { 
                android.os.Parcel _data = android.os.Parcel.obtain(); 
                android.os.Parcel _reply = android.os.Parcel.obtain(); 
                try { 
                    _data.writeInterfaceToken(DESCRIPTOR); 
                    _data.writeStrongBinder((((client!=null))?(client.asBinder()):(null))); 
                    <span style="color:#FF0000;"><strong>mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0);</strong></span> 
                    _reply.readException(); 
                } finally { 
                    _reply.recycle(); 
                    _data.recycle(); 
                } 
            } 
             
            public void serviceFun() throws android.os.RemoteException { 
                android.os.Parcel _data = android.os.Parcel.obtain(); 
                android.os.Parcel _reply = android.os.Parcel.obtain(); 
                try { 
                    _data.writeInterfaceToken(DESCRIPTOR); 
                    <strong><span style="color:#FF0000;">mRemote.transact(Stub.TRANSACTION_serviceFun, _data, _reply, 0);</span></strong> 
                    _reply.readException(); 
                } finally { 
                    _reply.recycle(); 
                    _data.recycle(); 
                } 
            } 
 
            public void invokeClientCallBack() throws android.os.RemoteException { 
                android.os.Parcel _data = android.os.Parcel.obtain(); 
                android.os.Parcel _reply = android.os.Parcel.obtain(); 
                try { 
                _data.writeInterfaceToken(DESCRIPTOR); 
                <strong><span style="color:#FF0000;">mRemote.transact(Stub.TRANSACTION_invokeClientCallBack, _data, _reply, 0);</span></strong> 
                _reply.readException(); 
                } finally { 
                    _reply.recycle(); 
                    _data.recycle(); 
                } 
            } 
        } 
        // ========================  Proxy用在client端  end ================================ 
    } 
    // ========================  Stub用在service端 end ================================ 
}</pre> 
<pre></pre> 
service端相关代码如下:<pre name="code" class="html">    <span style="color:#FF0000;"><strong>private final ServiceInterface.Stub mBinder = new ServiceInterface.Stub()</strong></span> {   
        @Override   
        public void register(ClientInterface client) throws RemoteException { 
        }  
         
        @Override   
        public void serviceFun() throws RemoteException {   
        }   
           
        @Override   
        public void invokeClientCallBack() throws RemoteException { 
        }           
    };  
 
    @Override   
    public IBinder onBind(Intent t) {  
        <strong><span style="color:#FF0000;">return mBinder;</span></strong>   
    } </pre>client端的相关代码如下: 
<p></p> 
<p></p> 
<pre name="code" class="html">    <strong><span style="color:#FF0000;">private ServiceInterface mService; </span></strong>    
    private ServiceConnection mConnection = new ServiceConnection() {   
        public void onServiceConnected(ComponentName className, IBinder service) { 
            <strong><span style="color:#FF0000;">mService = ServiceInterface.Stub.asInterface(service);</span></strong>   
            try {   
                mService.register(mClient); 
            } catch (RemoteException e) { 
                e.printStackTrace(); 
            } 
        } 
         
        public void onServiceDisconnected(ComponentName className) { 
            mService = null; 
        }   
    };</pre>优点: 
<p></p> 
<p>1. 可以进行IPC。</p> 
<p>缺点:</p> 
<p>1. 使用复杂,需要编写.aidl文件,而且client端和service端都需要copy一份.aidl文件,以便编译生成对应的.java文件。</p> 
<p>2. 由于service端的函数是在binder thread中执行,而系统又帮我们维护了一个binder thread的线程池,所以我们需要在service的函数中考虑线程安全。<br> 
</p> 
<p>注意:</p> 
<p>1. 如果client和service在同一个进程,那么即使我们采用了AIDL,由系统生成的代码可以看到通过<span style="color:#000000"><strong>ServiceInterface.Stub.asInterface(service)</strong>取得的实例实际上是本地的instance,所以ADIL调用就会变得和一个普通函数调用一样了,也就意味了service端的函数不会在binder thread中执行,而是在当前线程执行了。</span></p> 
<p><span style="color:#000000">2. Objects are reference counted across processes.也就是说可能出现内存泄露。<br> 
</span></p> 
<p></p> 
<p><span style="font-size:18px"><strong>二、使用Messager,onBind()返回Messager.getBinder()。</strong></span></p> 
<p>Messager可以使用两中不同的方法创建:</p> 
<p></p> 
<pre name="code" class="html">public Messenger (Handler target) 
public Messenger (IBinder target)</pre> 
<p></p> 
<p>1. 通过传入一个handler创建,service端使用;</p> 
<p>2. 通过传入一个binder创建,client端使用。</p> 
<p>其实Messager的底层实现还是AIDL,只不过帮我们做了封装,使用更方便。</p> 
<p>service端的相关代码如下:</p> 
<p></p> 
<pre name="code" class="html">    <span style="color:#FF0000;"><strong>private ArrayList<Messenger> mClients = new ArrayList<Messenger>();</strong></span> 
     
    <strong><span style="color:#FF0000;">private Messenger mMessenger = new Messenger(new IncomingHandler()); </span></strong>        
 
    @Override   
    public IBinder onBind(Intent t) { 
        <strong><span style="color:#FF0000;">return mMessenger.getBinder();</span></strong>   
    }  
         
    class IncomingHandler extends Handler { 
        @Override 
        public void handleMessage(Message msg) { 
            Log("===> handleMessage()"); 
            LogThreadInfo(); 
            switch (msg.what) { 
                case MSG_REGISTER_CLIENT: 
                    <strong><span style="color:#FF0000;">mClients.add(msg.replyTo);</span></strong> 
                    break; 
                case MSG_UNREGISTER_CLIENT: 
                    <strong><span style="color:#FF0000;">mClients.remove(msg.replyTo);</span></strong> 
                    break; 
                case MSG_SERVICE_FUN_ALPHA: 
                    for (int i=mClients.size()-1; i>=0; i--) { 
                        try { 
                            <strong><span style="color:#FF0000;">mClients.get(i).send(Message.obtain(null,MSG_SERVICE_FUN_ALPHA));</span></strong> 
                        } catch (RemoteException e) { 
                            // The client is dead.  Remove it from the list; 
                            mClients.remove(i); 
                        } 
                    } 
                    break; 
                default: 
                    super.handleMessage(msg); 
            } 
        } 
    } </pre> 
<p></p> 
<p>client端的相关代码如下:</p> 
<p></p> 
<pre name="code" class="html">    <span style="color:#FF0000;"><strong>private Messenger mService = null;</strong></span> 
    <strong><span style="color:#FF0000;">final Messenger mMessenger = new Messenger(new IncomingHandler());</span></strong> 
     
    class IncomingHandler extends Handler { 
        @Override 
        public void handleMessage(Message msg) { 
            switch (msg.what) { 
                case MSG_SERVICE_FUN_ALPHA: 
                    break; 
                default: 
                    super.handleMessage(msg); 
            } 
        } 
    }           
  
    private ServiceConnection mConnection = new ServiceConnection() {   
        public void onServiceConnected(ComponentName className, IBinder service) { 
            <strong><span style="color:#FF0000;">mService = new Messenger(service);</span></strong> 
            try { 
                <span style="color:#FF0000;"><strong>Message msg = Message.obtain(null,MSG_REGISTER_CLIENT);</strong></span> 
                <strong><span style="color:#FF0000;">msg.replyTo = mMessenger;</span></strong> // 可选项,主要是用来向service注册client,从而实现双向IPC。 
                <span style="color:#FF0000;"><strong>mService.send(msg);</strong></span> 
            } catch (RemoteException e) { 
                e.printStackTrace(); 
            } 
        } 
         
        public void onServiceDisconnected(ComponentName className) {   
            mService = null; 
        }   
    }; </pre> 
<p></p> 
<p>优点:</p> 
<p>1. 比较方便,而且可以实现进程间通信。<br> 
</p> 
<p>缺点:</p> 
<p>1. 必须想办法将Message Id,在service和client之间共享。<br> 
</p> 
<p>注意:</p> 
<p>1. 由于service是在main thread中创建,所以我们的Messager(包括构造Messager所需要提供的Handler)都是在main thread中创建的,所以一般情况下,service端的handleMessage()是在main thread中执行的。当然由于Handler创建时可以自定义所用的Looper,所以我们可以在service的onCreate()里面创建自己的线程,并prepare()线程自己的Looper,然后就可以让service端的handleMessage()运行在我们自己的线程中了。<br> 
</p> 
<p><br> 
</p> 
<br> 
分享到:
评论

相关推荐

    Android Service之bound实现

    本文将深入探讨“Android Service之bound实现”,理解如何通过绑定服务(Bound Service)来创建一个与应用程序组件交互的服务。 首先,我们要了解服务的两种基本类型:Start Service和Bound Service。Start Service...

    绑定服务BoundService详解之AIDL的使用(自定义属性也包含其中)

    在Android开发中,服务(Service)是四大组件之一,主要用于在后台执行长时间运行的任务,而绑定服务(Bound Service)则是服务的一种特殊形式,它允许其他组件(如Activity或BroadcastReceiver)通过接口与服务进行交互...

    Android Service简单实例

    在Android应用开发中,Service是四大组件之一,用于在后台执行长时间运行的操作,即使用户界面关闭也能继续工作。本篇文章将深入探讨`startService`类型的Android Service,通过一个简单的实例来展示其工作原理和...

    android Service 实现的四个案例

    在Android开发中,Service是四大组件之一,它用于在后台执行长时间运行的操作,不与用户交互。本篇文章将深入探讨四个具体的Service实现案例,帮助开发者更好地理解和应用Service。 案例一:简单服务(Basic ...

    Android服务Service_详解.pdf

    Android服务(Service)是Android操作系统中四个核心应用程序组件之一,其他三个分别是Activity、BroadcastReceiver和ContentProvider,它们在Android应用开发中的作用和使用场景各不相同。Service的作用主要体现在...

    android如何绑定service

    在Android开发中,Service是应用程序组件之一,它用于在后台执行长时间运行的操作,即使用户界面不在前台。在本文中,我们将深入探讨如何在Android应用中绑定Service,这通常用于实现客户端-服务器通信,使得应用...

    绑定服务BoundService利用扩展的IBinder类实现

    在Android开发中,服务(Service)是四大组件之一,它在后台执行长时间运行的操作而不会与用户界面交互。其中,绑定服务(Bound Service)是一种特殊的服务类型,它允许其他组件如活动(Activity)、...

    android Service类简介

    在Android开发中,Service是不可或缺的部分,它提供了后台运行的能力,使得应用可以执行那些不需要用户直接参与的任务。理解和掌握Service的使用对于开发高质量的Android应用至关重要。通过阅读博客文章《android ...

    Android通过Service实现简单的音乐播放

    Android 的四大组件之一是 Service,Service 是 Android 中的一种组件,用于在后台运行程序,承担着静悄悄的不为人所注意的工作。Service 可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他 ...

    android-service的demo

    总的来说,Service是Android系统中的重要组成部分,它使开发者能够实现后台运行的逻辑,增强应用的功能。在实际项目中,合理使用Service可以提高用户体验,同时避免不必要的资源消耗。通过研究“android-service的...

    On a search problem related to branch-and-bound procedures.pdf

    On a search problem related to branch-and-bound procedures.pdfOn a search problem related to branch-and-bound procedures.pdfOn a search problem related to branch-and-bound procedures.pdfOn a search ...

    startService和BoundService音乐播放DEMO

    总结来说,理解并熟练运用`startService`和`BoundService`是Android应用开发中的关键技能,尤其是在需要后台运行和交互的场景,如音乐播放。通过合理的组合使用,可以构建出高效、稳定且用户体验良好的应用。

    Android说明Service生命周期的代码例子

    在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的操作,不与用户界面直接交互。Service生命周期的理解和正确管理对于优化应用程序性能至关重要。以下是一个关于Service生命周期的详细解析,...

    service实现通话录音

    在Android开发中,Service是四大组件之一,它用于在后台执行长时间运行的操作,而不与用户交互。本篇文章将深入探讨如何使用Service实现通话录音功能,参考自博客:...

    Android4 Service中文指南

    #### 二、Android Service 的交互方式 **2.1 启动模式 (Started)** - **启动方式**: 通过调用 `startService()` 方法来启动 Service。这种方式下,Service 即使启动它的组件已经被销毁,仍能持续运行。 - **特点**...

    Service服务的android音乐播放器

    首先,`Service`是Android四大组件之一,它在后台执行长时间运行的任务,不与用户界面直接交互。在音乐播放器中,`Service`通常用来维持音乐播放的状态,即使用户离开应用,音乐也能继续播放。创建`Service`需要继承...

    service的生命周期以及启动方式

    总的来说,理解并熟练掌握Service的生命周期和启动方式是Android开发中的重要技能,它有助于优化应用性能,减少资源浪费,并实现高效的服务管理。在实际项目中,合理运用Service可以帮助我们实现后台任务的异步处理...

    Android Service基本知识

    Service不阻塞用户的交互,使得应用程序能够在后台安静地完成工作。 二、Service的类型 1. 启动服务(Started Service):由startService()方法启动,主要处理一次性任务,比如上传或下载文件。即使启动Service的...

    Android学习笔记-service[参考].pdf

    总结来说,Android的Service是实现后台任务的关键组件。理解Service的工作机制和生命周期对于开发高效、稳定的Android应用至关重要。开发者应根据需求选择合适类型的Service,并注意线程管理和资源管理,确保Service...

    2-Cramer-Rao-Lower-Bound.rar_Cramer-Rao_What Is the What

    **Cramer-Rao Lower Bound(克拉默-拉奥下界)** Cramer-Rao Lower Bound(CRLB),中文常称为克拉默-拉奥下界,是估计理论中的一个重要概念,它提供了一种衡量参数估计精度的下限。在统计推断中,当我们试图从一组...

Global site tag (gtag.js) - Google Analytics