[android] 02_视频播放器-SurfaceView-SurfaceHolder

Android 4.0

视频播放器

SurfaceView
SurfaceView里面维护了两个缓冲区,一个准备数据,一个显示到界面上。
由于SurfaceView是个很耗资源的,所以当按home视频界面不可见时,surface holder被销毁,
当再次可见时,会重新创建一个holder对象,原来的holder对象已经销毁,所以黑屏


1、画面显示在哪里
mediaPlayer.setDisplay(sh);  

2、异步准备,并监听准备完成的状态
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        mediaPlayer.start();
    }
});
3、
为SurfaceHolder增加回调函数,关心surfaceview holder的存活周期
sv.getHolder().addCallback(new Callback() {
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            currentPosition = mediaPlayer.getCurrentPosition();
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        System.out.println("holder 销毁了。。。播放位置:" + currentPosition);
    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        System.out.println("holder 创建了。。。");
        if (currentPosition > 0) {
            try {
                String videoPath = et_path.getText().toString().trim();
                mediaPlayer = new MediaPlayer();
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mediaPlayer.setDataSource(getApplicationContext(),Uri.parse(videoPath));
                mediaPlayer.setDisplay(sv.getHolder());
                mediaPlayer.prepareAsync();
                mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        System.out.println("从"+currentPosition+"位置开始播放");
                        mediaPlayer.seekTo(currentPosition);
                        mediaPlayer.start();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format,
            int width, int height) {
        System.out.println("holder 变化了。。。");
    }
});
4、
android4.0以下要加上,4.0后废弃了,告诉surfaceview 不要自己维护缓冲区 而是 等待多媒体播放器的框架 把数据填充过来
sv.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

5、
2.3 2.2模拟器有bug,播放不了视频, 需要用1.6模拟器或者真机
核心代码:
package cn.zengfansheng.videoplay;

import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {

    private EditText et_path;
    private Button bt_pause;
    private SurfaceView sv;
    private MediaPlayer mediaPlayer;
    private int currentPosition;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) this.findViewById(R.id.et_path);
        bt_pause = (Button) this.findViewById(R.id.bt_pause);

        sv = (SurfaceView) this.findViewById(R.id.sv);

        // android4.0以下要加上,4.0后废弃了,告诉surfaceview 不要自己维护缓冲区 而是 等待多媒体播放器的框架 把数据填充过来
        sv.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // 2.3 2.2模拟器有bug,播放不了视频, 需要用1.6模拟器或者真机

        // TODO c、为SurfaceHolder增加回调函数,//关心surfaceview holder的存活周期
        sv.getHolder().addCallback(new Callback() {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                    currentPosition = mediaPlayer.getCurrentPosition();
                    mediaPlayer.stop();
                    mediaPlayer.release();
                    mediaPlayer = null;
                }
                System.out.println("holder 销毁了。。。播放位置:" + currentPosition);
            }
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                System.out.println("holder 创建了。。。");
                if (currentPosition > 0) {
                    try {
                        String videoPath = et_path.getText().toString().trim();
                        mediaPlayer = new MediaPlayer();
                        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                        mediaPlayer.setDataSource(getApplicationContext(),Uri.parse(videoPath));
                        mediaPlayer.setDisplay(sv.getHolder());
                        mediaPlayer.prepareAsync();
                        mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                            @Override
                            public void onPrepared(MediaPlayer mp) {
                                System.out.println("从"+currentPosition+"位置开始播放");
                                mediaPlayer.seekTo(currentPosition);
                                mediaPlayer.start();
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {
                System.out.println("holder 变化了。。。");
            }
        });
    }
    /**
     * TODO 1、开始播放视频
     * 
     * @param view
     */
    public void start(View view) {
        try {
            String videoPath = et_path.getText().toString().trim();
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(videoPath));
            mediaPlayer.setLooping(true);// 循环播放
            // TODO b、SurfaceHolder//画面显示在哪里
            SurfaceHolder sh = sv.getHolder();
            mediaPlayer.setDisplay(sh);
            // TODO a、prepareAsync()
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaPlayer.start();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * TODO 2、暂停播放视频
     * 
     * @param view
     */
    public void pause(View view) {
        if ("续播".equals(bt_pause.getText().toString().trim()) && mediaPlayer!=null) {
            mediaPlayer.start();
            bt_pause.setText("暂停");
            return;
        }
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
            bt_pause.setText("续播");
        }
    }
    /**
     * TODO 3、停止播放视频
     * 
     * @param view
     */
    public void stop(View view) {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
    /**
     * TODO 4、重新播放视频
     * 
     * @param view
     */
    public void replay(View view) {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
            mediaPlayer.seekTo(0);
                start(view);
    }
}

问题1:播放过程中,按下Home,视频界面不可见,有声音,再次回到该视频界面,没有画面。
原因:由于SurfaceView是个很耗资源的,所以当按home视频界面不可见时, SurfaceHolder 被销毁,当再次可见时,会重新创建一个holder对象,原来的holder对象已经销毁,所以黑屏