`
Jonathan樊
  • 浏览: 77344 次
  • 性别: Icon_minigender_2
  • 来自: 上海
社区版块
存档分类
最新评论

Android开发——Service的学习(下)

阅读更多

        Bound Service 是客户端-服务器模式的服务,它允许允许组件(比如activity)对其进行绑定、发送请求、接收响应、甚至进行进程间通信(IPC)。为了提供绑定,开发人员必须实现onBind()毁掉方法,该方法返回IBinder对象,它定义了客户端用来与服务交互的程序接口。

        客户端通过bindService()方法绑定到服务。此时,客户端必须提供ServiceConnection接口的实现类,它监视客户端和服务之间的连接。多个客户端能够同时连接服务器。然而仅当第一个客户端绑定时,系统调用服务的onBind()方法来获取IBinder对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder ,而不再调用 onBind() 。

        当最后一个客户端解除绑定后,系统会销毁服务(除非服务同时是通过 startService() 启动的)。

 

       一:创建Bound服务

        当你实现自己的bound服务时,最重要的工作就是定义 onBind() 回调方法所返回的接口。 有一下三种方式:

        (1)继承Binder类

        如果服务是你的应用程序所私有的,并且与客户端运行于同一个进程中(通常都是如此),你应该通过j继承 Binder 类来创建你的接口,并从 onBind() 返回一个它的实例。客户端接收该 Binder 对象并用它来直接访问 Binder 实现类或者 Service 中可用的公共(public)方法。

        如果服务只应用于私有应用程序,那这就是首选的技术方案。如果服务要被其它应用程序使用或者访问独立进程时,则不能使用该技术。

        仅当客户端与服务位于同一个应用程序和进程时,才可以。例如音乐播放我绑定activity到自己的服务来在后台播放音乐。

        

        实现步骤如下:

  • 在你的服务中,创建一个 Binder 的实例,实现以下三者之一:

             (1)包含客户端能调用的公共方法

             (2)返回当前service实例,其中包含客户端能够调用的公共方法

             (3)返回服务管理的其他类的实例,其中包含客户端能够调用的公共方法

 

  • 从回调方法 onBind() 中返回 Binder 类的实例。
  • 在客户端中,在回调方法 onServiceConnected() 中接收 Binder 类实例并用所提供的方法对绑定的服务进行调用。

      以下是一个服务的示例,它通过实现一个 Binder 来为客户端访问它内部的方法提供支持:

 

public class LocalService extends Service {
    // 给客户端的Binder
    private final IBinder mBinder = new LocalBinder();
    // 产生随机数
    private final Random mGenerator = new Random();


    public class LocalBinder extends Binder {
        LocalService getService() {
            // 返回LocalService 的实例,其中包含客户端可以调用的方法
            return LocalService.this;
        }
    }

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

    /**客户端可以调用的方法 */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

         LocalBinder为客户端提供了getService()方法,用于返回当前LocalService的实例。 这就让客户端可以调用服务中的公共方法。比如,客户端可以调用服务中的getRandomNumber()。

 

 

        以下是一个绑定到LocalService的activity,当点击按钮时,它会调用getRandomNumber():

 

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();
        // 绑定到 LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 解除绑定的服务
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** 点击Button时,调用此方法 */
    public void onButtonClick(View v) {
        if (mBound) {
            // 调用LocalService中的方法。
            // 不过,如果该调用会导致某些操作的挂起,那么调用应该放入单独的线程中进行,
            // 以免降低activity的性能。
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** 定义服务绑定的回调方法,将其传给bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // 我们已经绑定了服务, 将IBinder转型获得LocalService实例
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

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

       上述例子展示了客户端如何利用 ServiceConnection 和 onServiceConnected() 回调方法绑定到服务。

 

       

       (2)使用Messenger类

        如果你的服务需要与远程进程进行通信,那你可以使用一个 Messenger 来提供服务的接口。这种技术能让你无需使用AIDL就能进行进程间通信(IPC),这是执行进程间通信(IPC)最为简便的方式。

       

        以下是使用方法:

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

        通过这种方式,客户端不需要调用服务中的“方法”。取而代之的是,客户端发送“消息”( Message 对象),服务则接收位于 Handler 中的这个消息。

 

public class MessengerService extends Service {
   
    static final int MSG_SAY_HELLO = 1;

    /**
     * 服务处理客户端发来的消息
     * 服务实现了一个Handler
     */
    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);
            }
        }
    }

    /**
     * 给客户端使用的用来发送消息给 IncomingHandler.即为,第二步。
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * 返回一个接口用来给服务发送消息,即为,第三步
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

        客户端要做的全部工作就是根据服务返回的 IBinder 创建一个 Messenger ,并用 send() 方法发送一个消息。例如,以下是一个activity示例,它绑定到上述服务,并向服务发送 MSG_SAY_HELLO消息:

        

public class ActivityMessenger extends Activity {
    /** 和service沟通的Messenger. */
    Messenger mService = null;

    /** 是否已经绑定 */
    boolean mBound;

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

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

    public void sayHello(View v) {
        if (!mBound) return;
        //  创建并向服务发送一个消息,用到了已约定的'what'值
        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();
        //绑定到服务
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 解除绑定
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

         二:绑定到服务

 

 

        应用程序组件(客户端)可以通过调用 bindService() 来绑定服务。然后Android系统会调用服务的 onBind() 方法,返回一个用于和服务进行交互的 IBinder 。

       绑定是异步进行的。 bindService() 将立即返回,并不会向客户端返回 IBinder 。为了接收 IBinder ,客户端必须创建一个 ServiceConnection 的实例,并把它传给 bindService() 。 ServiceConnection 包含了一个回调方法,系统将会调用该方法来传递客户端所需的那个 IBinder 。

       注意: 只有activity、service和content provider才可以绑定到服务上——broadcast receiver不能绑定服务。

      因此,要把客户端绑定到服务上,你必须:

  • 实现 ServiceConnection 。你的实现代码必须重写两个回调方法:onServiceConnected()系统调用该方法来传递服务的 onBind() 方法所返回的 IBinder 。onServiceDisconnected()当与服务的联接发生意外中断时,比如服务崩溃或者被杀死时,Android系统将会调用该方法。客户端解除绑定时,不会调用该方法。
  • 调用 bindService() ,传入已实现的 ServiceConnection 。
  • 当系统调用你的 onServiceConnected() 回调方法时,你可以利用接口中定义的方法开始对服务的调用。
  • 要断开与服务的联接,请调用 unbindService()

        当客户端被销毁时,与服务的绑定也将解除。但与服务交互完毕后,或者你的activity进入pause状态时,你都应该确保解除绑定,以便服务能够在用完后及时关闭。 

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // 与服务的联接建立之后将会调用
    public void onServiceConnected(ComponentName className, IBinder service) {
        // 因为我们已经与明显是运行于同一进程中的服务建立了联接,
        // 我们就可以把它的IBinder转换为一个实体类并直接访问它。
      LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // 与服务的联接意外中断时将会调用
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

 利用这个 ServiceConnection ,客户端就能够把它传入 bindService() 完成与服务的绑定。

Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

 

1
0
分享到:
评论

相关推荐

    解析Google Android SDK——智能手机开发范例手册-下载代码

    总的来说,《解析Google Android SDK——智能手机开发范例手册》覆盖了Android开发的多个重要方面,从基础环境到高级技术,为开发者提供了全面的学习资源。通过深入研究这些章节,开发者不仅可以构建功能丰富的...

    Android开发——从小工到专家(书签)

    在Android开发领域,从新手入门到成为专家是一个不断学习和实践的过程。《Android开发——从小工...《Android开发——从小工到专家》书签版,无疑为这一过程提供了便利,让开发者可以迅速找到关键信息,提高学习效率。

    安卓Android源码——ServiceSample.rar

    在安卓应用开发中,`Service` 是一个非常重要的组件,它用于在后台执行长时间运行的操作,即使用户与应用程序没有交互。本篇将深入探讨 `ServiceSample` 示例代码,帮助你理解如何在 Android 中有效地使用 `Service`...

    安卓Android源码——GpsTracker源码.zip

    描述中的 "安卓Android源码——GpsTracker源码.zip" 与标题相呼应,暗示了这是一个关于Android开发的项目,特别关注于GPS跟踪功能的实现。源码的提供是为了让开发者能够深入理解如何在Android应用中集成和操作GPS...

    Android系统级深入开发——移植与调试 pdf

    《Android系统级深入开发...以上是《Android系统级深入开发——移植与调试》一书可能涵盖的主要内容,通过学习这些知识点,开发者能够掌握Android系统的核心技术,为创建高效、稳定且安全的系统和应用打下坚实基础。

    [Android Studio应用开发——基础入门与应用实战][方欣,杨勃][电子课件]

    【Android Studio应用开发——基础入门与应用实战】是针对初学者和希望提升Android应用程序开发技能的人群设计的一门课程。这门课程由专家方欣和杨勃共同编写,旨在通过电子课件的形式,深入浅出地讲解Android ...

    Android教材————

    在Android开发领域,掌握基础知识是至关重要的。这份"Android教材"包含了关于Activity生命周期、Service使用以及Content Provider的讲解,这些都是Android应用开发的核心概念。 首先,我们来深入理解第六讲——...

    Android学习之路——7.Service

    本篇文章将深入探讨“Android学习之路——7.Service”,分析Service的基本概念、使用方式以及常见应用场景,同时结合源码解析Service的工作原理,并提供一个实战Demo——Service_Demo。 一、Service基本概念 ...

    安卓Android源码——GoogleService.rar

    对于希望提升Android开发技能,尤其是与Google服务集成的开发者来说,深入研究这部分源码无疑会带来极大的收获。同时,这也是一种挑战,因为源码阅读需要扎实的编程基础和对Android系统架构的深入理解。但只要投入...

    安卓Android源码——应用开发揭秘源码.zip

    总的来说,通过深入学习《安卓Android源码——应用开发揭秘》中的源码,开发者不仅可以提升自己的编程技能,还能了解到Android系统的架构设计,从而在面对复杂问题时能够更有条理地分析和解决。这份源码资源是...

    Android 移动开发——打地鼠(Android Studio 版)Rat.zip

    【Android 移动开发——打地鼠(Android Studio 版)...这个“打地鼠”项目是学习Android开发的绝佳实践,它涵盖了Android开发的诸多核心概念,通过实际操作,开发者可以更深入地理解和掌握Android应用开发的各个环节。

    安卓Android源码——Gmail备份手机短信源码.zip

    在安卓(Android)平台上,开发人员经常需要处理各种任务,其中一项常见的需求是备份和恢复用户的短信。这个压缩包文件“安卓Android源码——Gmail备份手机短信源码.zip”提供了一个示例,展示了如何利用Android SDK...

    安卓Android源码——android Widget小组件开发.zip

    在安卓平台上,Widget小组件是应用与用户交互的一种方式,它们可以被添加到用户的主屏幕上,提供...这对于提高Android开发技能,尤其是对于那些希望为用户提供更直观、便捷服务的开发者来说,是一份宝贵的参考资料。

    安卓Android源码——节奏大师.rar

    1. **Resources**:在Android开发中,资源文件通常存放于`res`目录下,包括了应用程序的各种非代码资源,如界面布局(XML文件)、图像资源(PNG、JPEG等)、字符串资源(strings.xml)、颜色资源(colors.xml)、...

    安卓Android源码——app更新,实现service下载.rar

    在安卓(Android)平台上,开发一个能够实现应用自动更新的功能是一项常见的任务,它涉及到服务(Service)组件的使用...这涉及到了Android组件交互、网络编程、错误处理等多个方面,是Android开发中的一个重要技能。

    安卓Android源码——通讯录的开发_完整代码.zip

    本资源"安卓Android源码——通讯录的开发_完整代码.zip"提供了一个完整的通讯录应用开发案例,可以帮助开发者深入理解Android系统中关于联系人管理的底层机制以及UI设计的实践技巧。 1. **Android源码分析** - **...

    Android源码——sharedPref学习源码.zip

    在Android开发中,Shared Preferences是应用中保存轻量级数据的一种常见方式,它主要用于存储一些简单的键值对数据,如用户设置、应用状态等。在深入理解`sharedPref`的学习源码之前,我们先来回顾一下 Shared ...

    安卓Android源码——安卓Android经典开发---豆瓣网移动客户端+讲解+源代码.rar

    总之,这份“安卓Android源码——安卓Android经典开发---豆瓣网移动客户端+讲解+源代码.rar”资料包为开发者提供了一个实践和学习Android开发的宝贵资源。通过深入研究豆瓣移动客户端的源码,开发者不仅可以掌握...

    Android系统的Binder机制之一——Service_Manager

    ### Android系统的Binder机制之一——Service_Manager #### 一、引言 在深入探讨Android系统中的Binder机制之前,我们首先简要回顾一下Binder机制的基本概念及其重要性。Android系统基于Linux内核,但在进程间通信...

Global site tag (gtag.js) - Google Analytics