zoukankan      html  css  js  c++  java
  • Android Service 服务(三)—— bindService与remoteService

    (转自:http://blog.csdn.net/ithomer/article/details/7366396)

     

    一、bindService简介

    bindService是绑定Service服务,执行service服务中的逻辑流程。

    service通过Context.startService()方法开始,通过Context.stopService()方法停止;也可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己。只要调用一次stopService()方法便可以停止服务,无论之前它被调用了多少次的启动服务方法。

    客户端建立一个与Service的连接,并使用此连接与Service进行通话,通过Context.bindService()方法来绑定服务,Context.unbindService()方法来关闭服务。多个客户端可以绑定同一个服务,如果Service还未被启动,bindService()方法可以启动服务。

    上面startService()和bindService()两种模式是完全独立的。你可以绑定一个已经通过startService()方法启动的服务。例如:一个后台播放音乐服务可以通过startService(intend)对象来播放音乐。可能用户在播放过程中要执行一些操作比如获取歌曲的一些信息,此时activity可以通过调用bindServices()方法与Service建立连接。这种情况下,stopServices()方法实际上不会停止服务,直到最后一次绑定关闭。

    二、bindService启动流程

    context.bindService()  ——> onCreate()  ——> onBind()  ——> Service running  ——> onUnbind()  ——> onDestroy()  ——> Service stop
     

    onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。 

    所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

    在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。详见:Android Service 服务(一)—— Service

    三、bindService生命周期

    像一个activity那样,一个service有些可以用来改变状态的生命周期方法,但是比activity的方法少,service生命周期方法只有三个public

       void onCreate()

       void onStart(Intent intent)

       void onDestroy()

    通过实现这三个生命周期方法,你可以监听service的两个嵌套循环的生命周期:

    1、整个生命周期

     service的整个生命周期是在onCreate()和onDestroy()方法之间。和activity一样,在onCreate()方法里初始化,在onDestroy()方法里释放资源。例如,一个背景音乐播放服务可以在onCreate()方法里播放,在onDestroy()方法里停止。

    2、活动的生命周期

     service的活动生命周期是在onStart()之后,这个方法会处理通过startServices()方法传递来的Intent对象。音乐service可以通过开打intent对象来找到要播放的音乐,然后开始后台播放。注: service停止时没有相应的回调方法,即没有onStop()方法,只有onDestroy()销毁方法。

    onCreate()方法和onDestroy()方法是针对所有的services,无论它们是否启动,通过Context.startService()和Context.bindService()方法都可以访问执行。然而,只有通过startService()方法启动service服务时才会调用onStart()方法。

     

    如果一个service允许别人绑定,那么需要实现以下额外的方法:

           IBinder onBind(Intent intent)

           boolean onUnbind(Intent intent)

           void onRebind(Intent intent)

    onBind()回调方法会继续传递通过bindService()传递来的intent对象

    onUnbind()会处理传递给unbindService()的intent对象。如果service允许绑定,onBind()会返回客户端与服务互相联系的通信句柄(实例)。

    如果建立了一个新的客户端与服务的连接,onUnbind()方法可以请求调用onRebind()方法。

    记住: 任何服务无论它怎样建立,默认客户端都可以连接,所以任何service都能够接收onBind()和onUnbind()方法

    四、bindService示例

    Activity

    1. public class PlayBindMusic extends Activity implements OnClickListener {  
    2.   
    3.     private Button playBtn;  
    4.     private Button stopBtn;  
    5.     private Button pauseBtn;  
    6.     private Button exitBtn;  
    7.   
    8.     private BindMusicService musicService;  
    9.   
    10.     @Override  
    11.     public void onCreate(Bundle savedInstanceState) {  
    12.         super.onCreate(savedInstanceState);  
    13.   
    14.         setContentView(R.layout.bind_music_service);  
    15.   
    16.         playBtn = (Button) findViewById(R.id.play);  
    17.         stopBtn = (Button) findViewById(R.id.stop);  
    18.         pauseBtn = (Button) findViewById(R.id.pause);  
    19.         exitBtn = (Button) findViewById(R.id.exit);  
    20.   
    21.         playBtn.setOnClickListener(this);  
    22.         stopBtn.setOnClickListener(this);  
    23.         pauseBtn.setOnClickListener(this);  
    24.         exitBtn.setOnClickListener(this);  
    25.   
    26.         connection();  
    27.     }  
    28.   
    29.     private void connection() {  
    30.         Intent intent = new Intent("com.homer.bind.bindService");  
    31.         bindService(intent, sc, Context.BIND_AUTO_CREATE);          // bindService  
    32.     }  
    33.   
    34.     @Override  
    35.     public void onClick(View v) {  
    36.         switch (v.getId()) {  
    37.         case R.id.play:  
    38.             musicService.play();  
    39.             break;  
    40.         case R.id.stop:  
    41.             if (musicService != null) {  
    42.                 musicService.stop();  
    43.             }  
    44.             break;  
    45.         case R.id.pause:  
    46.             if (musicService != null) {  
    47.                 musicService.pause();  
    48.             }  
    49.             break;  
    50.         case R.id.exit:  
    51.             this.finish();  
    52.             break;  
    53.         }  
    54.     }  
    55.   
    56.     private ServiceConnection sc = new ServiceConnection() {  
    57.   
    58.         @Override  
    59.         public void onServiceConnected(ComponentName name, IBinder service) {       //connect Service  
    60.             musicService = ((BindMusicService.MyBinder) (service)).getService();  
    61.             if (musicService != null) {  
    62.                 musicService.play();        // play music  
    63.             }  
    64.         }  
    65.           
    66.         @Override  
    67.         public void onServiceDisconnected(ComponentName name) {                 //disconnect Service  
    68.             musicService = null;  
    69.         }  
    70.     };  
    71.       
    72.     @Override  
    73.     public void onDestroy(){  
    74.         super.onDestroy();  
    75.           
    76.         if(sc != null){  
    77.             unbindService(sc);  
    78.         }  
    79.     }  
    80. }  


    Service

    1. public class BindMusicService extends Service {  
    2.   
    3.     private MediaPlayer mediaPlayer;  
    4.   
    5.     private final IBinder binder = new MyBinder();  
    6.   
    7.     public class MyBinder extends Binder {  
    8.         BindMusicService getService() {  
    9.             return BindMusicService.this;  
    10.         }  
    11.     }  
    12.   
    13.     @Override  
    14.     public IBinder onBind(Intent intent) {  
    15.         return binder;  
    16.     }  
    17.   
    18.     @Override  
    19.     public void onCreate() {  
    20.         super.onCreate();  
    21.           
    22.         Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();  
    23.     }  
    24.   
    25.     @Override  
    26.     public void onDestroy() {  
    27.         super.onDestroy();  
    28.           
    29.         Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);  
    30.         if(mediaPlayer != null){  
    31.             mediaPlayer.stop();  
    32.             mediaPlayer.release();  
    33.         }  
    34.     }  
    35.   
    36.       
    37.     public void play() {  
    38.         if (mediaPlayer == null) {  
    39.             mediaPlayer = MediaPlayer.create(this, R.raw.tmp);  
    40.             mediaPlayer.setLooping(false);  
    41.         }  
    42.         if (!mediaPlayer.isPlaying()) {  
    43.             mediaPlayer.start();  
    44.         }  
    45.     }  
    46.   
    47.     public void pause() {  
    48.         if (mediaPlayer != null && mediaPlayer.isPlaying()) {  
    49.             mediaPlayer.pause();  
    50.         }  
    51.     }  
    52.   
    53.     public void stop() {  
    54.         if (mediaPlayer != null) {  
    55.             mediaPlayer.stop();  
    56.             try {  
    57.                 mediaPlayer.prepare();      // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数  
    58.             } catch (IOException ex) {  
    59.                 ex.printStackTrace();  
    60.             }  
    61.         }  
    62.     }  
    63. }  


    AndroidManifest.xml

    1. <service  
    2.     android:name=".bind.BindMusicService"  
    3.     android:enabled="true" >  
    4.     <intent-filter>  
    5.         <action android:name="com.homer.bind.bindService" />  
    6.     </intent-filter>  
    7. </service>  



    五、代码解析

    1、 Activity中,Intent intent = new Intent("com.homer.bind.bindService"); 构建一个service的action,然后bindService(intent, sc, Context.BIND_AUTO_CREATE); 绑定服务

    2、 Activity中,通过private ServiceConnection sc = new ServiceConnection() 建立一个Service连接,onServiceConnected()获取Service实例,onServiceDisconnected()释放连接

    3、 Service中,重载onBind(Intent intent)方法,返回Service实例(即BindMusicService)给Activity,然后执行onCreate()函数(注:bindService不执行onStart()函数)

    4、 Activity中,通过返回的Service实例musicService,执行音乐播放的操作(play、pause、stop等)

    六、Remote Service拓展

    通常每个应用程序都在它自己的进程内运行,但有时需要在进程之间传递对象(IPC通信),你可以通过应用程序UI的方式写个运行在一个不同的进程中的service。在android平台中,一个进程通常不能访问其它进程中的内存区域。所以,他们需要把对象拆分成操作系统能理解的简单形式,以便伪装成对象跨越边界访问。编写这种伪装代码相当的枯燥乏味,好在android为我们提供了AIDL工具可以来做这件事。
     
    AIDL(android接口描述语言)是一个IDL语言,它可以生成一段代码,可以使在一个android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如在一个Activity中)访问另一个进程中(例如一个Service)某个对象的方法,你就可以使用AIDL来生成这样的代码来伪装传递各种参数。
     
    要使用AIDL,Service需要以aidl文件的方式提供服务接口,AIDL工具将生成一个相应的java接口,并且在生成的服务接口中包含一个功能调用的stub服务桩类。Service的实现类需要去继承这个stub服务桩类。Service的onBind方法会返回实现类的对象,之后你就可以使用它了,参见下例:

    IMusicControlService.aidl

    1. package com.homer.remote;  
    2.   
    3. interface IMusicControlService{  
    4.         void play();   
    5.         void stop();   
    6.         void pause();  
    7. }  
     
    使用eclipse的Android插件,会根据这个aidl文件生成一个Java接口类,生成的接口类中会有一个内部类Stub类,Service来继承该Stub类:
    Service
    1. public class RemoteMusicService extends Service {  
    2.   
    3.     private MediaPlayer mediaPlayer;  
    4.   
    5.     @Override  
    6.     public IBinder onBind(Intent intent) {  
    7.         return binder;  
    8.     }  
    9.   
    10.     private final IMusicControlService.Stub binder = new IMusicControlService.Stub() {  
    11.   
    12.         @Override  
    13.         public void play() throws RemoteException {  
    14.             if (mediaPlayer == null) {  
    15.                 mediaPlayer = MediaPlayer.create(RemoteMusicService.this, R.raw.tmp);  
    16.                 mediaPlayer.setLooping(false);  
    17.             }  
    18.             if (!mediaPlayer.isPlaying()) {  
    19.                 mediaPlayer.start();  
    20.             }  
    21.         }  
    22.   
    23.         @Override  
    24.         public void pause() throws RemoteException {  
    25.             if (mediaPlayer != null && mediaPlayer.isPlaying()) {  
    26.                 mediaPlayer.pause();  
    27.             }             
    28.         }  
    29.   
    30.         @Override  
    31.         public void stop() throws RemoteException {  
    32.             if (mediaPlayer != null) {  
    33.                 mediaPlayer.stop();  
    34.                 try {  
    35.                     mediaPlayer.prepare();      // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数  
    36.                 } catch (IOException ex) {  
    37.                     ex.printStackTrace();  
    38.                 }  
    39.             }  
    40.         }  
    41.     };  
    42.       
    43.     @Override  
    44.     public void onDestroy() {  
    45.         super.onDestroy();  
    46.           
    47.         if(mediaPlayer != null){  
    48.             mediaPlayer.stop();  
    49.             mediaPlayer.release();  
    50.         }  
    51.     }  
    52. }  

    客户端(Activity)应用连接到这个Service时,onServiceConnected方法将被调用,客户端就可以获得IBinder对象。参看下面的客户端onServiceConnected方法:

    Activity

    1. public class PlayRemoteMusic extends Activity implements OnClickListener {  
    2.   
    3.     private Button playBtn;  
    4.     private Button stopBtn;  
    5.     private Button pauseBtn;  
    6.     private Button exitBtn;  
    7.   
    8.     private IMusicControlService musicService;  
    9.   
    10.     @Override  
    11.     public void onCreate(Bundle savedInstanceState) {  
    12.         super.onCreate(savedInstanceState);  
    13.         setContentView(R.layout.remote_music_service);  
    14.   
    15.         playBtn = (Button) findViewById(R.id.play);  
    16.         stopBtn = (Button) findViewById(R.id.stop);  
    17.         pauseBtn = (Button) findViewById(R.id.pause);  
    18.         exitBtn = (Button) findViewById(R.id.exit);  
    19.   
    20.         playBtn.setOnClickListener(this);  
    21.         stopBtn.setOnClickListener(this);  
    22.         pauseBtn.setOnClickListener(this);  
    23.         exitBtn.setOnClickListener(this);  
    24.   
    25.         connection();  
    26.     }  
    27.   
    28.     private void connection() {  
    29.         Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");  
    30.         bindService(intent, sc, Context.BIND_AUTO_CREATE);              // bindService  
    31.     }  
    32.   
    33.     @Override  
    34.     public void onClick(View v) {  
    35.   
    36.         try {  
    37.             switch (v.getId()) {  
    38.             case R.id.play:  
    39.                 musicService.play();  
    40.                 break;  
    41.             case R.id.stop:  
    42.                 if (musicService != null) {  
    43.                     musicService.stop();  
    44.                 }  
    45.                 break;  
    46.             case R.id.pause:  
    47.                 if (musicService != null) {  
    48.                     musicService.pause();  
    49.                 }  
    50.                 break;  
    51.             case R.id.exit:  
    52.                 this.finish();  
    53.                 break;  
    54.             }  
    55.         } catch (RemoteException e) {  
    56.             e.printStackTrace();  
    57.         }  
    58.     }  
    59.   
    60.     private ServiceConnection sc = new ServiceConnection() {  
    61.         @Override  
    62.         public void onServiceConnected(ComponentName name, IBinder service) {       //connect Service  
    63.             musicService = IMusicControlService.Stub.asInterface(service);  
    64.         }  
    65.   
    66.         @Override  
    67.         public void onServiceDisconnected(ComponentName name) {                 //disconnect Service  
    68.             musicService = null;  
    69.         }  
    70.   
    71.     };  
    72.       
    73.     @Override  
    74.     public void onDestroy(){  
    75.         super.onDestroy();  
    76.           
    77.         if(sc != null){  
    78.             unbindService(sc);              // unBindService  
    79.         }  
    80.     }  
    81. }  


    Remote Service流程总结:

    1、 Activity(客户端)中,Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");构建intent,然后bindService(intent, sc, Context.BIND_AUTO_CREATE);绑定服务

    2、 Activity(客户端)中,通过ServiceConnection()重载onServiceConnected()建立连接,获取Service.Stub实例;onServiceDisconnected()释放连接(与bindService类似)

    3、 Service中,通过重载onBind(Intent intent) 返回Service.Stub实例,但Service.Stub类是由aidl文件生成的接口类中的一个内部类Stub类,Service来继承该Stub类

    4、 Activity中,通过操作Service实例(musicService),执行音乐播放操作(play、pause、stop等)

    源码下载

    参考推荐:

    Service (android developer)

    Android Service 服务(一)—— Service

    Android Service 服务(二)—— BroadcastReceiver

    android中service和aidl详细整理

    Android Service AIDL

    android笔记--Service与AIDL

  • 相关阅读:
    java基础——DecimalFormat
    剑指——重建二叉树
    error error: illegal character: 'u3000'
    Android: Unhandled exception java.net.malformedurlexception 异常笔记
    Android获取系统时间
    java基础——hashCode笔记
    golang 红黑树
    golang 实现跳表skiplist
    快排
    堆排序
  • 原文地址:https://www.cnblogs.com/shide/p/4016018.html
Copyright © 2011-2022 走看看