目前很多app都会有短视频内容,这里就来讲一下android中播放视频的几种方式。

Android播放视频有三种方式:

1,调用系统已有的播放软件播放视频。

2,使用android提供的VideoView控件定制自己的视频播放器。

3,使用MediaPlayer和SurfaceView定制自己的视频播放器。

第一种方式最简单了:

 //调用系统自带的播放器        Uri uri = Uri.parse("/storage/emulated/0/DCIM/Camera/VID_20161103_105921.mp4");        Intent intent = new Intent(Intent.ACTION_VIEW);        intent.setDataAndType(uri, "video/mp4");        startActivity(intent);

就android4.2.2的源码来看 ,系统自带的播放器程序是Gallery2

/packages/apps/Gallery2

通过清单文件,可以知道处理该intent的activity:


看一下这个MovieActivity.java

 @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);      。。        setContentView(R.layout.movie_view);        View rootView = findViewById(R.id.movie_view_root);        setSystemUiVisibility(rootView);        Intent intent = getIntent();      。。。        mPlayer = new MoviePlayer(rootView, this, intent.getData(), savedInstanceState,                !mFinishOnCompletion) {            @Override            public void onCompletion() {                if (mFinishOnCompletion) {                    finish();                }            }        };

主要用到MoviePlayer,看一下这个MoviePlayer类做了啥

 public MoviePlayer(View rootView, final MovieActivity movieActivity,            Uri videoUri, Bundle savedInstance, boolean canReplay) {        mContext = movieActivity.getApplicationContext();        mRootView = rootView;        mVideoView = (VideoView) rootView.findViewById(R.id.surface_view);        mBookmarker = new Bookmarker(movieActivity);        mUri = videoUri;        mController = new MovieControllerOverlay(mContext);        ((ViewGroup)rootView).addView(mController.getView());        mController.setListener(this);        mController.setCanReplay(canReplay);        mVideoView.setOnErrorListener(this);        mVideoView.setOnCompletionListener(this);        mVideoView.setVideoURI(mUri);        mVideoView.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                mController.show();                return true;            }        });        // The SurfaceView is transparent before drawing the first frame.        // This makes the UI flashing when open a video. (black -> old screen        // -> video) However, we have no way to know the timing of the first        // frame. So, we hide the VideoView for a while to make sure the        // video has been drawn on it.        mVideoView.postDelayed(new Runnable() {            @Override            public void run() {                mVideoView.setVisibility(View.VISIBLE);

这个mVideoView是VideoView类型

    

所以通过上面代码可以知道,android自带的播放器也是使用VideoView这个控件来实现的。

那么接着就讲一下第二种方式,使用VideoView定制自己的视频播放器

VideoView看名字应该是View的子类



VideoView的直接父类是SurfaceView .关于SurfaceView前面Android视图SurfaceView的使用一文已做简单介绍。

SurfaceView可以用来显示相机的预览界面,也可以用来显示视频的数据。

下面就来看一下如何使用VideoView。

使用VideoView播放视频也有两种方式:

一种是只使用VideoView进行播放视频,自己自定义播放进度,播放状态的布局,然后自己控制播放

另一种就是VideoView结合MediaController播放视频,这种方式不需要自己写布局去控制播放。

下面先看第一方式:

结合代码和效果图一起分析下是如何实现播放视频的:

用手机拍摄了一段视频,然后用写的应用程序来播放这段视频(真机测试的)



启动应用看到界面如上:

看一下布局文件:

<?xml version="1.0" encoding="utf-8"?>                                                

MyVideoView是用来播放视频的,ImageView是用来显示视频的缩略图的(还未开始播放,先显示缩略图,覆盖VideoView那块区域,因为一开始VideoView那块区域是黑色的),cover (FrameLayout)是用来控制 CheckBox 和 LinearLayout 隐藏与显示,CheckBox是控制播放与停止,LinearLayout就是显示播放进度的布局,两个TextView分别是显示当前播放的时间和总时间,SeekBar就是显示进度,可以拖曳到任意位置播放。

下面的代码片段就是设置视频预览图片

 private void initVideoView() {        Log.d(TAG,"initVideoView ");        Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(PATH, MINI_KIND);        if(bitmap != null){            preview.setImageBitmap(bitmap);        }        videoView.setVideoURI(Uri.parse(PATH));    }
这里用到了ThumbnailUtils这个工具,参考官方文档:https://developer.android.com/reference/android/media/ThumbnailUtils.html

VideoView播放视频,需要传入视频资源,传入方式有以下几种:


关于VideoView官方文档:https://developer.android.com/reference/android/widget/VideoView.html

我这里播放本地视频,当然也可以播放网络视频。

点击CheckBox进行播放,看一下播放效果:




看一下代码:

 playOrPause.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                Log.d(TAG,"onCheckedChanged  isChecked="+isChecked);                if(isChecked){//暂停                    videoView.pause();                    positon = videoView.getCurrentPosition();                }else{//播放                    videoView.seekTo(positon);                    videoView.start();                    playOrPause.setVisibility(View.GONE);                    preview.setVisibility(View.GONE);                }            }        });

播放视频的话直接调用VideoView 的start()函数即可,seekTo()函数设置从哪个位置开始播放。

pasue()暂停播放,getCurrentPosition()获取播放到哪个位置了 时间毫秒。

看一下控制播放进度消息的代码:

@Override    public void onClick(View v) {        switch (v.getId()){            case R.id.cover:                Log.d(TAG,"click cover ");                int currentPosition = videoView.getCurrentPosition();                int duration = videoView.getDuration();                Log.d(TAG,"currentPosition = "+currentPosition+"duration = "+duration);                if(currentPosition>0){//说明已经播放了,不管现在是暂停还是播放中                    if(playOrPause.getVisibility() == View.VISIBLE){                        playOrPause.setVisibility(View.GONE);                    }else {                        playOrPause.setVisibility(View.VISIBLE);                    }                    if(progressLayout.getVisibility() == View.VISIBLE){                        myHandler.removeCallbacks(runnable);                        progressLayout.setVisibility(View.GONE);                    }else {                        progressLayout.setVisibility(View.VISIBLE);                        currentTime.setText((currentPosition/1000)/60%60/10+""+(currentPosition/1000)/60%60%10+":"                                +(currentPosition/1000)%60/10+""+(currentPosition/1000)%60%10);                        sumTime.setText((duration/1000)/60%60/10+""+(duration/1000)/60%60%10+":"                                +(duration/1000)%60/10+""+(duration/1000)%60%10);                        progressBar.setMax(duration);                        progressBar.setProgress(currentPosition);                        new Thread(new Runnable() {                            @Override                            public void run() {                                while(progressLayout.getVisibility()==View.VISIBLE){                                    myHandler.sendEmptyMessage(0);                                    try {                                        Thread.sleep(1000);                                    } catch (InterruptedException e) {                                        e.printStackTrace();                                    }                                }                            }                        }).start();                        myHandler.postDelayed(runnable,3000);                    }                }                break;            default:                break;        }    }    private Runnable runnable = new Runnable() {        @Override        public void run() {            playOrPause.setVisibility(View.GONE);            progressLayout.setVisibility(View.GONE);        }    };

下载该demo源码点击这里


接着看一下VideoView结合MediaController来播放视频,就简单几句代码就可以了:


  videoView = (MyVideoView) findViewById(R.id.video_view);        videoView.setVideoURI(Uri.parse(PATH));        MediaController mediaController = new MediaController(this);        videoView.setMediaController(mediaController);
布局文件
<?xml version="1.0" encoding="utf-8"?>    
效果图如下:



可以直接控制视频的播放了。

这里来简单看一下VideoView的源码。

源码位置:frameworks/base/core/java/android/widget/VideoView.java

public VideoView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        initVideoView();    }
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 setVideoURI(Uri uri) {        setVideoURI(uri, null);    }
 public void setVideoURI(Uri uri, Map headers) {        mUri = uri;        mHeaders = headers;        mSeekWhenPrepared = 0;        openVideo();        requestLayout();        invalidate();    }

private void openVideo() {        if (mUri == null || mSurfaceHolder == null) {            // not ready for playback just yet, will try again later            return;        }        // Tell the music playback service to pause        // TODO: these constants need to be published somewhere in the framework.        Intent i = new Intent("com.android.music.musicservicecommand");        i.putExtra("command", "pause");        mContext.sendBroadcast(i);        // we shouldn't clear the target state, because somebody might have        // called start() previously        release(false);        try {            mMediaPlayer = new MediaPlayer();            mMediaPlayer.setOnPreparedListener(mPreparedListener);            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);            mMediaPlayer.setOnCompletionListener(mCompletionListener);            mMediaPlayer.setOnErrorListener(mErrorListener);            mMediaPlayer.setOnInfoListener(mOnInfoListener);            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);            mCurrentBufferPercentage = 0;            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);            mMediaPlayer.setDisplay(mSurfaceHolder);            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);            mMediaPlayer.setScreenOnWhilePlaying(true);            mMediaPlayer.prepareAsync();            // we don't set the target state here either, but preserve the            // target state that was there before.            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 start() {        if (isInPlaybackState()) {            mMediaPlayer.start();            mCurrentState = STATE_PLAYING;        }        mTargetState = STATE_PLAYING;    }

通过上面几个关键的函数可以看出,VideoView播放播放视频是通过SurfaceView(VideoView本身就是SurfaceView)加上MediaPlayer(VideoView封装该类)这个类来实现的。这也是后面要讲的第三种播放视频的方式------------使用MediaPlayer和SurfaceView定制自己的视频播放器。

看一下MediaController这个类


它是一个视图,VideoView通过setMediaController(MediaController controller)函数添加MediaController其实就是添加一个视图,该视图容器里有控件来控制视频的播放

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());        }    }

看一下Mediacontroller的源码,路径在frameworks/base/core/java/android/widget/MediaController.java

 public void setAnchorView(View view) {        if (mAnchor != null) {            mAnchor.removeOnLayoutChangeListener(mLayoutChangeListener);        }        mAnchor = view;        if (mAnchor != null) {            mAnchor.addOnLayoutChangeListener(mLayoutChangeListener);        }        FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                ViewGroup.LayoutParams.MATCH_PARENT        );        removeAllViews();        View v = makeControllerView();        addView(v, frameParams);    }    /**     * Create the view that holds the widgets that control playback.     * Derived classes can override this to create their own.     * @return The controller view.     * @hide This doesn't work as advertised     */    protected View makeControllerView() {        LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        mRoot = inflate.inflate(com.android.internal.R.layout.media_controller, null);        initControllerView(mRoot);        return mRoot;    }

看一下它的布局结构

frameworks/base/core/res/res/layout/media_controller.xml

<?xml version="1.0" encoding="utf-8"?>                                                                                

上面两个类的源码就没有详细分析了。

关于VideoView播放视频就讲这些了,demo是运行在真机上的。

后面文章讲一下使用MediaPlayer和SurfaceView来播放视频。



更多相关文章

  1. Android实现播放音频
  2. Android(安卓)VideoView播放视频
  3. android Volley 使用
  4. android视频截图
  5. Android(安卓)用service实现视频播放器
  6. Android使用Fragment嵌套Fragment的方式实现界面滑动
  7. android 动画1
  8. android studio 57 MP3 音乐播放器 下载网络歌曲 代码
  9. Android(安卓)两种方式实现圆形头像

随机推荐

  1. 赵雅智_Android的getResources()资源引用
  2. Android在Activity中获得控件宽高和截屏
  3. android实现开机自动播放音乐实例(Broadca
  4. Android(安卓)Permission denied 错误 (
  5. android有用的知识
  6. Android(安卓)Parcelable 源码解析
  7. android通过webservice验证用户
  8. Android(安卓)横竖屏切换 activity变化详
  9. android中动画效果编程详解
  10. Android(安卓)怎样获得手机信息(二)