本文利用SurfaceView来实现视频的播放

本文地址:http://www.cnblogs.com/wuyudong/p/5851156.html,转载请注明源地址。

在main.xml布局文件添加用于视频画面绘制的SurfaceView 控件:

<SurfaceView android:layout_width="fill_parent" android:layout_height="240dip" android:id="@+id/surfaceView" />

项目布局设计:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" > <EditText
android:id="@+id/et_path"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入视频文件的路径" /> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <Button
android:id="@+id/bt_play"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="播放" /> <Button
android:id="@+id/bt_pause"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="暂停" /> <Button
android:id="@+id/bt_replay"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="重播" /> <Button
android:id="@+id/bt_stop"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止" />
</LinearLayout> <SurfaceView
android:id="@+id/sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/> </LinearLayout>

大部分代码和《Android 多媒体播放API简介》中的完全一样,修改一点点代码即可:

public class MainActivity extends Activity implements OnClickListener {

    private EditText et_path;
private Button bt_play, bt_replay, bt_pause, bt_stop;
private SurfaceView sv; private MediaPlayer mediaPlayer; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); sv = (SurfaceView)findViewById(R.id.sv);
et_path = (EditText) findViewById(R.id.et_path);
bt_play = (Button) findViewById(R.id.bt_play);
bt_replay = (Button) findViewById(R.id.bt_replay);
bt_pause = (Button) findViewById(R.id.bt_pause);
bt_stop = (Button) findViewById(R.id.bt_stop); bt_pause.setOnClickListener(this);
bt_play.setOnClickListener(this);
bt_replay.setOnClickListener(this);
bt_stop.setOnClickListener(this); } @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_play:
play();
break;
case R.id.bt_replay:
replay();
break;
case R.id.bt_stop:
stop();
break;
case R.id.bt_pause:
pause();
break;
default:
break;
}
} /**
* 暂停音乐
*/
private void pause() {
if ("继续".equals(bt_pause.getText().toString().trim())) {
mediaPlayer.start();
bt_pause.setText("暂停");
return;
}
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
bt_pause.setText("继续");
return;
}
} /**
* 重新播放
*/
private void replay() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
return;
}
play();
} /**
* 停止播放音乐
*/
private void stop() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release(); // 记得释放资源
mediaPlayer = null;
bt_play.setEnabled(true);
}
} /**
* 播放音乐
*/
private void play() {
String path = et_path.getText().toString().trim();
File file = new File(path);
if (file.exists() && file.length() > 0) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); /* 设置Video影片以SurfaceHolder播放 */
mediaPlayer.setDisplay(sv.getHolder()); mediaPlayer.setDataSource(path);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
bt_play.setEnabled(true);
}
} ); bt_play.setEnabled(false);
} catch (Exception e) {
Toast.makeText(this, "播放失败", 0).show();
e.printStackTrace();
}
} else {
Toast.makeText(this, "文件不存在", 0).show();
} } }

运行项目效果如下:

但是上面的代码有点问题,那就是当点击home或返回屏幕主界面后,在回到播放页面,视频黑屏

原因:

SurfaceView内部维护双缓冲,消耗内存资源

如果发现当前SurfaceView 用户可见的时候,创建SurfaceView的holder

如果SurfaceView变成用户不可见的时候  销毁SurfaceView的holder

为了观察SurfaceView的生命周期,可以添加下面的代码进行打印追踪:

    sv.getHolder().addCallback(new Callback() {

            @Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("holder被销毁了");
} @Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("holder被创建了"); } @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
System.out.println("holder的大小变化了");
}
}); }

logcat中打印下面的信息:

09-07 11:36:34.613: I/System.out(28858): holder被创建了
09-07 11:36:34.623: I/System.out(28858): holder的大小变化了

返回主界面

09-07 11:39:08.245: I/System.out(28858): holder被销毁了

再次回到视频界面

09-07 11:39:39.405: I/System.out(28858): holder被创建了
09-07 11:39:39.405: I/System.out(28858): holder的大小变化了

可以看到,每次回到视频界面,holder都会被重新创建

修改后的代码如下:

public class MainActivity extends Activity implements OnClickListener {

    private EditText et_path;
private Button bt_play, bt_replay, bt_pause, bt_stop;
private SurfaceView sv; private MediaPlayer mediaPlayer;
private int currentPosition; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); sv = (SurfaceView) findViewById(R.id.sv);
et_path = (EditText) findViewById(R.id.et_path);
bt_play = (Button) findViewById(R.id.bt_play);
bt_replay = (Button) findViewById(R.id.bt_replay);
bt_pause = (Button) findViewById(R.id.bt_pause);
bt_stop = (Button) findViewById(R.id.bt_stop); bt_pause.setOnClickListener(this);
bt_play.setOnClickListener(this);
bt_replay.setOnClickListener(this);
bt_stop.setOnClickListener(this); sv.getHolder().addCallback(new Callback() { @Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("holder被销毁了"); if (mediaPlayer != null && mediaPlayer.isPlaying()) {
currentPosition = mediaPlayer.getCurrentPosition();
stop();
}
} @Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("holder被创建了");
if (currentPosition > 0) {
play(currentPosition);
} } @Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
System.out.println("holder的大小变化了");
}
}); } @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_play:
play(0);
break;
case R.id.bt_replay:
replay();
break;
case R.id.bt_stop:
stop();
break;
case R.id.bt_pause:
pause();
break;
default:
break;
}
} /**
* 暂停音乐
*/
private void pause() {
if ("继续".equals(bt_pause.getText().toString().trim())) {
mediaPlayer.start();
bt_pause.setText("暂停");
return;
}
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
bt_pause.setText("继续");
return;
}
} /**
* 重新播放
*/
private void replay() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
return;
}
play(0);
} /**
* 停止播放音乐
*/
private void stop() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release(); // 记得释放资源
mediaPlayer = null;
bt_play.setEnabled(true);
}
} /**
* 播放音乐
*/
private void play(final int currentPosition) {
String path = et_path.getText().toString().trim();
File file = new File(path);
if (file.exists() && file.length() > 0) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); /* 设置Video影片以SurfaceHolder播放 */
mediaPlayer.setDisplay(sv.getHolder()); mediaPlayer.setDataSource(path);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.seekTo(currentPosition); }
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
bt_play.setEnabled(true);
}
}); bt_play.setEnabled(false);
} catch (Exception e) {
Toast.makeText(this, "播放失败", 0).show();
e.printStackTrace();
}
} else {
Toast.makeText(this, "文件不存在", 0).show();
} } }

Android SurfaceView的生命周期的更多相关文章

  1. Android Activity的生命周期简单总结

    Android Activity的生命周期简单总结 这里的内容参考官方的文档,这篇文章的目的不是去总结Activity是如何启动,如何创造,以及暂停和销毁的,而是从实际开发中分析在Activity各个 ...

  2. android开发之生命周期

    android开发之生命周期 一:Activity的生命周期: 这几天了了解了安卓Activity的生命周期,对于生命周期有了大概的理解: 一个Activity的生命周期也就是Activity从生成到 ...

  3. Android内的生命周期整理

    1. Android App的生命周期: 2. Application的生命周期: 3. Activity的生命周期: 3.1 Fragment的生命周期: 4. Service的生命周期:5. Br ...

  4. Android开发——Activity生命周期

    Android开发--Activity生命周期 Activity作为四大组件之首,也是使用最频繁的一种组件.本文将主要讲解Activity生命周期,包括正常情况下的Activity生命周期和异常情况下 ...

  5. 重温Android和Fragment生命周期

    重温下Android和Fragment生命周期,理解生命周期方法的作用,什么时候调用,可以做一些什么操作. 1.Android生命周期 1.1 生命周期图 1.2 生命周期函数说明 onCreate: ...

  6. Xamarin.Android活动的生命周期

    一.前言 用过Android手机的人一定会发现一种现象,当你把一个应用置于后台后,一段时间之后在打开就会发现应用重新打开了,但是之前的相关的数据却没有丢失.可以看出app的“生命”是掌握在系统手上的, ...

  7. Android:Activity生命周期

    Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack). 栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新 ...

  8. Android targetSdkVersion 对生命周期的影响

    一直都认为当手机进入休眠时,Activity的生命周期会进入onPause()-->onStop()状态,但是今天偶然遇到了一个百思不得其解的问题,如果在AndroidMainfest.xml文 ...

  9. Android MediaPlayer的生命周期

    MediaPlayer的状态转换图也表征了它的生命周期,如下: 这张状态转换图清晰的描述了MediaPlayer的各个状态,也列举了主要的方法的调用时序,每种方法只能在一些特定的状态下使用,如果使用时 ...

随机推荐

  1. 12套有用的免费 PSD 格式 Android UI 素材

    在这里,我们向大家呈现一些有用的和免费的 Android 用户界面 PSD 素材.由于 Android 市场迅速增长,设计人员和开发人员正在寻找一些快速和容易的方法来创建 Android 友好的应用和 ...

  2. JavaScript最佳实践

    作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5540469.html 举个例子:用户在点击某个链接的时候弹出一个新窗口 弹出窗口的方法采用:wind ...

  3. Android中的FragmentManager的问题

    Fragment是构成灵活UI的重要部分.最近学习到Fragment的使用时候,碰到一个问题.主程序程序布局非常简单: <?xml version="1.0" encodin ...

  4. ASP.NET MVC5+EF6搭建三层实例

    一.创建项目解决方案 1.model层.BLL层.Dal层.Common层,都是类库 2.UI层使用MVC5 二.使用EF链接数据库 1.创建实体数据模型 2.选择来自数据库EF设计器 3.创建数据库 ...

  5. 用2263份证件照图片样本测试how-old.net的人脸识别

    上一年也就是这个时候微软根据自己的人脸识别API推出了一个识别照片中人脸年龄和性别的网站--http://how-old.net,小伙伴们各种玩耍,一年后的今天突发"奇想"地想测试 ...

  6. .Net语言 APP开发平台——Smobiler学习日志:如何在webview中加载网页

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的“Smobiler Components” ...

  7. C#常用字符串加解密方法封装

    C#中常用的字符串加密.解密方法封装,包含只加密但不解密的方法.收藏起来备用. //方法一 //须添加对System.Web的引用 //using System.Web.Security; /// & ...

  8. SQL常用语句(2)

    //计算表tb_Blog的字段个数 select count(*) from syscolumns where id=object_id('tb_Blog') 获取指定表的所有字段和字段类型 SELE ...

  9. java servlet+oracle 新手可看

    最近公司领导告诉接下去接的一个产品,可能会涉及到oracle数据库,以前用得最多的是mssql,前些时间学了下mysql也算少许用过.oracle没接触过.应为我之前做过.net开发,所以数据访问接口 ...

  10. Extjs 窗体居中,双重窗体弹出时清除父窗体的鼠标事件

    这个是监控窗体缩放的事件 缩放中居中主要在 'beforeshow' 和 'destroy'两个事件里面监控 var EditTempWindow; Ext.EventManager.onWindow ...