热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android多媒体之MediaPlayer

Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用Med


Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。


 


MediaPlayer的生命周期


 



 


这张状态转换图清晰的描述了 MediaPlayer 的各个状态,也列举了主要的方法的调用时序,每种方法只能在一些特定的状态下使用,如果使用时 MediaPlayer 的状态不正确则会引发 IllegalStateException 异常 。


 


Idle 状态: 当使用 new() 方法创建一个 MediaPlayer 对象或者调用了其 reset() 方法时,该 MediaPlayer 对象处于 idle 状态。这两种方法的一个重要差别就是:如果在这个状态下调用了 getDuration() 等方法(相当于调用时机不正确),通过 reset() 方法进入 idle 状态的话会触发 OnErrorListener.onError() ,并且 MediaPlayer 会进入 Error 状态;如果是新创建的 MediaPlayer 对象,则并不会触发 onError(), 也不会进入 Error 状态。


 


End 状态: 通过 release() 方法可以进入 End 状态,只要 MediaPlayer 对象不再被使用,就应当尽快将其通过 release() 方法释放掉,以释放相关的软硬件组件资源,这其中有些资源是只有一份的(相当于临界资源)。如果 MediaPlayer 对象进入了 End 状态,则不会在进入任何其他状态了。


 


Initialized 状态: 这个状态比较简单, MediaPlayer 调用 setDataSource() 方法就进入 Initialized 状态,表示此时要播放的文件已经设置好了。


 


Prepared 状态: 初始化完成之后还需要通过调用 prepare() 或 prepareAsync() 方法,这两个方法一个是同步的一个是异步的,只有进入 Prepared 状态,才表明 MediaPlayer 到目前为止都没有错误,可以进行文件播放。


 


Preparing 状态: 这个状态比较好理解,主要是和 prepareAsync() 配合,如果异步准备完成,会触发 OnPreparedListener.onPrepared() ,进而进入 Prepared 状态。


 


Started 状态: 显然, MediaPlayer 一旦准备好,就可以调用 start() 方法,这样 MediaPlayer 就处于 Started 状态,这表明 MediaPlayer 正在播放文件过程中。可以使用 isPlaying() 测试 MediaPlayer 是否处于了 Started 状态。 如果播放完毕,而又设置了循环播放,则 MediaPlayer 仍然会处于 Started 状态,类似的,如果在该状态下 MediaPlayer 调用了 seekTo() 或者 start() 方法均可以让 MediaPlayer 停留在 Started 状态。


 


Paused 状态: Started 状态下 MediaPlayer 调用 pause() 方法可以暂停 MediaPlayer ,从而进入 Paused 状态, MediaPlayer 暂停后再次调用 start() 则可以继续 MediaPlayer 的播放,转到 Started 状态,暂停状态时可以调用 seekTo() 方法,这是不会改变状态的。


 


Stop 状态: Started 或者 Paused 状态下均可调用 stop() 停止 MediaPlayer ,而处于 Stop 状态的 MediaPlayer 要想重新播放,需要通过 prepareAsync() 和 prepare() 回到先前的 Prepared 状态重新开始才可以。


 


PlaybackCompleted 状态: 文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发 OnCompletionListener 的 onCompletion() 方法。此时可以调用 start() 方法重新从头播放文件,也可以 stop() 停止 MediaPlayer ,或者也可以 seekTo() 来重新定位播放位置。


 


Error 状态: 如果由于某种原因 MediaPlayer 出现了错误,会触发 OnErrorListener.onError() 事件,此时 MediaPlayer 即进入 Error 状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。通过 setOnErrorListener(android.media.MediaPlayer.OnErrorListener) 可以设置该监听器。如果 MediaPlayer 进入了 Error 状态,可以通过调用 reset() 来恢复,使得 MediaPlayer 重新返回到 Idle 状态。


 


下面的程序是使用MediaPlayer播放音频文件并通过SeekBar显示进度的程序:


 





package com.example.musicplay;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
//import android.widget.SeekBar.OnSeekBarChangeListener;

@SuppressLint(
"HandlerLeak")
public class MusicActivity extends Activity
{
private MediaPlayer mp;
private Button play;
private Button pause;
private Button speed;
private Button stop;
private SeekBar seekbar;

private Handler myHandler;

@SuppressLint(
"HandlerLeak")
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);

initMusic();
initPlayerControl();
initHandler();

new Timer().schedule(new TimerTask()
{
@Override
public void run()
{
if(mp == null)
return;
if(mp.isPlaying()&&!seekbar.isPressed())
{
Message msg
= new Message();
msg.what
= 0x123;
myHandler.sendMessage(msg);
}
}
},
0,1000);
}

//初始化Handle
private void initHandler()
{
myHandler
= new Handler()
{
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
int position = mp.getCurrentPosition();
seekbar.setProgress(position );
}
}

};
}
//初始化mp,加载音乐
private void initMusic()
{
mp
= MediaPlayer.create(this, R.raw.xxx);
mp.setLooping(
false);
}
//初始化播放器控件
private void initPlayerControl()
{
play
= (Button)findViewById(R.id.play);
pause
= (Button)findViewById(R.id.pause);
speed
= (Button)findViewById(R.id.speed);
stop
= (Button)findViewById(R.id.stop);
seekbar
= (SeekBar)findViewById(R.id.my_seekbar);

play.setEnabled(
true);
pause.setEnabled(
false);
speed.setEnabled(
false);
stop.setEnabled(
false);
initSeekBar();

play.setOnClickListener(
new OnClickListener()
{
@Override
public void onClick(View v)
{
if(mp!=null)
{
mp.start();
play.setEnabled(
false);
pause.setEnabled(
true);
speed.setEnabled(
true);
stop.setEnabled(
true);
}
}
});

pause.setOnClickListener(
new OnClickListener()
{
@Override
public void onClick(View v)
{
if(mp!=null)
{
mp.pause();
play.setEnabled(
true);
pause.setEnabled(
false);
speed.setEnabled(
false);
stop.setEnabled(
false);
}
}
});

speed.setOnClickListener(
new OnClickListener()
{
@Override
public void onClick(View v)
{
if(mp!=null)
{
int positon = mp.getCurrentPosition();
int duration = mp.getDuration();
int headon = duration/20;
mp.seekTo(positon
+headon);
}
}
});

stop.setOnClickListener(
new OnClickListener()
{
@Override
public void onClick(View v)
{
if(mp!=null)
{
mp.stop();
play.setEnabled(
true);
pause.setEnabled(
false);
speed.setEnabled(
false);
stop.setEnabled(
false);
try
{
mp.prepare();
mp.seekTo(
0);
seekbar.setProgress(
0);
}
catch (IllegalStateException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
});
}

//初始化seekbar拖拽效果
private void initSeekBar()
{
seekbar.setMax(mp.getDuration());
// seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
// {
// @Override
// public void onStopTrackingTouch(SeekBar seekBar)
// {
// }
//
// @Override
// public void onStartTrackingTouch(SeekBar seekBar)
// {
// }
//
// @Override
// public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
// {
// if(mp == null)
// return;
// mp.seekTo(progress);
// }
// });
}
@Override
protected void onDestroy()
{
if(mp !=null)
mp.release();
}


}



<LinearLayout xmlns:android&#61;"http://schemas.android.com/apk/res/android"
xmlns:tools
&#61;"http://schemas.android.com/tools"
android:layout_width
&#61;"match_parent"
android:layout_height
&#61;"match_parent"
android:orientation
&#61;"vertical" >
<LinearLayout
android:layout_width&#61;"match_parent"
android:layout_height
&#61;"wrap_content"
android:orientation
&#61;"horizontal" >
<Button
android:id&#61;"&#64;&#43;id/play"
android:layout_width
&#61;"wrap_content"
android:layout_height
&#61;"wrap_content"
android:layout_weight
&#61;"1"
android:text
&#61;"play" />
<Button
android:id&#61;"&#64;&#43;id/pause"
android:layout_width
&#61;"wrap_content"
android:layout_height
&#61;"wrap_content"
android:layout_weight
&#61;"1"
android:text
&#61;"pause" />
<Button
android:id&#61;"&#64;&#43;id/speed"
android:layout_width
&#61;"wrap_content"
android:layout_height
&#61;"wrap_content"
android:layout_weight
&#61;"1"
android:text
&#61;"speed" />
<Button
android:id&#61;"&#64;&#43;id/stop"
android:layout_width
&#61;"wrap_content"
android:layout_height
&#61;"wrap_content"
android:layout_weight
&#61;"1"
android:text
&#61;"stop" />
LinearLayout>

<SeekBar
android:id&#61;"&#64;&#43;id/my_seekbar"
android:paddingLeft
&#61;"10dp"
android:paddingRight
&#61;"10dp"
android:layout_width
&#61;"match_parent"
android:layout_height
&#61;"wrap_content"
android:max
&#61;"100">
SeekBar>
LinearLayout>


 



 


 


转载于:https://www.cnblogs.com/Bigmouse123/p/3345706.html



推荐阅读
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 第一步:PyQt4Designer设计程序界面该部分设计类同VisvalStudio内的设计,改下各部件的objectName!设计 ... [详细]
  • 使用Flutternewintegration_test进行示例集成测试?回答首先在dev下的p ... [详细]
  • fileuploadJS@sectionscripts{<scriptsrc~Contentjsfileuploadvendorjquery.ui.widget.js ... [详细]
  • 人脸检测 pyqt+opencv+dlib
    一、实验目标绘制PyQT界面,调用摄像头显示人脸信息。在界面中,用户通过点击不同的按键可以实现多种功能:打开和关闭摄像头, ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
author-avatar
个性2402852463
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有