拆解需求 1. RN使用 2. 播放器

最终实现的播放器功能:可以提供给RN使用,不带边缓存边播放功能的播放器。

1. RN使用实现

以组件的形式提供给RN使用,至于组件和native如何交互,主要通过重写RN的ViewGroupManager<T>实现。泛型传入的就是RN组件包装的native内部实现的播放器的view(player view)。

RN组件向native通信:

重写receiveCommand方法,此方法带有参数palyer view,commandId(RN到native的映射关系通过重写getCommandsMap建立)args(携带数据)。

拿到player view实例,我们就可以根据具体的命令,调用实例里面的方法。如此就实现的RN调用native。

Native向RN通信:

主要是native的view与用户发生交互,需要通知到RN。通知的实现是EventDispatcher,如何拿到player view并监听player view里面的事件呢?在createViewInstance方法里面可以拿到player view,在view里面设置监听,回调方法中利用EventDispatcher通信RN。

RN如何向Native传入初始化信息呢?比如控件的宽高。通过@ReactProp 注解的方式。

2. 简单播放器的实现

使用源生MediaPlyaer实现的视频播放,不带有边下边播功能(如果是网络视频,会出现缓冲很久的情况)。

推荐封装一个自己的MediaPlyaer,比如起名SelfMediaPlayer。以View的形式对外提供使用(内部聚合了SelfMediaPlayer)。

实现时,我们有些需要注意的地方有: 1. MediaPlayer状态的管理 2. 注意收集mediaplayer上报信息并进行处理。3. 无论选择SurfaceView还是TextureView,最好用一个FrameLayout包裹它。

MediaPlayer状态的管理:

以实现对外提供的api start功能实现来说明。

@Override
public void start() {
    try{
        mediaPlayer.start();
    } catch(IllegalStateException e) {
        // invalid state
        // 这里可以加入自己的处理逻辑,建议定个listener交给使用者确定ivalid错误处理逻辑。
    }
}

收集mediaplayer上报信息并进行处理:

mediaplayer通过一系列listener上报播放时的相关状态信息。比如OnErrorListener监听mediaplayer进入Error状,OnPreparedListener监听mediaplayer进入Prepared状态。

MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
    public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
        // The MediaPlayer has moved to the Error state, must be reset!
        // 代表进入错误状态了,我们可以进行自己错误处理逻辑并同时给出interface让使用者监听
        // 这里,我们也可以记录下状态,因为error这个状态很特殊,在进入到如此状态后后续很多操作都不可用了,必须reset。
        return true;
    }
}

private MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener
            () {

        @Override
        public void onPrepared(MediaPlayer mp) {
            // 这里可以记录下prepared状态,因为很多操作的前提就是当前状态是prepared
       }
    };

无论选择SurfaceView还是TextureView,最好用一个FrameLayout包裹它

带来的优点有很多,可以通过控制framelayout的大小实现间接控制SurfaceView大小。有了父容器的包裹之后,我们可以扩展一些定制化的view。