| 在Android框架中,Service是比较难以理解的一部分,而网上的大多数资料最多就是讲述了如何去用Service,并没有对Service做一个深入的、系统的讲解。现在傻蛋将做一个系列文章,将对Service做一个由浅入深的梳理,帮助大家深入的掌握Android Service。 首先我们先来看看怎么使用Service,然后再谈Android Service的内部机制。 在Android中Service的启动方式有两种,今天先发第一种。 Service的启动方式一: 启动:Context.startService(new Intent(context,xxx.class)); 停止:Context.stopService() ; 我画了一个Service启动的流程图,相信大家一看就懂。Activity通过 Intent启动Service,如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果 Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 调用stopService就会触发Service的onDestroy()方法。 
 这一节里面傻蛋做了一个示例程序是一个音乐播放器,界面如下,功能很简单:播放、暂停、停止音乐、关闭Activity(这时Service仍然运行,继续播放音乐)、退出程序(停止音乐退出Activity)。 
 由于要控制Service的动作,傻蛋写了一个播放的通用类,这样在以后的课程中还能用上,代码如下: /**  
  * MyMediaController.java  
  * com.androidtest.service.mediaplayer  
  *  
  * Function: TODO  
  *  
  * ver date author  
  * ──────────────────────────────────  
  * 2011-5-16 Leon  
  *  
  * Copyright (c) 2011, 最牛网 All Rights Reserved.  
  */ 
  package com.zuiniuwang; 
  import java.io.Serializable; 
  import android.media.MediaPlayer; 
  /**  
  * ClassName:MyMediaController  
  * Function: Mediaplayer 的一个控制类,控制播放器的播放 暂停 停止 等动作  
  * REASON  
  *  
  * @author Leon  
  * @version  
  * @since Ver 1.1  
  * @Date 2011-5-16  
  */  
  public enum MyMediaController implements Serializable {  
      play {  
          @Override  
          public void execute() {  
              if (mediaPlayer != null && !mediaPlayer.isPlaying())  
              mediaPlayer.start();  
              // TODO Auto-generated method stub  
          }  
      },  
      pause {  
          @Override  
          public void execute() {  
              // TODO Auto-generated method stub  
              if (mediaPlayer != null && mediaPlayer.isPlaying()) {  
                  mediaPlayer.pause();  
              }  
          }  
      },  
      stop {  
          @Override  
          public void execute() {  
              // TODO Auto-generated method stub  
              if (mediaPlayer != null) {  
                  mediaPlayer.stop();  
                  try {  
                      // 在stop后如果要重新Start需要prepare一下  
                      mediaPlayer.prepare();  
                      // 从头播放  
                      mediaPlayer.seekTo(0);  
                  } catch (Exception e) {  
                      // TODO Auto-generated catch block  
                      e.printStackTrace();  
                  }  
              }  
          }  
      };  
      public static MediaPlayer mediaPlayer;  
      public abstract void execute();  
  }  
  然后是控制播放的Activity: /**  
  * MusicPlayer.java  
  * com.androidtest.activity  
  *  
  * Function: TODO  
  *  
  * ver date author  
  * ──────────────────────────────────  
  * 2011-5-15 Leon  
  *  
  * Copyright (c) 2011, 最牛网 All Rights Reserved.  
  */  
  package com.androidtest.activity.musicplayer;  
  import android.app.Activity;  
  import android.content.Intent;  
  import android.os.Bundle;  
  import android.util.Log;  
  import android.view.View;  
  import android.view.View.OnClickListener;  
  import android.widget.Button;  
  import com.androidtest.MyImageButton;  
  import com.androidtest.R;  
  import com.androidtest.service.mediaplayer.MyMediaController;  
  import com.androidtest.service.mediaplayer.NormalMusicService;  
  import com.androidtest.sharedpreferences.TestSharePreferences;  
  /**  
  * ClassName:MusicPlayer Function: TODO ADD FUNCTION Reason: TODO ADD REASON  
  *  
  * @author Leon  
  * @version  
  * @since Ver 1.1  
  * @Date 2011-5-15  
  */  
  public class NormalMusicPlayerActivity extends Activity implements OnClickListener {  
      private static final String TAG = NormalMusicPlayerActivity.class.getSimpleName();  
      private Intent intent ;  
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
          // TODO Auto-generated method stub  
          super.onCreate(savedInstanceState);  
          this.setContentView(R.layout.music_player_layout);  
          Button playButton = (Button) this.findViewById(R.id.play);  
          playButton.setOnClickListener(this);  
          Button pauseButton =(Button) this.findViewById(R.id.pause);  
          pauseButton.setOnClickListener(this);  
          Button stopButton =(Button)this.findViewById(R.id.stop);  
          stopButton.setOnClickListener(this);  
          Button closeActivityButton =(Button)this.findViewById(R.id.close);  
          closeActivityButton.setOnClickListener(this);  
          Button exitActivityButton =(Button)this.findViewById(R.id.exit);  
          exitActivityButton.setOnClickListener(this);  
          intent = new Intent("com.androidtest.service.mediaplayer.NormalMusicService");  
          TestSharePreferences testSharePreferences=(TestSharePreferences)this.getApplication();  
          Log.v(TAG , ""+testSharePreferences.getSharedInteger());  
      }  
      private void playAction(MyMediaController playType) {  
          Bundle bundle = new Bundle();  
          bundle.putSerializable(NormalMusicService.INTENT_KEY, playType);  
          intent.putExtras(bundle);  
          NormalMusicPlayerActivity.this.startService(intent);  
      }  
      @Override  
      public void onClick(View view) {  
          // TODO Auto-generated method stub  
          switch (view.getId()) {  
              case R.id.play:  
              Log.d(TAG, "play.......");  
              playAction(MyMediaController.play);  
              break;  
              case R.id.pause:  
              Log.d(TAG, "pause.......");  
              playAction(MyMediaController.pause);  
              break;  
              case R.id.stop:  
              Log.d(TAG, "stop.......");  
              playAction(MyMediaController.stop);  
              break;  
              case R.id.close:  
              Log.d(TAG, "close.......");  
              this.finish();  
              break;  
              case R.id.exit:  
              Log.d(TAG, "exit.......");  
              stopService(intent);  
              this.finish();  
          }  
      }  
  }  
  最后是Service类 /**  
  * MusicService.java  
  * com.androidtest.service  
  *  
  * Function: TODO  
  *  
  * ver date author  
  * ──────────────────────────────────  
  * 2011-5-15 Leon  
  *  
  * Copyright (c) 2011, 最牛网 All Rights Reserved.  
  */  
  package com.zuiniuwang.service;  
  import java.io.Serializable;  
  import android.app.Service;  
  import android.content.Intent;  
  import android.media.MediaPlayer;  
  import android.os.IBinder;  
  import android.util.Log;  
  import com.zuiniuwang.*;  
  /**  
  * ClassName:MusicService  
  * Function: TODO ADD FUNCTION  
  * Reason: TODO ADD REASON  
  *  
  * @author Leon  
  * @version  
  * @since Ver 1.1  
  * @Date 2011-5-15  
  */  
  public class NormalMusicService extends Service{  
      private String TAG = NormalMusicService.class.getSimpleName();  
      private MediaPlayer myMediaPlayer ;  
      public static final String INTENT_KEY= "action" ;  
      @Override  
      public IBinder onBind(Intent arg0) {  
          // TODO Auto-generated method stub  
          return null;  
      }  
      @Override  
      public void onCreate() {  
          // TODO Auto-generated method stub  
          Log.v(TAG , TAG+ " onCreate()");  
          super.onCreate();  
          if(myMediaPlayer==null){  
              myMediaPlayer=MediaPlayer.create(this, R.raw.test) ;  
              myMediaPlayer.setLooping(false);  
          }  
      }  
      @Override  
      public void onStart(Intent intent, int startId) {  
          // TODO Auto-generated method stub  
          Log.v(TAG , TAG + " onStart()");  
          super.onStart(intent, startId);  
          if(intent!=null){  
              MyMediaController mediaControl =(MyMediaController)intent.getSerializableExtra(NormalMusicService.INTENT_KEY);  
              mediaControl.mediaPlayer=myMediaPlayer;  
              mediaControl.execute();  
          }  
      }  
      @Override  
      public void onDestroy() {  
          // TODO Auto-generated method stub  
          super.onDestroy();  
          Log.v(TAG , " onDestroy");  
          if(myMediaPlayer!=null){  
              myMediaPlayer.stop();  
              myMediaPlayer.release();  
          }  
      }  
  }  
  附件为本实例的代码下载地址:http://down.51cto.com/data/326354 第二种是通过绑定的方式来启动Service。先看流程图。 
 绑定的方式和第一节的方式最大的不同就是在于,Activity可以和Service实现关联,当被关联的Activity结束后,相应的Service 也会停止,同时在绑定了的Activity中我们还可以回调我们在Service中定义的方法。在这里我们使用了 this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); 来启动Service,当Service创建了同时绑定了Activity之后,会回调我们定义的ServiceConnection(),从而传回IBinder接口,我们就能够调用Service中的方法了。这时候Activity就和 Service实现了绑定,Activity退出了Service就相应的退出了。Service的申明如下,intent filter 是对接收Service的过滤。 <service android:enabled="true" android:name=".service.mediaplayer.BindMusicService">  
<intent-filter>  
http://down.51cto.com/data/326354<action android:name="com.androidtest.service.mediaplayer.BindMusicService" />  
</intent-filter>  
</service>  
                          本节的源代码可以在此下载: http://down.51cto.com/data/326385 前两节中可以看到Activity和Service,context.startService对应着Service中的onStart()方法,context.onBindService对应的是Service中的onBind()方法。当我们继想绑定一个Service又想在 Activity停止时,Service不会停止,我们可以先StartService,然后再BindService()。这时候的流程图如下所示: 
 此时需要注意一个问题,当Activity退出的时候,Sercvice并不会停止,此时我们可以再进入Activity重新绑定,当这时候 Service就会调用onRebind()方法,但是调用onRebind()方法的前提是先前的onUnbind()方法执行成功,但是使用 super.onUnbind(intent)是执行不成功的,这时候我们要手动的使其返回true,再次绑定时Rebind()就会执行。否则,如果退出时不显示的指定onUnbind()为成功的话(为false),那么重新启动此Activity来绑定服务时,Service的onBind()方法和onReBind都不会执行,但是ServiceConnection方法确一定会回调了。这说明在Service中的onBind()方法不同于 onStart()方法不能被重复调用。 本节代码和上节代码大致相同,只不过是在bind之前先start service ,大家可以在DDMS中看onUnbind() onRebind()的调用情况。本节代码在此下载:http://down.51cto.com/data/326376 |