本节使用系统的示例类VideoView继续SurfaceView类相关内容的讲解,以让大家能更深入理解Android系统中图形绘制基础类的实现原理。也许你会发现无法改变VideoView类的控制方面,我们可以通过重构VideoView类来实现更加个性化的播放器。
      下面是VideoView类的相关代码。
Java代码
    - public class VideoView extends SurfaceView implements MediaPlayerControl {   
-     private String TAG = "VideoView";   
-       
-     private Uri         mUri;   
-     private int         mDuration;   
-   
-       
-     private static final int STATE_ERROR              = -1;   
-     private static final int STATE_IDLE               = 0;   
-     private static final int STATE_PREPARING          = 1;   
-     private static final int STATE_PREPARED           = 2;   
-     private static final int STATE_PLAYING            = 3;   
-     private static final int STATE_PAUSED             = 4;   
-     private static final int STATE_PLAYBACK_COMPLETED = 5;   
-   
-       
-       
-       
-       
-       
-     private int mCurrentState = STATE_IDLE;   
-     private int mTargetState  = STATE_IDLE;   
-   
-       
-     private SurfaceHolder mSurfaceHolder = null;   
-     private MediaPlayer mMediaPlayer = null;   
-     private int         mVideoWidth;   
-     private int         mVideoHeight;   
-     private int         mSurfaceWidth;   
-     private int         mSurfaceHeight;   
-     private MediaController mMediaController;   
-     private OnCompletionListener mOnCompletionListener;   
-     private MediaPlayer.OnPreparedListener mOnPreparedListener;   
-     private int         mCurrentBufferPercentage;   
-     private OnErrorListener mOnErrorListener;   
-     private int         mSeekWhenPrepared;    
-     private boolean     mCanPause;   
-     private boolean     mCanSeekBack;   
-     private boolean     mCanSeekForward;   
-   
-     public VideoView(Context context) {   
-         super(context);   
-         initVideoView();   
-     }   
-        
-     public VideoView(Context context, AttributeSet attrs) {   
-         this(context, attrs, 0);   
-         initVideoView();   
-     }   
-        
-     public VideoView(Context context, AttributeSet attrs, int defStyle) {   
-         super(context, attrs, defStyle);   
-         initVideoView();   
-     }   
-   
-     @Override  
-     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   
-           
-         int width = getDefaultSize(mVideoWidth, widthMeasureSpec);   
-         int height = getDefaultSize(mVideoHeight, heightMeasureSpec);   
-         if (mVideoWidth > 0 && mVideoHeight > 0) {   
-             if ( mVideoWidth * height  > width * mVideoHeight ) {   
-                   
-                 height = width * mVideoHeight / mVideoWidth;   
-             } else if ( mVideoWidth * height  < width * mVideoHeight ) {   
-                   
-                 width = height * mVideoWidth / mVideoHeight;   
-             } else {   
-                   
-                           
-                           
-             }   
-         }   
-           
-         setMeasuredDimension(width, height);   
-     }   
-        
-     public int resolveAdjustedSize(int desiredSize, int measureSpec) {   
-         int result = desiredSize;   
-         int specMode = MeasureSpec.getMode(measureSpec);   
-         int specSize =  MeasureSpec.getSize(measureSpec);   
-   
-         switch (specMode) {   
-             case MeasureSpec.UNSPECIFIED:   
-                  
-  
-   
-                 result = desiredSize;   
-                 break;   
-   
-             case MeasureSpec.AT_MOST:   
-                  
-  
-  
-   
-                 result = Math.min(desiredSize, specSize);   
-                 break;   
-                    
-             case MeasureSpec.EXACTLY:   
-                   
-                 result = specSize;   
-                 break;   
-         }   
-         return result;   
- }   
-        
-     private void initVideoView() {   
-         mVideoWidth = 0;   
-         mVideoHeight = 0;   
-         getHolder().addCallback(mSHCallback);   
-         getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);   
-         setFocusable(true);   
-         setFocusableInTouchMode(true);   
-         requestFocus();   
-         mCurrentState = STATE_IDLE;   
-         mTargetState  = STATE_IDLE;   
-     }   
-   
-     public void setVideoPath(String path) {   
-         setVideoURI(Uri.parse(path));   
-     }   
-   
-     public void setVideoURI(Uri uri) {   
-         mUri = uri;   
-         mSeekWhenPrepared = 0;   
-         openVideo();   
-         requestLayout();   
-         invalidate();   
-     }   
-        
-     public void stopPlayback() {   
-         if (mMediaPlayer != null) {   
-             mMediaPlayer.stop();   
-             mMediaPlayer.release();   
-             mMediaPlayer = null;   
-             mCurrentState = STATE_IDLE;   
-             mTargetState  = STATE_IDLE;   
-         }   
-     }   
-   
-     private void openVideo() {   
-         if (mUri == null || mSurfaceHolder == null) {   
-               
-             return;   
-         }   
-           
-           
-         Intent i = new Intent("com.android.music.musicservicecommand");   
-         i.putExtra("command", "pause");   
-         mContext.sendBroadcast(i);   
-   
-           
-           
-         release(false);   
-         try {   
-             mMediaPlayer = new MediaPlayer();   
-             mMediaPlayer.setOnPreparedListener(mPreparedListener);   
-             mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);   
-             mDuration = -1;   
-             mMediaPlayer.setOnCompletionListener(mCompletionListener);   
-             mMediaPlayer.setOnErrorListener(mErrorListener);   
-             mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);   
-             mCurrentBufferPercentage = 0;   
-             mMediaPlayer.setDataSource(mContext, mUri);   
-             mMediaPlayer.setDisplay(mSurfaceHolder);   
-             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);   
-             mMediaPlayer.setScreenOnWhilePlaying(true);   
-             mMediaPlayer.prepareAsync();   
-               
-               
-             mCurrentState = STATE_PREPARING;   
-             attachMediaController();   
-         } catch (IOException ex) {   
-             Log.w(TAG, "Unable to open content: " + mUri, ex);   
-             mCurrentState = STATE_ERROR;   
-             mTargetState = STATE_ERROR;   
-             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);   
-             return;   
-         } catch (IllegalArgumentException ex) {   
-             Log.w(TAG, "Unable to open content: " + mUri, ex);   
-             mCurrentState = STATE_ERROR;   
-             mTargetState = STATE_ERROR;   
-             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);   
-             return;   
-         }   
-     }   
-        
-     public void setMediaController(MediaController controller) {   
-         if (mMediaController != null) {   
-             mMediaController.hide();   
-         }   
-         mMediaController = controller;   
-         attachMediaController();   
-     }   
-   
-     private void attachMediaController() {   
-         if (mMediaPlayer != null && mMediaController != null) {   
-             mMediaController.setMediaPlayer(this);   
-             View anchorView = this.getParent() instanceof View ?   
-                     (View)this.getParent() : this;   
-             mMediaController.setAnchorView(anchorView);   
-             mMediaController.setEnabled(isInPlaybackState());   
-         }   
-     }   
-        
-     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =   
-         new MediaPlayer.OnVideoSizeChangedListener() {   
-             public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {   
-                 mVideoWidth = mp.getVideoWidth();   
-                 mVideoHeight = mp.getVideoHeight();   
-                 if (mVideoWidth != 0 && mVideoHeight != 0) {   
-                     getHolder().setFixedSize(mVideoWidth, mVideoHeight);   
-                 }   
-             }   
-     };   
-        
-     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {   
-         public void onPrepared(MediaPlayer mp) {   
-             mCurrentState = STATE_PREPARED;   
-   
-               
-             Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,   
-                                       MediaPlayer.BYPASS_METADATA_FILTER);   
-   
-             if (data != null) {   
-                 mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)   
-                         || data.getBoolean(Metadata.PAUSE_AVAILABLE);   
-                 mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)   
-                         || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);   
-                 mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)   
-                         || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);   
-             } else {   
-                 mCanPause = mCanSeekForward = mCanSeekForward = true;   
-             }   
-   
-             if (mOnPreparedListener != null) {   
-                 mOnPreparedListener.onPrepared(mMediaPlayer);   
-             }   
-             if (mMediaController != null) {   
-                 mMediaController.setEnabled(true);   
-             }   
-             mVideoWidth = mp.getVideoWidth();   
-             mVideoHeight = mp.getVideoHeight();   
-   
-             int seekToPosition = mSeekWhenPrepared;    
-             if (seekToPosition != 0) {   
-                 seekTo(seekToPosition);   
-             }   
-             if (mVideoWidth != 0 && mVideoHeight != 0) {   
-                   
-                 getHolder().setFixedSize(mVideoWidth, mVideoHeight);   
-                 if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {   
-                       
-                       
-                       
-                     if (mTargetState == STATE_PLAYING) {   
-                         start();   
-                         if (mMediaController != null) {   
-                             mMediaController.show();   
-                         }   
-                     } else if (!isPlaying() &&   
-                                (seekToPosition != 0 || getCurrentPosition() > 0)) {   
-                        if (mMediaController != null) {   
-                              
-                            mMediaController.show(0);   
-                        }   
-                    }   
-                 }   
-             } else {   
-                   
-                   
-                 if (mTargetState == STATE_PLAYING) {   
-                     start();   
-                 }   
-             }   
-         }   
-     };   
-   
-     private MediaPlayer.OnCompletionListener mCompletionListener =   
-         new MediaPlayer.OnCompletionListener() {   
-         public void onCompletion(MediaPlayer mp) {   
-             mCurrentState = STATE_PLAYBACK_COMPLETED;   
-             mTargetState = STATE_PLAYBACK_COMPLETED;   
-             if (mMediaController != null) {   
-                 mMediaController.hide();   
-             }   
-             if (mOnCompletionListener != null) {   
-                 mOnCompletionListener.onCompletion(mMediaPlayer);   
-             }   
-         }   
-     };   
-   
-     private MediaPlayer.OnErrorListener mErrorListener =   
-         new MediaPlayer.OnErrorListener() {   
-         public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {   
-             Log.d(TAG, "Error: " + framework_err + "," + impl_err);   
-             mCurrentState = STATE_ERROR;   
-             mTargetState = STATE_ERROR;   
-             if (mMediaController != null) {   
-                 mMediaController.hide();   
-             }   
-   
-               
-             if (mOnErrorListener != null) {   
-                 if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {   
-                     return true;   
-                 }   
-             }   
-   
-              
-  
-  
-  
-   
-             if (getWindowToken() != null) {   
-                 Resources r = mContext.getResources();   
-                 int messageId;   
-   
-                 if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {   
-                     messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;   
-                 } else {   
-                     messageId = com.android.internal.R.string.VideoView_error_text_unknown;   
-                 }   
-   
-                 new AlertDialog.Builder(mContext)   
-                         .setTitle(com.android.internal.R.string.VideoView_error_title)   
-                         .setMessage(messageId)   
-                         .setPositiveButton(com.android.internal.R.string.VideoView_error_button,   
-                                 new DialogInterface.OnClickListener() {   
-                                     public void onClick(DialogInterface dialog, int whichButton) {   
-                                          
-  
-   
-                                         if (mOnCompletionListener != null) {   
-                                             mOnCompletionListener.onCompletion(mMediaPlayer);   
-                                         }   
-                                     }   
-                                 })   
-                         .setCancelable(false)   
-                         .show();   
-             }   
-             return true;   
-         }   
-     };   
-   
-     private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =   
-         new MediaPlayer.OnBufferingUpdateListener() {   
-         public void onBufferingUpdate(MediaPlayer mp, int percent) {   
-             mCurrentBufferPercentage = percent;   
-         }   
-     };   
-   
-      
-  
-  
-  
-  
-   
-     public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)   
-     {   
-         mOnPreparedListener = l;   
-     }   
-   
-      
-  
-  
-  
-  
-   
-     public void setOnCompletionListener(OnCompletionListener l)   
-     {   
-         mOnCompletionListener = l;   
-     }   
-   
-      
-  
-  
-  
-  
-  
-  
-   
-     public void setOnErrorListener(OnErrorListener l)   
-     {   
-         mOnErrorListener = l;   
-     }   
-   
-     SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()   
-     {   
-         public void surfaceChanged(SurfaceHolder holder, int format,   
-                                     int w, int h)   
-         {   
-             mSurfaceWidth = w;   
-             mSurfaceHeight = h;   
-             boolean isValidState =  (mTargetState == STATE_PLAYING);   
-             boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);   
-             if (mMediaPlayer != null && isValidState && hasValidSize) {   
-                 if (mSeekWhenPrepared != 0) {   
-                     seekTo(mSeekWhenPrepared);   
-                 }   
-                 start();   
-                 if (mMediaController != null) {   
-                     mMediaController.show();   
-                 }   
-             }   
-         }   
-   
-         public void surfaceCreated(SurfaceHolder holder)   
-         {   
-             mSurfaceHolder = holder;   
-             openVideo();   
-         }   
-   
-         public void surfaceDestroyed(SurfaceHolder holder)   
-         {   
-               
-             mSurfaceHolder = null;   
-             if (mMediaController != null) mMediaController.hide();   
-             release(true);   
-         }   
-     };   
-   
-      
-  
-   
-     private void release(boolean cleartargetstate) {   
-         if (mMediaPlayer != null) {   
-             mMediaPlayer.reset();   
-             mMediaPlayer.release();   
-             mMediaPlayer = null;   
-             mCurrentState = STATE_IDLE;   
-             if (cleartargetstate) {   
-                 mTargetState  = STATE_IDLE;   
-             }   
-         }   
-     }   
-   
-     @Override  
-     public boolean onTouchEvent(MotionEvent ev) {   
-         if (isInPlaybackState() && mMediaController != null) {   
-             toggleMediaControlsVisiblity();   
-         }   
-         return false;   
-     }   
-        
-     @Override  
-     public boolean onTrackballEvent(MotionEvent ev) {   
-         if (isInPlaybackState() && mMediaController != null) {   
-             toggleMediaControlsVisiblity();   
-         }   
-         return false;   
-     }   
-        
-     @Override  
-     public boolean onKeyDown(int keyCode, KeyEvent event)   
-     {   
-         boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&   
-                                      keyCode != KeyEvent.KEYCODE_VOLUME_UP &&   
-                                      keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&   
-                                      keyCode != KeyEvent.KEYCODE_MENU &&   
-                                      keyCode != KeyEvent.KEYCODE_CALL &&   
-                                      keyCode != KeyEvent.KEYCODE_ENDCALL;   
-         if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {   
-             if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||   
-                     keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {   
-                 if (mMediaPlayer.isPlaying()) {   
-                     pause();   
-                     mMediaController.show();   
-                 } else {   
-                     start();   
-                     mMediaController.hide();   
-                 }   
-                 return true;   
-             } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP    
-                     && mMediaPlayer.isPlaying()) {   
-                 pause();   
-                 mMediaController.show();   
-             } else {   
-                 toggleMediaControlsVisiblity();   
-             }   
-         }   
-   
-         return super.onKeyDown(keyCode, event);   
-     }   
-   
-     private void toggleMediaControlsVisiblity() {   
-         if (mMediaController.isShowing()) {    
-             mMediaController.hide();   
-         } else {   
-             mMediaController.show();   
-         }   
-     }   
-        
-     public void start() {   
-         if (isInPlaybackState()) {   
-             mMediaPlayer.start();   
-             mCurrentState = STATE_PLAYING;   
-         }   
-         mTargetState = STATE_PLAYING;   
-     }   
-        
-     public void pause() {   
-         if (isInPlaybackState()) {   
-             if (mMediaPlayer.isPlaying()) {   
-                 mMediaPlayer.pause();   
-                 mCurrentState = STATE_PAUSED;   
-             }   
-         }   
-         mTargetState = STATE_PAUSED;   
-     }   
-        
-       
-     public int getDuration() {   
-         if (isInPlaybackState()) {   
-             if (mDuration > 0) {   
-                 return mDuration;   
-             }   
-             mDuration = mMediaPlayer.getDuration();   
-             return mDuration;   
-         }   
-         mDuration = -1;   
-         return mDuration;   
-     }   
-        
-     public int getCurrentPosition() {   
-         if (isInPlaybackState()) {   
-             return mMediaPlayer.getCurrentPosition();   
-         }   
-         return 0;   
-     }   
-        
-     public void seekTo(int msec) {   
-         if (isInPlaybackState()) {   
-             mMediaPlayer.seekTo(msec);   
-             mSeekWhenPrepared = 0;   
-         } else {   
-             mSeekWhenPrepared = msec;   
-         }   
-     }       
-                
-     public boolean isPlaying() {   
-         return isInPlaybackState() && mMediaPlayer.isPlaying();   
-     }   
-        
-     public int getBufferPercentage() {   
-         if (mMediaPlayer != null) {   
-             return mCurrentBufferPercentage;   
-         }   
-         return 0;   
-     }   
-   
-     private boolean isInPlaybackState() {   
-         return (mMediaPlayer != null &&   
-                 mCurrentState != STATE_ERROR &&   
-                 mCurrentState != STATE_IDLE &&   
-                 mCurrentState != STATE_PREPARING);   
-     }   
-   
-     public boolean canPause() {   
-         return mCanPause;   
-     }   
-   
-     public boolean canSeekBackward() {   
-         return mCanSeekBack;   
-     }   
-   
-     public boolean canSeekForward() {   
-         return mCanSeekForward;   
-     }   
- }