最近因为要做一个广告机上图片视频轮播,所以又是百度,github上一堆找,结果发现并没有特别合适的,不是播放视频首帧黑屏,就是切换界面后,没法继续播放,或者动态更新数据后,没法继续轮播等等问题,所以最后结合别人的方案自己修改了一下,具体参考android 实现图片和视频混合轮播_android 图片视频轮播_a1466850214的博客-CSDN博客

修改完成后,1.可以实现无黑屏
                      2.切换界面后,回到播放界面继续上次播放位置播放,
                      3.不支持点击和手动切换
                      4.动态更新数据后继续播放
下面是具体代码:
1.播放实体类

public class Advance {public String path;//路径  我使用的是本地绝对路径public String type;//类型 1、视频 2、图片public Advance(String path, String type) {this.path = path;this.type = type;}
}

2.图片类

package com.anssy.smartbox.selfview.videoplay;import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;import com.anssy.smartbox.utils.glide.GlideApp;public class AdvanceImageView extends RelativeLayout {private ImageView imageView;public AdvanceImageView(Context context) {super(context);initView();}public AdvanceImageView(Context context, AttributeSet attrs) {super(context, attrs);initView();}public AdvanceImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}private void initView() {imageView = new ImageView(getContext());imageView.setScaleType(ImageView.ScaleType.FIT_XY);addView(imageView, new RelativeLayout.LayoutParams(-1, -1));}public void setImage(String path) {GlideApp.with(getContext()).load(path).into(imageView);}}​

3.视频播放类,这里面的播放视频控件,没有采用和其他博主用的系统VideoView,这里引用一个第三方,大家可以在gradle里面导入,至于为什么引入第三方,1.可以实现缓存2.视频pause后,切回后,可以无缝播放,Application中加入初始化,如果有视频播放不了,请切换内核为AndroidMediaFactory.create()或切换为ExoPlayer,具体参考GitHub - Doikki/DKVideoPlayer: Android Video Player. 安卓视频播放器,封装MediaPlayer、ExoPlayer、IjkPlayer。模仿抖音并实现预加载,列表播放,悬浮播放,广告播放,弹幕,视频水印,视频滤镜

        VideoViewManager.setConfig(VideoViewConfig.newBuilder()//使用使用IjkPlayer解码.setPlayerFactory(IjkPlayerFactory.create()).build());
    implementation 'xyz.doikki.android.dkplayer:dkplayer-java:3.3.7'implementation 'xyz.doikki.android.dkplayer:player-ijk:3.3.7'implementation 'xyz.doikki.android.dkplayer:videocache:3.3.7'
package com.anssy.smartbox.selfview.videoplay;import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.RelativeLayout;import com.anssy.smartbox.R;
import com.anssy.smartbox.utils.cache.PreloadManager;
import com.anssy.smartbox.utils.glide.GlideApp;
import com.bumptech.glide.request.RequestOptions;import xyz.doikki.videoplayer.ijk.IjkPlayer;
import xyz.doikki.videoplayer.player.AbstractPlayer;
import xyz.doikki.videoplayer.player.VideoView;
import xyz.doikki.videoplayer.player.VideoViewManager;public class AdvanceVideoView extends RelativeLayout {public ImageView imageView;private VideoView videoView;private RelativeLayout videoRela;private String path;public int currentPosition;public AdvanceVideoView(Context context) {super(context);initView();}public AdvanceVideoView(Context context, AttributeSet attrs) {super(context, attrs);initView();}public AdvanceVideoView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}private PreloadManager mPreloadManager;private void initView() {videoRela = new RelativeLayout(getContext());addView(videoRela, new RelativeLayout.LayoutParams(-1, -1));imageView = new ImageView(getContext());imageView.setScaleType(ImageView.ScaleType.FIT_XY);addView(imageView, new RelativeLayout.LayoutParams(-1, -1));}public void setImage(String path,VideoView  videoView,PreloadManager preloadManager) {this.path = path;this.videoView = videoView;this.mPreloadManager = preloadManager;GlideApp.with(getContext()) .setDefaultRequestOptions(new RequestOptions().frame(0)).load(path).into(imageView);}/*** 将View从父控件中移除*/public static void removeViewFormParent(View v) {if (v == null) return;ViewParent parent = v.getParent();if (parent instanceof RelativeLayout) {((RelativeLayout) parent).removeView(v);}}public void setVideo() {
//        if (videoView != null) {
//            videoView.release();
//            videoRela.removeView(videoView);
//            videoView = null;
//        }removeViewFormParent(videoView);videoView.release();videoView.setPlayerBackgroundColor(getContext().getResources().getColor(R.color.main_color));// videoView = new VideoView(getContext());videoView.setScreenScaleType(VideoView.SCREEN_SCALE_MATCH_PARENT);
//        HttpProxyCacheServer proxy = BaseApplication.getProxy(getContext());
//        String proxyUrl = proxy.getProxyUrl(path);
//        videoView.setVideoPath(proxyUrl);//videoView.setVideoPath(path);//  videoView.setBackgroundColor(Color.TRANSPARENT);String playUrl = mPreloadManager.getPlayUrl(path);videoView.setUrl(playUrl);RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(-1, -1);//设置videoview占满父view播放layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);videoRela.addView(videoView, layoutParams);videoView.start();
//        videoView.setOnPreparedListener(mediaPlayer -> {
//            new Handler().postDelayed(() -> {
//                imageView.setVisibility(GONE);
//            }, 400);//防止videoview播放视频前有个闪烁的黑屏
//        });}public void setDestroy(){if (videoView!=null){videoView.release();}}public void setPause() {if (videoView != null) {videoView.pause();//currentPosition = videoView.getCurrentPosition();// imageView.setVisibility(VISIBLE);}}public void setRestart() {if (videoView != null) {videoView.resume();// videoView.seekTo(currentPosition);//videoView.start();}}}

4.第三方缓存类

package com.anssy.smartbox.utils.cache;import android.content.Context;import com.danikula.videocache.HttpProxyCacheServer;import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import xyz.doikki.videoplayer.util.L;/*** 抖音预加载工具,使用AndroidVideoCache实现*/
public class PreloadManager {private static PreloadManager sPreloadManager;/*** 单线程池,按照添加顺序依次执行{@link PreloadTask}*/private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();/*** 保存正在预加载的{@link PreloadTask}*/private final LinkedHashMap<String, PreloadTask> mPreloadTasks = new LinkedHashMap<>();/*** 标识是否需要预加载*/private boolean mIsStartPreload = true;private final HttpProxyCacheServer mHttpProxyCacheServer;/*** 预加载的大小,每个视频预加载1M,这个参数可根据实际情况调整*/public static final int PRELOAD_LENGTH = 1024 * 1024;private PreloadManager(Context context) {mHttpProxyCacheServer = ProxyVideoCacheManager.getProxy(context);}public static PreloadManager getInstance(Context context) {if (sPreloadManager == null) {synchronized (PreloadManager.class) {if (sPreloadManager == null) {sPreloadManager = new PreloadManager(context.getApplicationContext());}}}return sPreloadManager;}/*** 开始预加载** @param rawUrl 原始视频地址*/public void addPreloadTask(String rawUrl, int position) {if (isPreloaded(rawUrl)) return;PreloadTask task = new PreloadTask();task.mRawUrl = rawUrl;task.mPosition = position;task.mCacheServer = mHttpProxyCacheServer;L.i("addPreloadTask: " + position);mPreloadTasks.put(rawUrl, task);if (mIsStartPreload) {//开始预加载task.executeOn(mExecutorService);}}/*** 判断该播放地址是否已经预加载*/private boolean isPreloaded(String rawUrl) {//先判断是否有缓存文件,如果已经存在缓存文件,并且其大小大于1KB,则表示已经预加载完成了File cacheFile = mHttpProxyCacheServer.getCacheFile(rawUrl);if (cacheFile.exists()) {if (cacheFile.length() >= 1024) {return true;} else {//这种情况一般是缓存出错,把缓存删掉,重新缓存cacheFile.delete();return false;}}//再判断是否有临时缓存文件,如果已经存在临时缓存文件,并且临时缓存文件超过了预加载大小,则表示已经预加载完成了File tempCacheFile = mHttpProxyCacheServer.getTempCacheFile(rawUrl);if (tempCacheFile.exists()) {return tempCacheFile.length() >= PRELOAD_LENGTH;}return false;}/*** 暂停预加载* 根据是否反向滑动取消在position之下或之上的PreloadTask** @param position 当前滑到的位置* @param isReverseScroll 列表是否反向滑动*/public void pausePreload(int position, boolean isReverseScroll) {L.d("pausePreload:" + position + " isReverseScroll: " + isReverseScroll);mIsStartPreload = false;for (Map.Entry<String, PreloadTask> next : mPreloadTasks.entrySet()) {PreloadTask task = next.getValue();if (isReverseScroll) {if (task.mPosition >= position) {task.cancel();}} else {if (task.mPosition <= position) {task.cancel();}}}}/*** 恢复预加载* 根据是否反向滑动开始在position之下或之上的PreloadTask** @param position        当前滑到的位置* @param isReverseScroll 列表是否反向滑动*/public void resumePreload(int position, boolean isReverseScroll) {L.d("resumePreload:" + position + " isReverseScroll: " + isReverseScroll);mIsStartPreload = true;for (Map.Entry<String, PreloadTask> next : mPreloadTasks.entrySet()) {PreloadTask task = next.getValue();if (isReverseScroll) {if (task.mPosition < position) {if (!isPreloaded(task.mRawUrl)) {task.executeOn(mExecutorService);}}} else {if (task.mPosition > position) {if (!isPreloaded(task.mRawUrl)) {task.executeOn(mExecutorService);}}}}}/*** 通过原始地址取消预加载** @param rawUrl 原始地址*/public void removePreloadTask(String rawUrl) {PreloadTask task = mPreloadTasks.get(rawUrl);if (task != null) {task.cancel();mPreloadTasks.remove(rawUrl);}}/*** 取消所有的预加载*/public void removeAllPreloadTask() {Iterator<Map.Entry<String, PreloadTask>> iterator = mPreloadTasks.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, PreloadTask> next = iterator.next();PreloadTask task = next.getValue();task.cancel();iterator.remove();}}/*** 获取播放地址*/public String getPlayUrl(String rawUrl) {PreloadTask task = mPreloadTasks.get(rawUrl);if (task != null) {task.cancel();}if (isPreloaded(rawUrl)) {return mHttpProxyCacheServer.getProxyUrl(rawUrl);} else {return rawUrl;}}
}
package com.anssy.smartbox.utils.cache;import com.danikula.videocache.HttpProxyCacheServer;import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;import xyz.doikki.videoplayer.util.L;/*** 原理:主动去请求VideoCache生成的代理地址,触发VideoCache缓存机制* 缓存到 PreloadManager.PRELOAD_LENGTH 的数据之后停止请求,完成预加载* 播放器去播放VideoCache生成的代理地址的时候,VideoCache会直接返回缓存数据,* 从而提升播放速度*/
public class PreloadTask implements Runnable {/*** 原始地址*/public String mRawUrl;/*** 列表中的位置*/public int mPosition;/*** VideoCache服务器*/public HttpProxyCacheServer mCacheServer;/*** 是否被取消*/private boolean mIsCanceled;/*** 是否正在预加载*/private boolean mIsExecuted;private final static List<String> blackList = new ArrayList<>();@Overridepublic void run() {if (!mIsCanceled) {start();}mIsExecuted = false;mIsCanceled = false;}/*** 开始预加载*/private void start() {// 如果在小黑屋里不加载if (blackList.contains(mRawUrl)) return;L.i("预加载开始:" + mPosition);HttpURLConnection connection = null;try {//获取HttpProxyCacheServer的代理地址String proxyUrl = mCacheServer.getProxyUrl(mRawUrl);URL url = new URL(proxyUrl);connection = (HttpURLConnection) url.openConnection();connection.setConnectTimeout(5_000);connection.setReadTimeout(5_000);InputStream in = new BufferedInputStream(connection.getInputStream());int length;int read = -1;byte[] bytes = new byte[8 * 1024];while ((length = in.read(bytes)) != -1) {read += length;//预加载完成或者取消预加载if (mIsCanceled || read >= PreloadManager.PRELOAD_LENGTH) {if (mIsCanceled) {L.i("预加载取消:" + mPosition + " 读取数据:" + read + " Byte");} else {L.i("预加载成功:" + mPosition + " 读取数据:" + read + " Byte");}break;}}} catch (Exception e) {L.i("预加载异常:" + mPosition + " 异常信息:"+ e.getMessage());// 关入小黑屋blackList.add(mRawUrl);} finally {if (connection != null) {connection.disconnect();}L.i("预加载结束: " + mPosition);}}/*** 将预加载任务提交到线程池,准备执行*/public void executeOn(ExecutorService executorService) {if (mIsExecuted) return;mIsExecuted = true;executorService.submit(this);}/*** 取消预加载任务*/public void cancel() {if (mIsExecuted) {mIsCanceled = true;}}
}
package com.anssy.smartbox.utils.cache;import android.content.Context;import com.danikula.videocache.HttpProxyCacheServer;
import com.danikula.videocache.StorageUtils;import java.io.File;public class ProxyVideoCacheManager {private static HttpProxyCacheServer sharedProxy;private ProxyVideoCacheManager() {}public static HttpProxyCacheServer getProxy(Context context) {return sharedProxy == null ? (sharedProxy = newProxy(context)) : sharedProxy;}private static HttpProxyCacheServer newProxy(Context context) {return new HttpProxyCacheServer.Builder(context).maxCacheSize(512 * 1024 * 1024)       // 512MB for cache//缓存路径,不设置默认在sd_card/Android/data/[app_package_name]/cache中
//                .cacheDirectory().build();}/*** 删除所有缓存文件* @return 返回缓存是否删除成功*/public static boolean clearAllCache(Context context) {getProxy(context);return StorageUtils.deleteFiles(sharedProxy.getCacheRoot());}/*** 删除url对应默认缓存文件* @return 返回缓存是否删除成功*/public static boolean clearDefaultCache(Context context, String url) {getProxy(context);File pathTmp = sharedProxy.getTempCacheFile(url);File path = sharedProxy.getCacheFile(url);return StorageUtils.deleteFile(pathTmp.getAbsolutePath()) &&StorageUtils.deleteFile(path.getAbsolutePath());}
}

5.播放控件,其实是ViewPager切换

package com.anssy.smartbox.selfview.videoplay;import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;import androidx.viewpager.widget.ViewPager;import java.util.ArrayList;
import java.util.List;public class AdvanceView extends RelativeLayout {private ViewPager viewPager;private List<View> views = new ArrayList<>();public AdvancePagerAdapter adapter;public AdvanceView(Context context) {super(context);initView();}public AdvanceView(Context context, AttributeSet attrs) {super(context, attrs);initView();}public AdvanceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}@SuppressLint("ClickableViewAccessibility")private void initView() {viewPager = new ViewPager(getContext());viewPager.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {return true;}});adapter = new AdvancePagerAdapter(getContext(),viewPager);viewPager.setAdapter(adapter);addView(viewPager, new RelativeLayout.LayoutParams(-1, -1));}public void setData(List<Advance> advances) {adapter.setData(advances);}public void setDestroy(){adapter.setDestroy();}public void setPause(){adapter.setPause();}public void setResume(){adapter.setResume();}
}

6.ViewPager的适配器,里面原作者的代码我并未删除,大家也可以对比下,或者区别调用下,看下效果,我将原作者的thread定时器,改为了handler的方法,这样可操作性要强一点,避免动态切换数据后,轮播卡死的情况。这里我用的是自己定义的handler,大家替换为系统的handler即可

package com.anssy.smartbox.selfview.videoplay;import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;import com.anssy.smartbox.utils.WeakHandler;
import com.anssy.smartbox.utils.cache.PreloadManager;import java.util.ArrayList;
import java.util.List;import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import xyz.doikki.videoplayer.player.BaseVideoView;
import xyz.doikki.videoplayer.player.VideoView;public class AdvancePagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener,BaseVideoView.OnStateChangeListener {private Context context;private ViewPager viewPager;private List<Advance> datas;private List<View> list = new ArrayList<>();private int current = 0;private int time = 5000;private boolean pause;private Thread thread;private int lastPosition = -1;private final VideoView videoView;private final PreloadManager mPreloadManager;public AdvancePagerAdapter(Context context, ViewPager viewPager) {this.context = context;mPreloadManager = PreloadManager.getInstance(context);videoView = new VideoView(context);// 清空DNS,有时因为在APP里面要播放多种类型的视频(如:MP4,直播,直播平台保存的视频,和其他http视频), 有时会造成因为DNS的问题而报10000问题的//videoView.addFormatOption( "dns_cache_clear", 1);videoView.addOnStateChangeListener(this);this.viewPager = viewPager;}private boolean isRunning = false;public void setData(List<Advance> advances) {if (advances.size() == 0) return;for (int i = 0; i < advances.size(); i++) {if (advances.get(i).type.equals("1")){mPreloadManager.addPreloadTask(advances.get(i).path,i);}}if (isRunning){if (list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView){((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setDestroy();((AdvanceVideoView) list.get(viewPager.getCurrentItem())).currentPosition = 0;}stopTimer();}else {viewPager.addOnPageChangeListener(this);}viewPager.removeAllViews();this.datas = advances;list.clear();addView(advances.get(advances.size() - 1));if (advances.size() > 1) { //多于1个要循环for (Advance d : advances) { //中间的N个(index:1~N)addView(d);}addView(advances.get(0));}notifyDataSetChanged();//在外层,将mViewPager初始位置设置为1即可if (advances.size() > 1) { //多于1个,才循环并开启定时器viewPager.setCurrentItem(1);startNewTimer();}if (advances.get(0).type.equals("1")) {//有人反应第一个是视频不播放这边优化了一下
//            if ( ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView!=null){
//                ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView.setVisibility(View.VISIBLE);
//            }((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setVideo();}}private void addView(Advance advance) {if (advance.type.equals("1")) {AdvanceVideoView videoView = new AdvanceVideoView(context);videoView.setImage(advance.path,this.videoView,mPreloadManager);list.add(videoView);} else {AdvanceImageView imageView = new AdvanceImageView(context);imageView.setImage(advance.path);list.add(imageView);}}private final WeakHandler weakHandler = new WeakHandler();public void startNewTimer(){isRunning = true;weakHandler.post(timeRunnable);}private void stopTimer(){isRunning = false;current = 0;lastPosition = -1;weakHandler.removeCallbacks(timeRunnable);}private final Runnable timeRunnable = new Runnable() {@Overridepublic void run() {if (!pause && !(list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView)){current+=1000;}if (current >= time) {viewPager.post(() -> viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true));current = 0;}weakHandler.postDelayed(this,1000);}};private void startTimer() {if (thread != null && !thread.isInterrupted()) {thread.interrupt();thread = null;}thread = new Thread(() -> {while (thread != null && !thread.isInterrupted()) {try {Thread.sleep(1000);if (!pause && !(list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView))current += 1000;if (current >= time) {viewPager.post(() -> viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true));current = 0;}} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();}@Overridepublic int getCount() {return list.size();}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView(list.get(position));}@Overridepublic Object instantiateItem(ViewGroup container, int position) {View view = list.get(position);container.addView(view);return view;}@Overridepublic int getItemPosition(Object object) {return POSITION_NONE;}//
//    // 实现ViewPager.OnPageChangeListener接口@Overridepublic void onPageSelected(int position) {}@Overridepublic void onPageScrolled(int position, float positionOffset,int positionOffsetPixels) {// 什么都不干}@Overridepublic void onPageScrollStateChanged(int state) {// 由于viewpager的预加载机制onPageSelected这里面加载videoview 放的跟玩一样  等操作完成后再播放videoview就香了  很丝滑if (state == 0) {if (list.size() > 1) { //多于1,才会循环跳转if (lastPosition != -1 && lastPosition != viewPager.getCurrentItem() && list.get(lastPosition) instanceof AdvanceVideoView) {((AdvanceVideoView) list.get(lastPosition)).setPause();}if (viewPager.getCurrentItem() < 1) { //首位之前,跳转到末尾(N)int position = datas.size(); //注意这里是mList,而不是mViewsviewPager.setCurrentItem(position, false);} else if (viewPager.getCurrentItem() > datas.size()) { //末位之后,跳转到首位(1)viewPager.setCurrentItem(1, false); //false:不显示跳转过程的动画}current = 0;//换页重新计算时间if (list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView) {
//                    if ( ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView!=null){
//                        Log.e("xxx","xx"+((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView.toString());
//                        ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView.setVisibility(View.VISIBLE);
//                    }mPreloadManager.resumePreload(viewPager.getCurrentItem()-1,false);((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setVideo();}lastPosition = viewPager.getCurrentItem();}}}public void setDestroy(){pause = true;if (list.size() > 0 && list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView) {((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setDestroy();Log.e("调用销毁", " destroy");}weakHandler.removeCallbacksAndMessages(null);}public void setPause() {pause = true;if (list.size() > 0 && list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView) {((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setPause();Log.e("调用暂停", " pause");}}public void setResume() {pause = false;if (list.size() > 0 && list.get(viewPager.getCurrentItem()) instanceof AdvanceVideoView) {((AdvanceVideoView) list.get(viewPager.getCurrentItem())).setRestart();Log.e("调用start", " start");}}@Overridepublic void onPlayerStateChanged(int playerState) {}@Overridepublic void onPlayStateChanged(int playState) {Log.e("xxx","xx"+playState);if (playState== VideoView.STATE_PLAYBACK_COMPLETED){if (list.get(viewPager.getCurrentItem())instanceof AdvanceVideoView){((AdvanceVideoView) list.get(viewPager.getCurrentItem())).currentPosition = 0;if ( ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView!=null){((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView.setVisibility(View.VISIBLE);}}viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);}else if (playState==VideoView.STATE_PLAYING){if (list.get(viewPager.getCurrentItem())instanceof AdvanceVideoView){if ( ((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView!=null){((AdvanceVideoView) list.get(viewPager.getCurrentItem())).imageView.setVisibility(View.GONE);}}}else if (playState==VideoView.STATE_ERROR){mPreloadManager.pausePreload(viewPager.getCurrentItem()-1,false);viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);}}
}

7.xml中引入

  <com.anssy.smartbox.selfview.videoplay.AdvanceViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/home_vp"android:clickable="false"/>

8.activity中调用,oncreate中调用initData()即可,动态更新数据,只需调用data.clear(),mViewPager.setData(data)即可

    private List<Advance> data = new ArrayList<>();   private void initView(){mViewPager = findViewById(R.id.home_vp);mViewPager.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {return true;}});}  private void initData(){data.clear();//https://t7.baidu.com/it/u=1956604245,3662848045&fm=193&f=GIFAdvance advance1= new Advance("https://t7.baidu.com/it/u=1956604245,3662848045&fm=193&f=GIF","2");data.add(advance1);Advance advance = new Advance("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4","1");data.add(advance);Advance advance2 = new Advance("https://www.w3schools.com/html/movie.mp4","1");data.add(advance2);Advance advance3 = new Advance("https://t7.baidu.com/it/u=1415984692,3889465312&fm=193&f=GIF","2");data.add(advance3);mViewPager.setData(data);}public static String toURLString(String str) {StringBuilder sb = new StringBuilder();for (int i = 0; i < str.length(); i++) {char charAt = str.charAt(i);if (charAt > 255) {try {sb.append(URLEncoder.encode(String.valueOf(charAt), "utf-8"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}} else {sb.append(charAt);}}return sb.toString();}@Overrideprotected void onResume() {super.onResume();mViewPager.setResume();}@Overrideprotected void onPause() {super.onPause();mViewPager.setPause();}@Overrideprotected void onDestroy() {super.onDestroy();mViewPager.setDestroy();}

9.播放效果

20230507103839

切换效果

20230507105453

Android 广告机图片视频轮播相关推荐

  1. Android实现广告页图片无限轮播

    一.概述 对于一个联网的Android应用, 首页广告无限轮播基本已经成为标配了. 那么它是怎么实现的呢? 有几种实现方式呢? 二.无限轮播的实现 1.最常规的手段是用 ViewPager来实现 2. ...

  2. Android 视频图片 轮播,详解android 视频图片混合轮播实现

    循环添加视频view  图片view for (int i = 0 ;i if (beansarraylist.get(i).gettype()==1){ videoplayer = new nice ...

  3. vue项目里面视频与图片的轮播

    需求 仿照天猫等实现视频与图片的轮播效果 运用的控件有: 1.视频播放器:腾讯云点播超级播放器官方文档地址(一定要看) 2.轮播插件:iSlider----这是一个表现出众,轻量且高性能,无任何库依赖 ...

  4. Android三方框架banner实现轮播图

    Android三方框架banner实现轮播图 关于 效果图 第一步,添加引用 第二步,新增实体类及测试数据 第三步,添加banner实例控件,修改主界面代码 自定义图片+标题轮播图 效果图 你以为到这 ...

  5. 使用Swiper插件实现视频轮播,怎么实现切换自动播放视频?

    一.需求分析 这两天讨论了一个项目需求,刚开始是希望:轮播图中嵌入视频,轮播到视频自动播放,播放完毕切换下一张轮播,手动切换时暂停播放视频.后面因为自动播放没有声音,便暂时放弃了这个想法(有知道或了解 ...

  6. 仿网易云音乐 专辑图片折叠轮播

    仿网易云音乐 专辑图片折叠轮播 先不多说现上一张效果图 首先简述一下实现原理 1.首先让我们的imageview**动起来** 其实是不断的.invalidate();函数 让他不断的调用ondarw ...

  7. BannerLayoutSimple 支持图片无限轮播的 BannerLayout,支持自定义小圆点位置以及显示位置等等,反正支持的挺多的,源码也有注释

    BannerLayoutSimple 项目地址: 7449/BannerLayoutSimple 简介:支持图片无限轮播的 BannerLayout,支持自定义小圆点位置以及显示位置等等,反正支持的挺 ...

  8. uniapp APP端视频轮播问题

    uniapp APP端视频轮播问题(黑屏,变形) 今天接到一个需求:需要在商品详情轮播展示视频,本以为很简单,但是发现好多坑,在app端出现黑屏,卡顿,变形,视频只展示半屏的情况. 完整代码放底下了 ...

  9. 网页视频轮播video

    最近,在项目的实际开发中,有遇到UI设计的视频轮播的效果,在实际解决之前,在网上查找了相关资料,有看到一篇CDSN的博客,有所启发,现根据实际遇到的问题,做如下记录. 一.实例相关情况介绍 参考的实例 ...

最新文章

  1. 怎么样才可批量导出word文档中的照片 不再一张一张的另存为!
  2. windows常见的运行命令以及各快捷键组合
  3. Qt学习笔记(一) 第一个Qt应用程序
  4. SQL Server语句大全(增删改查数据、创建表、删除表、修改表)
  5. 30分钟后的飞鸽传书
  6. Arcgis License的安装及破解
  7. Java ConcurrentHashMap 最佳实践
  8. php中的魔术常量__FILE__
  9. 一个关于var函数计算方差 / 标准差的问题
  10. 微信开发 ━━ 微信商户v3微信支付回调之php篇
  11. oppok1掉色吗?_如何对旧的褪色照片进行色彩校正
  12. vue3中导出excel表格
  13. 媒体 | 冒志鸿:ArcBlock打造跨链应用平台的思路
  14. gb18030编码格式了解和应用
  15. 【Unity XR】Unity开发OpenXR
  16. 【python】身份证号码有效性校验
  17. caffe-MobileNet-ssd环境搭建及训练自己的数据集模型
  18. 2020-09-20周总结
  19. 三相永磁同步电机的矢量控制学习笔记一
  20. C#将jpg格式图片合成到bmp格式图片中

热门文章

  1. Linux Netlink通信
  2. pingpong机制的理解
  3. 【广告】会数学就能学会的编程语言
  4. 如何制作有小颗粒的背景图片
  5. mysql chinanet外网连接不上_中国的chinanet计算机网络是什么
  6. linux搭建文件服务器
  7. shellexecute 执行完成_如何使用hinstance确定win32api.ShellExecute是否成功?
  8. 安装Sql server2019时出现错误:服务没有及时响应启动或控制请求
  9. C The Party and Sweets(思维 + 贪心)
  10. CDN加速究竟是怎么加速的 其工作原理是怎样的