资源:
ImageButton所用图片4张
Strings:<string name="app_name">MyVideoPlayer</string>
<string name="video_text">视频文件</string>
<string name="notfoundsdcard_error">找不到Sd卡</string>
<string name="notfoundfile_error">找不到视频文件</string>
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFCC"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/video_text" />
<EditText
android:id="@+id/videoFileEt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="cat.3gp" />
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:stretchColumns="*" >
<TableRow >
<ImageButton
android:id="@+id/playBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageButton
android:id="@+id/pauseBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/pause" />
<ImageButton
android:id="@+id/resetBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/reset" />
<ImageButton
android:id="@+id/stopBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stop" />
</TableRow>
</TableLayout>
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="fill_parent"
android:layout_height="240dip" />
</LinearLayout>
Activity
package cn.class3g.videoplayer;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
public class VideoPlayerActivity extends Activity implements OnClickListener {
private static final String TAG = "VideoPlayerActivity";
private ImageButton playBtn, pauseBtn, resetBtn, stopBtn;
private EditText fileEt;
private SurfaceView videoSv;
private MediaPlayer mediaPlayer;
private SurfaceHolder holder;
private int position = 0;
File videoFile = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
mediaPlayer = new MediaPlayer();
}
private void findViews() {
fileEt = (EditText) this.findViewById(R.id.videoFileEt);
playBtn = (ImageButton) this.findViewById(R.id.playBtn);
pauseBtn = (ImageButton) this.findViewById(R.id.pauseBtn);
resetBtn = (ImageButton) this.findViewById(R.id.resetBtn);
stopBtn = (ImageButton) this.findViewById(R.id.stopBtn);
playBtn.setOnClickListener(this);
pauseBtn.setOnClickListener(this);
resetBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
videoSv = (SurfaceView) this.findViewById(R.id.surfaceView);
holder = videoSv.getHolder();
holder.setFixedSize(176, 144); // 设置分辨率
/* 下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前 */
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//holder.addCallback(new SurfaceCallback());
}
public void onClick(View v) {
if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) {
String fileName = fileEt.getText().toString().trim();
videoFile = new File(
Environment.getExternalStorageDirectory(), fileName);
if (videoFile.exists()) {
try {
switch (v.getId()) {
case R.id.playBtn:
playVideo(videoFile);
break;
case R.id.pauseBtn:
// if(mediaPlayer.isPlaying()){
// mediaPlayer.pause();
// }else{
// mediaPlayer.start();
// }
if(mediaPlayer.isPlaying()){
position = mediaPlayer.getCurrentPosition();
mediaPlayer.pause();
}
break;
case R.id.resetBtn:
if(mediaPlayer.isPlaying()){
mediaPlayer.seekTo(0);
}else{
playVideo(videoFile);
}
break;
case R.id.stopBtn:
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
break;
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
} else {
showToast(R.string.notfoundfile_error);
}
} else {
showToast(R.string.notfoundsdcard_error);
}
}
private void playVideo(File videoFile) throws IOException {
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(videoFile.getAbsolutePath());
mediaPlayer.setDisplay(holder);
mediaPlayer.prepare();
mediaPlayer.start();
}
private void showToast(int resId) {
Toast.makeText(this, resId, 1).show();
}
}
解决来电显示问题
protected void onDestroy() {
if(mediaPlayer != null){
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
mediaPlayer.release();
}
super.onDestroy();
}
protected void onPause() {
if(mediaPlayer != null && !mediaPlayer.isPlaying()){
position = mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
super.onPause();
}
protected void onResume() {
if(position >0 && videoFile != null){
try {
playVideo(videoFile);
Log.i(TAG,"position="+ position);
mediaPlayer.seekTo(position);
position = 0;
} catch (IOException e) {
Log.e(TAG,e.toString());
}
}
super.onResume();
}
问题:
来电后返回后,只有声音,没有画面
原因:
当前activity对象被遮挡后,SurfaceView对象被销毁,而activity重新显示时他的重建晚于onResume()方法的执行,所以此时只有声音而没有图象
解决SurfaceView的重建问题
取消onPause和onResume,由下面方法代替
private final class SurfaceCallback implements Callback{
public void surfaceCreated(SurfaceHolder holder) {
if(position >0 && videoFile != null){
try {
playVideo(videoFile);
Log.i(TAG,"position="+ position);
mediaPlayer.seekTo(position);
position = 0;
} catch (IOException e) {
Log.e(TAG,e.toString());
}
}
Log.i(TAG, "surfaceCreated");
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder holder) {
if(mediaPlayer != null && mediaPlayer.isPlaying()){
position = mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
Log.i(TAG, "surfaceDestroyed");
}
}
为SurfaceView对象添加Callback对象
holder.addCallback(new SurfaceCallback());
问题:
应用程序如处于后台,且系统需要内存时会把应用杀死,此时回到播放器界面,需要重新调用onCreate()方法,所以无法继续之前的播放。
解决内存不足时应用被杀死问题:
protected void onRestoreInstanceState(Bundle savedInstanceState) {
position = savedInstanceState.getInt("position");
String fn = savedInstanceState.getString("fileName");
if(fn!=null){
videoFile = new File(Environment.getExternalStorageDirectory(),fn);
}
super.onRestoreInstanceState(savedInstanceState);
}
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("position", position);
outState.putString("fileName", videoFile.getName());
super.onSaveInstanceState(outState);
注意:
1. 在2.1和2.2版本的模拟器中视频播放有bug,真机没事儿。
2. 有些视频文件,不能正常的调整播放位置(估计跟格式转换时索引丢失有关)。