资源:
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. 有些视频文件,不能正常的调整播放位置(估计跟格式转换时索引丢失有关)。