作者 : 万境绝尘 (octopus_truth@163.com)
转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38895143
一. 相关模块解析
1. 播放载体 SurfaceView 简介
(1) SurfaceView 与 Surface
SurfaceView 与 Surface 简介 : SurfaceView 中嵌入了一个 Surface, SurfaceView 可以操控 Surface 的 位置, 大小尺寸等;
-- SurfaceView 绘制图像可见性 : Surface 相当与一块画板, 上面绘制了一些东西, 但是不是所有的内容都可见, SurfaceView 相当与 Surface 的窗口, 只有在 SurfaceView 窗口区域内的才是可见的, 其它没有在窗口正下方的内容不可见;
-- Surface 与 SurfaceView 声明周期对应 : SurfaceView 可见的时候 Surface 被创建, SurfaceView 不可见时 Surface 销毁, Surface 创建销毁时机回调方法 SurfaceCreated(SurfaceHolder) 和 SurfaceDestoryed(SurfaceHolder) 方法, 这两个回调方法是 SurfaceHolder.Callback 中设定;
-- Surface 控制 : SurfaceView 通过 SurfaceHolder 控制 Surface;
(2) SurfaceHolder 简介
Surfaceholder 简介 : SurfaceHolder 是 Surface 的控制器, 用于控制 SurfaceView 绘图, 处理画布上的 动画 渲染效果 尺寸等;
-- 添加 Callback 回调接口 : abstract void addCallback(SurfaceHolder.Callback callback), 添加一个 SurfaceHolder.Callback 接口对象, 监听 Surface 的开始结束绘制大小改变事件;
-- 锁定画布 : abstract Canvas lockCanvas(), 锁定画布, 可以获得 Canvas 对象, 之后就可以在 Canvas 上绘图了;
(3) SurfaceHolder.Callback 简介
SurfaceHolder.Callback 接口 :
-- Surface 绘图边界 : 所有的绘图操作, 在 Surface 创建后操作, 在 Surface 销毁之前结束;
-- SurfaceHolder.Callback 接口对应 Surface 边界 : SurfaceCreated() 方法在 Surface 创建时回调, SurfaceDestroyed() 方法在 Surface 销毁前回调;
SurfaceHolder.Callback 接口中的方法简介 :
-- SurfaceChanged() : Surface 大小改变前回调;
-- surfaceCreated() : surface 创建时回调;
-- surfaceDestroyed() : surface 销毁时回调;
2. SurfaceView 使用流程
(1) 在布局文件中使用 SurfaceView 组件
布局文件 : 在布局文件中使用 <SurfaceView /> 组件;
-- 示例 :
代码语言:javascript复制<SurfaceView
android:id="@ id/surface_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"/>
(2) 设置 SurfaceHolder.Callback 回调接口
创建回调接口子类 : Activity 继承 SurfaceHolder.Callback 接口, 实现接口的三个方法 SurfaceCreated(), SurfaceChanged(), SurfaceDestroyed() 方法;
-- 示例 : 一般情况下直接设置 Activity 实现该接口, 为 SurfaceHolder 设置接口的时候直接将 Activity 设置进去;
代码语言:javascript复制public class HomeActivity extends Activity implements SurfaceHolder.Callback {
/**
* 在 Surface 大小发生改变的时候回调
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
System.out.println("SurfaceHolder.Callback.surfaceChanged : Surface 大小发生改变");
}
/**
* 在 Surface 创建的时候回调, 一般在该方法中开始绘图
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceCreated(SurfaceHolder arg0) {
System.out.println("SurfaceHolder.Callback.surfaceCreated : Surface 开始创建");
}
/**
* 在 Surface 销毁之前回调, 在该方法中停止渲染线程, 释放相关资源
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
System.out.println("SurfaceHolder.Callback.surfaceDestroyed : Surface 销毁");
}
}
(3) 获取 SurfaceHolder 对象 并添加回调接口子类
获取 SurfaceHolder 流程 :
-- a. 获取 SurfaceView : 使用 findViewById() 方法从布局文件中获取 SurfaceView 组件对象;
代码语言:javascript复制surface_view = (SurfaceView) findViewById(R.id.surface_view);
-- b. 从 SurfaceView 组件对象中获取 SurfaceHolder : 调用 SurfaceView 对象的 getHolder() 即可获取 SurfaceHolder 对象;
代码语言:javascript复制surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */
-- c. 为 SurfaceHolder 设置回调接口 : 调用 Surfaceholder 的 setCallback() 方法即可, 用于监听 Surface 的创建 改变 和 销毁;
代码语言:javascript复制surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */
SurfaceHolder 其它设置 :
-- 设置 SurfaceHolder 画面比例 : 调用 SurfaceHolder 的 setFixedSize() 方法;
代码语言:javascript复制surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */
-- 设置 SurfaceHolder 数据类型 : 调用 SurfaceHolder 的 setType() 方法;
代码语言:javascript复制surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */
总体代码示例 :
代码语言:javascript复制/**
* 初始化相关数据变量
*/
private void initData() {
/* 获取并设置 SurfaceHolder 对象 */
surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */
surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */
surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */
}
3. AutoCompleteTextView 组件
组件特性 : 可以设置一个适配器, 适配器中维护一组字符串, 当输入一部份字符后, 能 自动将符合条件的提示出来;
-- 示例 :
(1) 在布局文件中定义组件
布局文件中 : 使用 <AutoCompleteTextView /> 标签添加组件;
-- 设置后面省略 : android:ellipsize="end" , 由于链接太长, 不能显示全部, 自动将后面的部分省略;
-- 设置提示 : android:completionHint="选择下载的视频地址", 设置弹出的提示栏最后一栏的提示;
-- 设置单行显示 : android:singleLine="true";
-- 设置输入几个字符之后开始提示 : android:completionThreshold="1", 这里设置的是输入第一个字符之后就开始自动提示;
-- 示例 :
代码语言:javascript复制<AutoCompleteTextView
android:id="@ id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:completionThreshold="1"
android:text="http://daily3gp.com/vids/747.3gp"
android:completionHint="选择下载的视频地址"/>
(2) 创建适配器
创建适配器方法 :
代码语言:javascript复制android.widget.ArrayAdapter.ArrayAdapter<String>(Context context, int textViewResourceId, String[] objects)
-- Context context 参数 : 上下文对象;
-- int textViewResourceId 参数 : 显示列表的组件的布局;
-- String[] objects 参数 : 字符串数组对象;
代码示例 :
代码语言:javascript复制/* 设置一个列表适配器 */
String[] urls = {
"http://daily3gp.com/vids/747.3gp",
"http://daily3gp.com/vids/Funny women cannot understand.3gp",
"http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/0300020100540024BC9E5C08BD8A98D8200E2B-7950-B9A5-8669-DC283BDCC077?K=3a58dc2cdcc532df261dddec&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h+Fg9JjALshTOi/mzqjtJTFS4xCHottelMPGJ/5qdDnH0JmYfdKrGgQrUfZPPro+Pbq5dkgxpgDFG1FAc3Qs1SbRTn3",
"http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/030002040053FFB59E433100422C39BAFA46CC-4DED-E928-87B8-91706CDB5FF2?K=645d8478a3aa59052411eb8a&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h+Fg9JmALshS57J6zvYspmzTf5CFv0bcFEFGZmA3aHjbDNnYfQ33BwQqkeqMfro+YLr5aRSw5AGFW1Ed7uhtlSbRTn3"
};
/* 创建数组适配器 */
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, urls);
/* 将适配器设置给 AutoCompleteTextView 组件对象 */
url.setAdapter(adapter);
4. MediaPlayer 播放
(1) 设置音量 和 播放载体
设置音量 :
代码语言:javascript复制mediaPlayer.setAudioStreamType(2); /* 设置播放音量 */
设置播放载体 : 调用 setDisplay() 方法, 传入 SurfaceHolder 对象;
代码语言:javascript复制mediaPlayer.setDisplay(surface_holder); /* 设置播放载体 */
(2) 设置各种监听器
设置错误监听器 : 如果出现错误, 会回调该监听器中的方法, 并提供错误码;
代码语言:javascript复制/* 设置 MediaPlayer 错误监听器, 如果出现错误就会回调该方法打印错误代码 */
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer arg0, int what, int extra) {
System.out.println("MediaPlayer 出现错误 what : " what " , extra : " extra);
return false;
}
});
设置缓冲进度监听器 : 缓冲有进展后, 回调该监听器中的方法, 传入缓冲的数据百分比;
代码语言:javascript复制/* 设置缓冲进度更新监听器 */
mediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
/* 打印缓冲的百分比, 如果缓冲 */
System.out.println("缓冲了的百分比 : " percent " %");
}
});
设置播放完毕监听器 : 播放完毕后会回调该监听器中的方法;
代码语言:javascript复制 /* 设置播放完毕监听器 */
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
System.out.println("播放完毕了");
status.setText("播放完毕");
}
});
设置准备完毕回调监听器 : 准备完毕后会回调该方法;
代码语言:javascript复制 /* 设置准备完毕监听器 */
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer arg0) {
System.out.println("准备完毕");
/* 设置播放状态 */
status.setText("播放中");
}
});
二. 代码示例
1. 布局文件代码
代码语言:javascript复制<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@ id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
tools:context="cn.org.octopus.videodemo.HomeActivity"
tools:ignore="MergeRootFrame"
android:orientation="vertical">
<AutoCompleteTextView
android:id="@ id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:completionThreshold="1"
android:text="http://daily3gp.com/vids/747.3gp"
android:completionHint="选择下载的视频地址"/>
<SurfaceView
android:id="@ id/surface_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"/>
<TextView
android:id="@ id/status"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="20dp"
android:text="状态"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<Button
android:id="@ id/play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="播放"/>
<Button
android:id="@ id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="暂停"/>
<Button
android:id="@ id/reset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="重放"/>
<Button
android:id="@ id/stop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="停止"/>
</LinearLayout>
</LinearLayout>
2. AndroidManifest 代码
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.org.octopus.videodemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="cn.org.octopus.videodemo.HomeActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3. Activity 代码
代码语言:javascript复制package cn.org.octopus.videodemo;
import java.io.IOException;
import android.R.anim;
import android.app.Activity;
import android.content.DialogInterface.OnClickListener;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.TextView;
/**
*
*
* SurfaceHolder
* 1. 简介 : 是 Surface 的控制器, 用于控制 SurfaceView 绘图, 处理画布上的动画, 渲染效果, 大小等;
* 2. 常用方法 :
* -- abstract void addCallback(SurfaceHolder.Callback callback) : 添加一个 SurfaceHolder.Callback 接口对象, 监听 Surface 的开始结束绘制大小改变事件;
* -- abstract Canvas lockCanvas() : 锁定画布, 可以获得 Canvas 对象, 之后就可以在 Canvas 上绘图了;
*
* SurfaceHolder.Callback接口 :
* 1. Surface 绘图边界 : 所有的绘图工作都在 Surface 创建之后才能进行, 在 Surface 销毁之前结束;
* 2. Callback 接口对应的 Surface 边界 : surfaceCreated() 方法在开始绘制时回调, surfaceDestroyed() 在 Surface 销毁前回调;
* 3. 该接口中的方法 :
* -- surfaceChanged() : 在 Surface 大小改变时回调;
* -- surfaceCreated() : 在 Surface 创建时回调;
* -- surfaceDestroyed() : 在 Surface 销毁时回调;
*
* @author octopus
*
*/
public class HomeActivity extends Activity implements SurfaceHolder.Callback {
private AutoCompleteTextView url; /* 地址输入框, 带自动提示功能 */
private SurfaceView surface_view; /* 播放视频载体 */
private TextView status; /* 显示播放状态 */
private Button play; /* 播放按钮 */
private Button pause; /* 咱提供按钮 */
private Button reset; /* 重放按钮 */
private Button stop; /* 停止按钮 */
private MediaPlayer mediaPlayer; /* 播放器 */
private SurfaceHolder surface_holder; /* Surface 控制器 */
private boolean isStartPlaying; /* 是否开始了播放 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
initViews();
initData();
}
/**
* 初始化成员变量中的组件变量
*/
private void initViews() {
/* 通过 findViewById 获取相关方法 */
url = (AutoCompleteTextView) findViewById(R.id.url);
surface_view = (SurfaceView) findViewById(R.id.surface_view);
status = (TextView) findViewById(R.id.status);
play = (Button) findViewById(R.id.play);
pause = (Button) findViewById(R.id.pause);
reset = (Button) findViewById(R.id.reset);
stop = (Button) findViewById(R.id.stop);
/* 设置一个列表适配器 */
String[] urls = {
"http://daily3gp.com/vids/747.3gp",
"http://daily3gp.com/vids/Funny women cannot understand.3gp",
"http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/0300020100540024BC9E5C08BD8A98D8200E2B-7950-B9A5-8669-DC283BDCC077?K=3a58dc2cdcc532df261dddec&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h+Fg9JjALshTOi/mzqjtJTFS4xCHottelMPGJ/5qdDnH0JmYfdKrGgQrUfZPPro+Pbq5dkgxpgDFG1FAc3Qs1SbRTn3",
"http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/030002040053FFB59E433100422C39BAFA46CC-4DED-E928-87B8-91706CDB5FF2?K=645d8478a3aa59052411eb8a&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h+Fg9JmALshS57J6zvYspmzTf5CFv0bcFEFGZmA3aHjbDNnYfQ33BwQqkeqMfro+YLr5aRSw5AGFW1Ed7uhtlSbRTn3"
};
/* 创建数组适配器 */
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, urls);
/* 将适配器设置给 AutoCompleteTextView 组件对象 */
url.setAdapter(adapter);
/* 使窗口支持透明度, 把当前 Activity 窗口设置成透明, 设置了该选项就可以使用 setAlpha 等函数设置窗口透明度 */
getWindow().setFormat(PixelFormat.TRANSPARENT);
}
/**
* 初始化相关数据变量
*/
private void initData() {
/* 获取并设置 SurfaceHolder 对象 */
surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */
surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */
surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */
}
/**
* 设置点击事件
* @param view
*/
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.play:
/* 播放视频直接从 AutoCompleteTextView 中获取字符串, 播放该 url 代表的网络视频 */
playVideo(url.getText().toString());
break;
case R.id.pause:
if(mediaPlayer != null){
mediaPlayer.pause();
status.setText("暂停");
}
break;
case R.id.reset:
if(mediaPlayer != null){
mediaPlayer.seekTo(0);
mediaPlayer.start();
status.setText("播放中");
}
break;
case R.id.stop:
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
isStartPlaying = false;
status.setText("停止");
}
break;
default:
break;
}
}
/**
* 播放网络视频
* a. 创建并配置 MediaPlayer 对象 (音量, SurfaceHolder)
* b. 为 MediaPlayer 设置错误监听器, 缓冲进度监听器, 播放完毕监听器, 准备完毕监听器
* c. 未 MediaPlayer 设置数据源
* d. 调用 prepare() 进入 Prapared 状态
* e. 调用 start() 进入 Started 状态
*
* @param dataSource 播放视频的网络地址
*/
private void playVideo(final String dataSource) {
/* 点击播放有两种情况
* a. 第一次点击 : 需要初始化 MediaPlayer 对象, 设置监听器
* b. 第二次点击 : 只需要 调用 mediaPlayer 的 start() 方法
* 两种情况通过 isStartPlaying 点击时间判断 */
if(isStartPlaying){ /* 如果已经开始了播放, 就直接开始播放 */
mediaPlayer.start();
}else{ /* 如果是第一次开始播放, 需要初始化 MediaPlayer 设置监听器等操作 */
mediaPlayer = new MediaPlayer(); /* 创建 MediaPlayer 对象 */
mediaPlayer.setAudioStreamType(2); /* 设置播放音量 */
mediaPlayer.setDisplay(surface_holder); /* 设置播放载体 */
/* 设置 MediaPlayer 错误监听器, 如果出现错误就会回调该方法打印错误代码 */
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer arg0, int what, int extra) {
System.out.println("MediaPlayer 出现错误 what : " what " , extra : " extra);
return false;
}
});
/* 设置缓冲进度更新监听器 */
mediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
/* 打印缓冲的百分比, 如果缓冲 */
System.out.println("缓冲了的百分比 : " percent " %");
}
});
/* 设置播放完毕监听器 */
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
System.out.println("播放完毕了");
status.setText("播放完毕");
}
});
/* 设置准备完毕监听器 */
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer arg0) {
System.out.println("准备完毕");
/* 设置播放状态 */
status.setText("播放中");
}
});
new Thread(){
public void run() {
try {
System.out.println("设置数据源");
mediaPlayer.setDataSource(dataSource);
mediaPlayer.prepare();
/* 打印播放视频的时长 */
System.out.println("视频播放长度 : " mediaPlayer.getDuration());
mediaPlayer.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
};
}.start();
/* 设置 MediaPlayer 开始播放标识为 true */
isStartPlaying = true;
/* 设置播放状态 */
status.setText("正在缓冲");
}
}
/**
* 在 Surface 大小发生改变的时候回调
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
System.out.println("SurfaceHolder.Callback.surfaceChanged : Surface 大小发生改变");
}
/**
* 在 Surface 创建的时候回调, 一般在该方法中开始绘图
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceCreated(SurfaceHolder arg0) {
System.out.println("SurfaceHolder.Callback.surfaceCreated : Surface 开始创建");
}
/**
* 在 Surface 销毁之前回调, 在该方法中停止渲染线程, 释放相关资源
* 实现的 SurfaceHolder.Callback 接口方法
*/
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
System.out.println("SurfaceHolder.Callback.surfaceDestroyed : Surface 销毁");
}
@Override
protected void onDestroy() {
if(mediaPlayer != null)
mediaPlayer.release();
super.onDestroy();
}
}
4. 运行示例
日志信息 :
代码语言:javascript复制octopus@octopus:~/develop/adt-bundle-linux/sdk/tools$ adb logcat -s System.out
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
I/System.out(21129): 设置数据源
I/System.out(21129): 视频播放长度 : 31200
I/System.out(21129): 准备完毕
I/System.out(21129): 缓冲了的百分比 : 0 %
I/System.out(21129): 缓冲了的百分比 : 37 %
I/System.out(21129): 缓冲了的百分比 : 37 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 缓冲了的百分比 : 100 %
I/System.out(21129): 播放完毕了
I/System.out(21129): 缓冲了的百分比 : 100 %
作者 : 万境绝尘 (octopus_truth@163.com)
转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38895143