本文利用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. elasticsearch 查询(match和term)

    elasticsearch 查询(match和term) es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL). 由于DSL查询更为直观也更为简 ...

  2. 理解SQL Server是如何执行查询的 (1/3)

    查询执行的总图: 根据总图的流程,详细说明每个部分: 1. 请求(Request) SQL Server是C/S架构的平台.与它交互的唯一方式就是发送包含数据库命令的请求.应用程序和数据库之前的通信协 ...

  3. LeetCode - Balanced Binary Tree

    题目: Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced bin ...

  4. WinForm中DataGridView显示更新数据--人性版

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  5. 一道java算法题分析

    最近在面试中遇到这样的一道算法题:       求100!的结果的各位数之和为多少?       如:5!=5*4*3*2*1=120,那么他们的和为1+2+0=3这道题不算难,不过倒是注意的细节也有 ...

  6. 通过泛型数据,操作SQL数据库

    本人在操作数据库的时候,采用将对象的形式操作传入数据库,经过大量百度和朋友帮助,总结出如下两个接口.用于插入数据,提取数据. 要这样操作的前提条件,就是类名和表名一致,类字段和表字段一致就可以了 // ...

  7. 背水一战 Windows 10 (4) - UI: 多窗口

    [源码下载] 背水一战 Windows 10 (4) - UI: 多窗口 作者:webabcd 介绍背水一战 Windows 10 之 UI 多窗口 示例1.自定义帮助类,用于简化 Secondary ...

  8. jquery练习

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. luogg_java学习_02_基本语法

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! 关键字 定义:被java语言赋予了特殊含义,用作专门用 ...

  10. 我整理的PHP 7.0主要新特性

    原文:http://php.net/manual/en/migration70.new-features.php 1.标量参数类型声明 现在支持字符串(string).整型(int).浮点数(floa ...