6.1.3 控制服务中的MediaPlayer

   然而,当使用一个服务时,从而向用户的活动向MediaPlayer发出命令变得更为复杂。

   为了能够控制MediaPlayer,需要把该活动与服务绑定在一起。一旦这样做,由于活动和服务在相同的进程中运行,因此可以直接调用该服务中的方法。如果正在创建一个远程服务,那么必须采起更深入一步的步骤。

   我们在上述活动中添加一个按钮,其标签为“have fun”。当单击这个按钮时,会使得MediaPlayer倒回来几秒中,然后继续播放音频文件。

   首先把该按钮添加到布局XML:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical"
 5     >
 6  <TextView 
 7      android:text="Backgroung Audio Player"
 8      android:layout_width="fill_parent"
 9      android:layout_height="wrap_content"></TextView>
10  <Button 
11      android:layout_width="wrap_content"
12      android:layout_height="wrap_content"
13      android:id="@+id/StartPlayerbackButton"
14      android:text="Start Playerback"/>
15  <Button 
16      android:layout_width="wrap_content"
17      android:layout_height="wrap_content"
18      android:id="@+id/StopPlayerbackButton"
19      android:text="Stop Playerback"/>
20  <Button 
21      android:layout_width="wrap_content"
22      android:layout_height="wrap_content"
23      android:id="@+id/HaveFunButton"
24      android:text="Have Fun"/>
25 </LinearLayout>

     然而在活动中会得到该按钮的引用,并且把它的OnClickListener设置为活动本身,就像现有的按钮一样。

 1 package com.nthm.androidtestActivity;
 2 
 3 import com.nthm.androidtest.R;
 4 import com.nthm.androidtestService.BackgroundAudioService;
 5 import android.app.Activity;
 6 import android.content.Intent;
 7 import android.os.Bundle;
 8 import android.view.View;
 9 import android.view.View.OnClickListener;
10 import android.widget.Button;
11 
12 public class BackgroundAudioActivity extends Activity implements
13         OnClickListener {
14     private Button startPlaybackButton;
15     private Button stopPlaybackButton;
16     private Button haveFunButton;
17     private Intent playbackServiceIntent;
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.backgroundaudioactivity);
22         startPlaybackButton=(Button) findViewById(R.id.StartPlayerbackButton);
23         stopPlaybackButton=(Button) findViewById(R.id.StopPlayerbackButton);
24         haveFunButton=(Button) findViewById(R.id.HaveFunButton);
25         startPlaybackButton.setOnClickListener(this);
26         stopPlaybackButton.setOnClickListener(this);
27         haveFunButton.setOnClickListener(this);
28         playbackServiceIntent=new Intent(this, BackgroundAudioService.class);
29     }

    为了使此按钮与服务中运行的MediaPlayer进行交互,必须绑定到该服务。完成该操作的方式是采用bindService方法。该方法接受一个意图;事实上,可以重用启动该服务的playbackServiceIntent、一个ServiceConnection对象以及一些指明当该服务没有运行时应该做什么的标志。

    在活动的onClick方法中,当按下startPlaybackButton时,在启动服务之后就会立刻绑定他。当调用stopPlaybackButton时,将与服务解除绑定。

 1     @Override
 2     public void onClick(View v) {
 3       if(v==startPlaybackButton){
 4           //startService(playbackServiceIntent);
 5           //finish();
 6           bindService(playbackServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
 7       }else if(v==stopPlaybackButton){
 8           //stopService(playbackServiceIntent);
 9           //finish();
10           unbindService(serviceConnection);
11       }

     你可能会注意到其中使用了一个没有定义的新对象:serviceConnection。过一会儿将对该对象进行介绍。

     接下来还需要完成onClick方法。因为该活动也被设置为新按钮的OnClickListener。所以同样应该处理这种情况以完成onClick方法。

1         else if(v==haveFunButton){
2           baService.havaFun();
3       }
4     }

    在新的部分中使用了另一个新对象:baService。baService是BackgroundAudioService类型的对象。现在仅仅是声明它,在创建serviceConnection对象时再介绍如何创建它。

1     private BackgroundAudioService baService;

    如前所述,我们仍然没有声明和实例化一个称为serviceConnection的对象。serviceConnection是一个ServiceConnection类型的对象,他是一个接口,用于监听所绑定服务的状态。

    现在开始介绍如何创建serviceConnection

1     private ServiceConnection serviceConnection=new ServiceConnection() {

    当通过一条bindService命令建立了与服务的连接,且该bindService命令把这个对象命名为serviceConnection(如同在bindService调用中所做的一样)时,将调用如下所示的onServiceConnected方法。

    向该方法传递一个IBinder对象,其实际上是从服务本身创建和提交的。在当前情况下,这个IBinder对象将使BackgroundAudioServiceBinder类型,我们将在服务中创建它。它将有一个方法用于返回我们的服务本身,称为getService。可以对该方法返回的对象直接操作,正如我们在单击haveFunButton时所做的一样。

1         @Override
2         public void onServiceConnected(ComponentName name, IBinder service) {
3             baService=((BackgroundAudioService.BackgroundAudioServiceBinder)service).getService();
4         }

    还需要一恶搞onServiceDisconnected方法来处理与服务断开时的情况。

1         @Override
2         public void onServiceDisconnected(ComponentName name) {
3             baService=null;
4         }
5     };
6 }

    现在可以关注在服务本身中需要做出的更改。

 1 package com.nthm.androidtestService;
 2 
 3 import com.nthm.androidtest.R;
 4 import android.app.Service;
 5 import android.content.Intent;
 6 import android.media.MediaPlayer;
 7 import android.media.MediaPlayer.OnCompletionListener;
 8 import android.os.Binder;
 9 import android.os.IBinder;
10 
11 public class BackgroundAudioService extends Service implements
12         OnCompletionListener {
13     private MediaPlayer mediaPlayer;

     需要在服务中做出的第一个改动是创建一个内部类,其扩展Binder,在请求时可以返回服务本身。

1 public class BackgroundAudioServiceBinder extends Binder{
2         public    BackgroundAudioService getService(){
3             return BackgroundAudioService.this;
4         }
5     }

   随后,将其实例化为一个对象,称为basBinder。

1 private final IBinder basBinder=new BackgroundAudioServiceBinder();

    并且重写onBind的实现以返回它。

1     @Override
2     public IBinder onBind(Intent intent) {
3         return basBinder;
4     }

    以上就是实现绑定多需要完成的工作。现在只需要处理“Having Fun”按钮。

    如前所述,当单击haveFunButton时,我们希望MediaPlayer倒回来几秒钟,在当前实现中,它将倒回2500毫秒或2.5秒。

1     public void havaFun(){
2         if(mediaPlayer.isPlaying()){
3             mediaPlayer.seekTo(mediaPlayer.getCurrentPosition()-2500);
4         }                                                                             
5     }

   以上就是服务中的更新。下面是除此之外的其他代码。

 1     @Override
 2     public void onCreate() {
 3         super.onCreate();
 4         mediaPlayer=MediaPlayer.create(this, R.raw.music);
 5         mediaPlayer.setOnCompletionListener(this);
 6     }
 7 
 8     @Override
 9     public int onStartCommand(Intent intent, int flags, int startId) {
10         if(!mediaPlayer.isPlaying()){
11             mediaPlayer.start();
12         }
13         return START_STICKY;
14     }
15 
16     @Override
17     public void onDestroy() {
18         if(mediaPlayer.isPlaying()){
19             mediaPlayer.stop();
20         }
21         mediaPlayer.release();
22         super.onDestroy();
23     }
24     @Override
25     public void onCompletion(MediaPlayer mp) {
26          stopSelf();
27     }
28 }

    既然已经搭建好了基础,现在就可以向服务中添加任何喜欢的功能,同时通过绑定服务,可以直接从活动中调用havaFun等各种方法。如果没有绑定服务,那么除了启动和停止该服务之外,我们将不能做任何其他事情。

    上述示例提供了一个良好的起点。可用于搭建在后台播放音频文件的应用程序,即当音频持续播放时允许用户继续执行其他的任务。可以对第二个示例进行扩展,以构建一个具有完整功能的音频播放应用程序。

原文地址:https://www.cnblogs.com/ZSS-Android/p/3941992.html