android 封装DefaultTask控件 封装sdk 给 app_ide

业务逻辑层没有用到很多新的类,但是它用到一个很重要的知识点,叫做接口回调

一、监听播放器产生的各种事件并实现逻辑

 

2、接口回调

 

假设有两个类,一个叫classA,一个叫classB,如果classA想调用classB的功能该如何做呢?在classA中创建classB的对象,这样就可以调用classB的方法了,这样是可以的。那么如果在classB中调用classA的方法,应该如何做呢?在classB中创建classA的对象,这样就可以了。这样就形成了一个循环关系,这就叫做你中有我我中有你,这是在开发中最不可取的一种方式,因为它的耦合度是100%,也就是最高的耦合度。所以要想办法打断其中的一条线,那么该如何打断呢?借助回调就可以。

android 封装DefaultTask控件 封装sdk 给 app_封装_02

 

打断其中一条线的方法:

android 封装DefaultTask控件 封装sdk 给 app_ide_03

 

①创建interface接口,这个接口包含了被调用者所关心的一些方法和事件。

android 封装DefaultTask控件 封装sdk 给 app_业务逻辑_04

②在业务逻辑层实现了该接口,并重写接口中的方法

android 封装DefaultTask控件 封装sdk 给 app_封装_05

 

android 封装DefaultTask控件 封装sdk 给 app_ide_06

 

③在创建B类的时候,给b类设置listener

android 封装DefaultTask控件 封装sdk 给 app_ide_07

 

④在B类中触发了对应事件后就会触通知相应的事件

android 封装DefaultTask控件 封装sdk 给 app_封装_08

 

这样就实现了A可以调用B类中的方法,同时B也可以调用A类中的方法

 

二、业务逻辑的封装

1、VideoAdSlot

业务逻辑层

①变量

Context mContext:上下文

CustomVideoView mVideoView: 自定义的视频播放器

ViewGroup mParentView  :  videoview要添加到的父容器

AdValue mVideoInfo: 视频相关信息的实体对象

AdSDKSlotListener mSlotListener: 接口回调

boolean canPause :一个标志位,标志视频是否可以自动暂停

int lastArea :是在测试时发现的一个问题

android 封装DefaultTask控件 封装sdk 给 app_封装_09

 

②构造方法中接收参数并初始化数据

android 封装DefaultTask控件 封装sdk 给 app_封装_10

 

③点击视频后进行界面跳转

为什么不把跳转代码直接写在CustomVideoView中呢?非要通过一个回调,到业务层来处理?放在customvideoview中完全是可以的,没问题,但是一定不能那样做。因为customvideoview是播放器,它主要实现的就是加载、播放、暂停、异常处理等等与播放相关的一些处理。而跳转、发监测等等与它压根就没有关系。所以根据类的单一原则,不把它放在customvideoview中来实现,而放在专门处理业务逻辑的slot中去处理。这也是在实际开发中需要注意的,哪些是固定不变的,哪些是变化的,需要把固定不变的封装起来,把经常变化的隔离出来。

android 封装DefaultTask控件 封装sdk 给 app_ide_11

 

 

在onAdVideoLoadSuccess()和onAdVideoLoadFailed()中很简单,就是通知视频加载成功还是加载失败了。这也是一个接口回调。所以这里的接口回调主要有两层,一层是从customvideoview传递到了videoslot,另一层是从videoslot传递到了后面的api层。api层会在后面去封装。

android 封装DefaultTask控件 封装sdk 给 app_ide_12

 

onAdVideoPlayComplete()视频播放结束时进行的处理,主要是通过ReportManager去发送了一个sue监测。

android 封装DefaultTask控件 封装sdk 给 app_ide_13

 

 

注:sue监测所做的操作

拿到所有的监测地址,拿到一些参数,最后调用封装好的网络请求组件commonokhttpclient把我们这个地址发送出去,告诉服务器我们当前的视频播放结束了

android 封装DefaultTask控件 封装sdk 给 app_ide_14

 

 

android 封装DefaultTask控件 封装sdk 给 app_封装_15

同理,onBufferUpdate()也是发送监测

getPosition():获取当前播放到第几秒

android 封装DefaultTask控件 封装sdk 给 app_ide_16

resumeVideo()主要是对resumeVideo()的resume()方法进行了一层包装,只是判断了一下是否为空

而pasueVideo()不仅是对videoview进行的一层封装,而且它调用的是seekAndPause(0),传入的是0。为什么呢?因为和后面的业务需求有关系。这里的需要是当划出屏幕50%以后,是需要从头开始播放的,所以需要调用seekAndPause(0)这个方法回到0去暂停,而不能直接调用pause()方法

 

注:seekAndPause(int position)这个方法与pause()这个方法是类似的,唯一的不同是,在暂停之前,需要传到传入的这个点,传入的是0,就会跳转到0,在跳转结束后,添加了一个onSeekCompleteListener,在跳转结束后才会进行pause()暂停。为什么不直接暂停呢?因为seekTo()是一个时间不确定的方法,所以是通过回调类型的这种方式执行的

android 封装DefaultTask控件 封装sdk 给 app_ide_17

 

2、AdValue

是一个视频信息实体类,包含了视频相关的所有内容。

主要用到的是resource,也就是视频的url,和监测的一些地址,以及点击要跳转的地址

android 封装DefaultTask控件 封装sdk 给 app_ide_18

 

 

二、完成活出屏幕暂停,滑入屏幕自动播放功能

1、实现滑入播放,滑出暂停功能

如何知道外界发生了滑动呢?自己是无法获取到外界是否发生了滑动的。那如何实现这个功能呢?我们只需要把功能实现,何时调用由调用方决定。当然,它不会直接调用slot层的这个方法,因为api层还没有封装完。

处理两种异常情况

android 封装DefaultTask控件 封装sdk 给 app_封装_19

 

处理正常的逻辑

如果videoview不足屏幕的50%,判断一下是否可以暂停,如果可以的话就暂停播放。为什么要canPause这个变量呢?当listview设置滑动监听以后,只要手一抖,就会不停地调用updateVideoView(),如果不做这个处理的话,一滑动就会调用这个pauseVideoView()这个方法,这样就会导致多次调用这个pause videoview,而可能出现状态上的异常。这样通过这个变量,在暂停状态下只进行一次暂停。

android 封装DefaultTask控件 封装sdk 给 app_业务逻辑_20

 

 

 

接着判断isRealPause()或者isComplete(),满足下面的任何一条,表明当前是真正的暂停,不能再往下继续判断了,表明当前是播放结束或者由于不满足播放条件而进入了暂停状态,也就是真正的暂停。这时要真正地暂停播放,同时将canPause置为false,防止再次地调用pauseVideo()

android 封装DefaultTask控件 封装sdk 给 app_业务逻辑_21

 

 

 

如果上面的条件都不满足,那么就可以判断一下是否可以进入到播放状态了

主要用来判断网络状态是否与用户的设置相一致。

走到这一步说明滑动已经超过50%了,并且条件已经满足了

android 封装DefaultTask控件 封装sdk 给 app_ide_22

 

 

 

 

注:①获取view在屏幕中显示的百分比

android 封装DefaultTask控件 封装sdk 给 app_业务逻辑_23

 

这是一种什么异常呢?假如videoview放在了listview的item中,itemview在刚刚要滑出屏幕的时候,它的面积会突然从0变成100,而这个突变会导致程序出现问题,所以要把这种异常情况排除掉。

if(Math.abs(currentArea - lastArea) >=100){
return;
}