6.2.1 HTTP音频播放

   要探讨的最简单的情况是仅仅播放在线的,可通过HTTP对其进行访问的音频文件。

   下面就是一个这样的文件,它存在于服务器上:

    www.baidu.com/music

    下面是一个活动的示例,其使用MediaPlayer来演示如何播放通过HTTP获得的音频。

 1 package com.nthm.androidtestActivity;
 2 
 3 import java.io.IOException;
 4 import com.nthm.androidtest.R;
 5 import android.app.Activity;
 6 import android.media.MediaPlayer;
 7 import android.os.Bundle;
 8 
 9 public class AudioHTTPPlayer extends Activity {
10     private MediaPlayer mediaPlayer;
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.audiohttpplayeractivity);

     当创建活动时,通过调用MediaPlayer的无参数构造函数实例化一个通用的MediaPlayer对象。这种使用MediaPlayer的方式与之前所看到的方式不同,而且它要求采取一些额外的步骤才能播放音频。

1         mediaPlayer=new MediaPlayer();

    具体来说,需要调用setDataSource方法,并传入想要播放的音频文件的HTTP位置。该方法可能会抛出一个IOException,所以同时必须捕获和处理异常。

1         try {
2             mediaPlayer.setDataSource("www.baidu.com/music");

    随后我们调用prepare方法,接着是调用start方法,在此之后应该开始播放音频。

1             mediaPlayer.prepare();
2             mediaPlayer.start();
3         } catch (IllegalArgumentException | SecurityException
4                 | IllegalStateException | IOException e) {
5             e.printStackTrace();
6         }
7     }
8 }

    运行此示例时,你可能会注意到从加载应用程序到播放音频之间有一个明显的滞后时间。延迟的长度取决于用于构建电话Internet连接的数据网络的速度(不考虑其他因素)。

    如果在整个代码中添加Log或Toast消息,那么将看到在调用prepare方法和start方法之间发生了这样的延迟。在运行prepare方法期间。MediaPlayer将填充一个缓冲区,因此即使网络速度缓慢也能平稳的播放音频。

    当这么操作时,prepare方法实际上发生了阻塞。这意味着使用该方法的应用程序可能会直到prepare方法完成之后才能响应。幸运的是,有一种方法可以解决这个问题,即使用prepareAsync方法。该方法会立即返回,并在后台执行缓冲和其他工作,从而允许应用程序继续运行。

   然后,问题就变成需要注意MediaPlayer对象的状态,以及实现各种回调来帮助跟踪它的状态。

   为了掌握MediaPlayer对象可能处于的各种状态,查看一下Android API参考手册中MediaPlayer页的相关状态图会有所帮助。

   下面是完整的MediaPlayer示例,其使用了prepareAsync方法,同时实现了几个监听来跟踪MediaPlayer的状态。

 1 package com.nthm.androidtestActivity;
 2 
 3 import java.io.IOException;
 4 import com.nthm.androidtest.R;
 5 import android.app.Activity;
 6 import android.media.MediaPlayer;
 7 import android.media.MediaPlayer.OnBufferingUpdateListener;
 8 import android.media.MediaPlayer.OnCompletionListener;
 9 import android.media.MediaPlayer.OnErrorListener;
10 import android.media.MediaPlayer.OnPreparedListener;
11 import android.os.Bundle;
12 import android.view.View;
13 import android.view.View.OnClickListener;
14 import android.widget.Button;
15 import android.widget.TextView;

     在这个版本的HTTP音频播放器中实现了几个接口。其中的两个接口OnPreparedListener和OnCompletionListener将帮助跟踪MediaPlayer的状态,从而不必在不应该的时候尝试播放或停止音频。

1 public class AudioHTTPPlayer extends Activity implements OnClickListener,OnErrorListener,
2            OnCompletionListener,OnBufferingUpdateListener,OnPreparedListener{
3     private MediaPlayer mediaPlayer;

    此活动的界面包含启动和停止按钮、一个用于显示状态的TextView以及一个用于显示缓冲区已填充的百分比的TextView。

1     private Button stopButton;
2     private Button startButton;
3     private TextView statusTextView;
4     private TextView bufferValueTextView;
5     
6     @Override
7     protected void onCreate(Bundle savedInstanceState) {
8         super.onCreate(savedInstanceState);
9         setContentView(R.layout.audiohttpplayeractivity);

    在onCreate方法中设置stopButtonstartButton为禁用。他们在运行应用程序期间会被启用或禁用。以下代码演示他们触发的方法时可用还是不可用。

 1         stopButton=(Button) findViewById(R.id.EndButton);
 2         startButton=(Button) findViewById(R.id.StartButton);
 3         stopButton.setOnClickListener(this);
 4         startButton.setOnClickListener(this);
 5         stopButton.setEnabled(false);
 6         startButton.setEnabled(false);
 7         
 8         bufferValueTextView=(TextView) findViewById(R.id.BufferValueTextView);
 9         statusTextView=(TextView) findViewById(R.id.StatusDisplayTextView);
10         statusTextView.setText("onCreate");

     在实例化MediaPlayer对象之后,将把活动注册为OnErrorListener,OnCompletionListener,OnBufferingUpdateListener和OnPreparedListener。

1         mediaPlayer=new MediaPlayer();
2         mediaPlayer.setOnCompletionListener(this);
3         mediaPlayer.setOnErrorListener(this);
4         mediaPlayer.setOnBufferingUpdateListener(this);
5         mediaPlayer.setOnPreparedListener(this);
6         statusTextView.setText("MediaPlayer Create");

    接下来将使用音频文件的URL调用setDataSource。

1         try {
2             mediaPlayer.setDataSource("www.baidu.com/music");
3             statusTextView.setText("setDataSource done");
4             statusTextView.setText("calling prepareAsync");

    最后调用prepareAsync方法,它将在后台开始缓冲音频文件并返回。当准备工作完成时,由于活动被注册了MediaPlayer的OnPreparedListener,因此将调用活动的onPrepared方法。

1             mediaPlayer.prepareAsync();
2         } catch (IllegalArgumentException | SecurityException
3                 | IllegalStateException | IOException e) {
4             e.printStackTrace();
5         }
6     }

    接下来是对两个按钮实现onClick方法。当按下stopButton时,将调用MediaPlayer的pause方法。当按下startButton时,将调用MediaPlayer的start方法。

 1     @Override
 2     public void onClick(View v) {
 3         if(v==stopButton){
 4             mediaPlayer.pause();
 5             statusTextView.setText("pause called");
 6             startButton.setEnabled(true);
 7         }else if(v==startButton){
 8             mediaPlayer.start();
 9             statusTextView.setText("start called");
10             startButton.setEnabled(false);
11             stopButton.setEnabled(true);
12         }
13     }

    如果MediaPlayer进入错误状态,那么将调用活动的onError方法,该活动注册为MediaPlayer的OnErrorListener。下面的onError方法显示了各种在MediaPlayer类中指定的常量。

1     @Override
2     public boolean onError(MediaPlayer mp, int what, int extra) {
3         
4         return false;
5     }

    当MediaPlayer完成播放音频文件时,将调用活动的onCompletion方法,该活动注册为MediaPlayer的OnCompletionListener。这表明可以再次开始播放过。

1     @Override
2     public void onCompletion(MediaPlayer mp) {
3         statusTextView.setText("onCompletion called");
4         startButton.setEnabled(true);
5         stopButton.setEnabled(false);
6     }

    当MediaPlayer正在缓冲时,将调用活动的onBufferingUpdate方法,该活动注册为MediaPlayer的OnBufferingUpdateListener。传入已填充的缓冲区百分比。

1     @Override
2     public void onBufferingUpdate(MediaPlayer mp, int percent) {
3         bufferValueTextView.setText(""+percent+"%");
4     }

    当完成prepareAsync方法时,将调用活动的onPrepared方法,该活动注册为MediaPlayer的OnPreparedListener。这表明音频准备播放,因此在下面的方法中把startButton设置为启用。

1     @Override
2     public void onPrepared(MediaPlayer mp) {
3         statusTextView.setText("onPrepared called");
4         startButton.setEnabled(true);
5     }
6 }

   下面是与上述活动相关联的布局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:id="@+id/TextView01"
 8      android:text="Status"
 9      android:layout_width="fill_parent"
10      android:layout_height="wrap_content"></TextView>
11  <TextView 
12      android:id="@+id/StatusDisplayTextView"
13      android:text="Unknown"
14      android:layout_width="fill_parent"
15      android:layout_height="wrap_content"></TextView>
16  <TextView 
17      android:id="@+id/BufferValueTextView"
18      android:text="0%"
19      android:layout_width="fill_parent"
20      android:layout_height="wrap_content"></TextView>
21  <Button 
22      android:layout_width="wrap_content"
23      android:layout_height="wrap_content"
24      android:id="@+id/StartButton"
25      android:text="Start"/>
26  <Button 
27      android:layout_width="wrap_content"
28      android:layout_height="wrap_content"
29      android:id="@+id/EndButton"
30      android:text="Stop"/>
31 </LinearLayout>

   如上所示,MediaPlayer有一个良好的功能集,用来处理通过HTTP在线获取的音频文件。

posted on 2014-08-29 08:57  宁静致远,一览众山小  阅读(629)  评论(0编辑  收藏  举报

导航