Android 列表视频滑动自动播放—滑动过程自动播放(实现思路)

本文基于Exoplayer +  PlayerView 实现列表视频显示一定比例后自动播放

首先引入google media3包

implementation 'androidx.media3:media3-exoplayer:1.1.1'
implementation 'androidx.media3:media3-exoplayer-dash:1.1.1'
implementation 'androidx.media3:media3-ui:1.1.1'
implementation "androidx.media3:media3-common:1.1.1"

列表自动播放,我们需要监听recyclerView.addOnScrollListener(this),并实现对应方法

onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) 中判断滑动过程中,展示视频itemVideoView比例

1、首先我们需要拿到recyclerView显示出来的itemPosition

int firstItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
int lastItemPosition = linearLayoutManager.findLastVisibleItemPosition();

2、当判断第一个(firstItemPosition)和最后一个(lastItemPosition)都大于0时候,开始遍历recyclerView数据,判断显示视频itemVideoView显示比例(因为我项目,视频播放数据是二维数组。RecyclerView1+RecyclerView2结构,所以视频播放时在里层RecyclerView2,如果不是二维,那么就RecyclerView2其实就是视频播放容器,dataItem.getVideoPosition()其实就是告诉我们RecyclerView2中第几条数据播放视频,默认是-1,表示没有视频,需要我们在网络请求后,遍历数据生成对应可以展示视频position)

 public void recyclerViewScrollVideo() {
        if (recyclerView == null || linearLayoutManager == null || communityPostListAdapter == null) {
            return;
        }
        int firstItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
        int lastItemPosition = linearLayoutManager.findLastVisibleItemPosition();
        if (firstItemPosition >= 0 && lastItemPosition >= 0) {
            DataItem dataItem = communityPostListAdapter.getData(firstItemPosition);
            CommonViewHolder viewHolder = (CommonViewHolder) recyclerView.findViewHolderForAdapterPosition(firstItemPosition);
            if (viewHolder != null) {
                //当第一个显示数据,不支持播放视频时候,需要直接遍历后面,看是否有支持视频的
                //获取里层 RecyclerView Image
                RecyclerView recyclerImage = viewHolder.getView(R.id.communal_post_header_recycler_image);
                if (dataItem != null && dataItem.getVideoPosition() >= 0 && recyclerImage != null) {
                    //获取里层视频那个itemView position
                    int videoPosition = dataItem.getVideoPosition();
                    CommonViewHolder itemViewHolder = (CommonViewHolder) recyclerImage.findViewHolderForAdapterPosition(videoPosition);
                    //获取当前视频itemBen
                    VideoAdapter videoAdapter = (CommunalImageAdapter) recyclerImage.getAdapter();
                    //获取视频数据对象
                    VideoDataBean videoDataBean = null;
                    if (videoDataBean != null) {
                        videoDataBean = videoAdapter.getData(videoPosition);
                    }
                    boolean isPlaying = ExoPlayerManager.getInstance().recyclerViewScrollVideo(recyclerImage, itemViewHolder, firstItemPosition, videoDataBean);
                    if (!isPlaying) {
                        //firstItemPosition不支持播放,则遍历RecyclerView数据判断下一个是否支持播放
                        int newFirstItemPosition = firstItemPosition + 1;
                        traversal(recyclerView, newFirstItemPosition, lastItemPosition);
                    }
                } else {
                    //有可能是多布局,则第一条数据,找不到视频播放view,那么我们需要遍历数据,从第二条数据开始找
                    int newFirstItemPosition = firstItemPosition + 1;
                    traversal(recyclerView, newFirstItemPosition, lastItemPosition);
                }

            }

        }
    }

3、当第一条不满足,开始遍历

 /**
     * 遍历寻找,屏幕显示可以播放视频的item
     *
     * @param recycler
     * @param newFirstItemPosition
     * @param lastItemPosition
     */
    private void traversal(RecyclerView recycler, int newFirstItemPosition, int lastItemPosition) {
        //标记是否找到视频-1,表示未找到视频
        int playPosition = -1;
        for (int i = newFirstItemPosition; i <= lastItemPosition; i++) {
            DataItem dataItem = communityPostListAdapter.getData(i);
            CommonViewHolder viewHolder = (CommonViewHolder) recycler.findViewHolderForAdapterPosition(i);
            if (viewHolder != null && dataItem != null && dataItem.getVideoPosition() >= 0) {
                RecyclerView recyclerImage = viewHolder.getView(R.id.communal_post_header_recycler_image);
                if (recyclerImage != null) {
                    CommonViewHolder itemViewHolder = (CommonViewHolder) recyclerImage.findViewHolderForAdapterPosition(dataItem.getVideoPosition());
                    //获取当前视频itemBen
                    VideoAdapter videoAdapter = (CommunalImageAdapter) recyclerImage.getAdapter();
                    VideoDataBean videoDataBean = null;
                    if (videoAdapter != null) {
                        videoDataBean = videoAdapter.getData(dataItem.getVideoPosition());
                    }
                    if (ExoPlayerManager.getInstance().recyclerViewScrollVideo(recyclerImage, itemViewHolder, i, communalImageBean)) {
                        playPosition = i;
                        break;
                    }

                }

            }
        }
        if (playPosition == -1) {
            //都没有找到视频
            ExoPlayerManager.getInstance().stopVideo();
        }
    }

4、视频播放器单例(Exoplayer +  PlayerView)


public class ExoPlayerManager {

    private static volatile ExoPlayerManager inStance = null;
    ExoPlayer mExoPlayer;
    public ExoPlayerListener mExoPlayerListener;
    private UserPlayerView mUserPlayerView;
    //视频容器
    private FrameLayout mLayout;
    //loading view
    private ProgressBar mLoading;
    //视频logo
    private ImageView mLogo;
    //点击播放按钮
    private ImageView mPlay;

    //计算RecyclerView显示位置
    private Rect mItemRect;
    //RecyclerView显示高度
    float visibleHeight;
    //RecyclerView内容高度
    float totalHeight;
    //RecyclerView 显示高度和高度比例
    float visibleRatio;
    int mItemPlayPosition;
    //视频播放数据对象
    VideoDataBean mVideoDataBean;
    //视频最先显示比例
    private float minRatio;

    /**
     * 监听
     */
    private AnalyticsListener mAnalyticsListener = new AnalyticsListener() {
        @Override
        public void onPlaybackStateChanged(EventTime eventTime, int state) {
            AnalyticsListener.super.onPlaybackStateChanged(eventTime, state);
            switch (state) {
                case Player.STATE_IDLE:  //未加载到资源,停止播放,包含无网也会执行
                    if (mExoPlayerListener != null) {
                        mExoPlayerListener.onVideoPlayIdle();
                    } else {
                        stopShowView();
                    }
                    showController();
                    break;
                case Player.STATE_BUFFERING: //缓冲中
                    if (mExoPlayerListener != null) {
                        mExoPlayerListener.onVideoPlayBuffering(eventTime != null ? eventTime.currentPlaybackPositionMs : -1L);
                    } else {
                        loadingShowView();
                    }
                    break;

                case Player.STATE_READY:  //开始播放
                    if (mExoPlayerListener != null) {
                        mExoPlayerListener.onVideoPlay(eventTime != null ? eventTime.currentPlaybackPositionMs : -1L);
                    } else {
                        startShowView();
                    }

                    break;

                case Player.STATE_ENDED:  //播放结束,当循环播放时候,改方法不会被触发  onPositionDiscontinuity  DISCONTINUITY_REASON_AUTO_TRANSITION
                    if (mExoPlayerListener != null) {
                        mExoPlayerListener.onVideoPlayerCompletion();
                    }
                    break;
            }
        }

        @Override
        public void onPositionDiscontinuity(EventTime eventTime, Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
            AnalyticsListener.super.onPositionDiscontinuity(eventTime, oldPosition, newPosition, reason);
            if (mExoPlayerListener != null) {
                mExoPlayerListener.onVideoPlayerCompletion();
            } else {
                //循环播放了,显示时间
                if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
                    showController();
                }
            }

        }

        @Override
        public void onPlayerError(EventTime eventTime, PlaybackException error) {
            AnalyticsListener.super.onPlayerError(eventTime, error);
            if (mExoPlayerListener != null) {
                mExoPlayerListener.onVideoPlayerError(eventTime != null ? eventTime.currentPlaybackPositionMs : -1l);
            } else {
                Toast.makeText(CommonParam.getInstance().getApplication(), "网络异常", Toast.LENGTH_LONG).show();
                if (eventTime != null) {
                    long currentPlaybackPositionMs = eventTime.currentPlaybackPositionMs;
                    if (mVideoDataBean != null && currentPlaybackPositionMs > 0) {
                        mVideoDataBean.setSeekToPositionMs(currentPlaybackPositionMs);
                    }
                }
                //网络异常会执行--onPlayerError---onPlaybackStateChanged(1)----onIsPlayingChanged()
                stopShowView();
            }
        }
    };

    public static ExoPlayerManager getInstance() {
        if (inStance == null) {
            synchronized (ExoPlayerManager.class) {
                if (inStance == null) {
                    inStance = new ExoPlayerManager();
                }
            }
        }
        return inStance;
    }

    private ExoPlayerManager() {
        init();
    }


    private void init() {
        //初始化exoPlayer
        if (mExoPlayer == null) {
            mExoPlayer = new ExoPlayer.Builder(CommonParam.getInstance().getApplication()).build();
            mExoPlayer.addAnalyticsListener(mAnalyticsListener);
        }
        // 设置重复模式
        // Player.REPEAT_MODE_ALL 无限重复
        // Player.REPEAT_MODE_ONE 重复一次
        // Player.REPEAT_MODE_OFF 不重复
        mExoPlayer.setRepeatMode(Player.REPEAT_MODE_ALL);
        setVolume(CommonParam.getInstance().isVideoVolumeChange());

        if (mItemRect == null) {
            mItemRect = new Rect();
        }
        if (mUserPlayerView == null) {
            mUserPlayerView = new UserPlayerView(CommonParam.getInstance().getApplication());
            ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            mUserPlayerView.setLayoutParams(layoutParams);
        }
        //设置视频填充模式  RESIZE_MODE_FILL 拉伸视频达到没有黑边效果,RESIZE_MODE_ZOOM:这个是居中填充效果
        mUserPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH);
        minRatio = 9f / 16f;
    }


    /**
     * 获取视频View
     *
     * @return
     */
    public UserPlayerView getUserPlayerView() {
        return mUserPlayerView;
    }

    /**
     * 添加监听
     */
    public void addAnalyticsListener() {
        if (mExoPlayer != null) {
            mExoPlayer.removeAnalyticsListener(mAnalyticsListener);
            mExoPlayer.addAnalyticsListener(mAnalyticsListener);
        }
    }

    /**
     * 移除监听
     */
    public void removeAnalyticsListener() {
        if (mExoPlayer != null) {
            mExoPlayer.removeAnalyticsListener(mAnalyticsListener);
        }
    }

    /**
     * 视频显示尺寸修改
     *
     * @param params
     * @param playerView
     * @param maxWidth   屏幕显示最大宽
     * @param width      视频真实宽
     * @param height     视频真实高
     */
    public void disposeVideoSize(ViewGroup.LayoutParams params, View playerView, int maxWidth, float width, float height) {
        if (params != null && playerView != null) {
            if (width > 0 && height > 0) {
                if (height >= width) {
                    int showWidth = (int) (maxWidth > 0 ? maxWidth : width);
                    params.width = showWidth;
                    params.height = showWidth;
                } else {
                    params.width = maxWidth;
                    float ratio = height / width;
                    params.height = (int) ((ratio >= minRatio) ? ratio * maxWidth : minRatio * maxWidth);
                }

            } else if (maxWidth > 0) {
                params.width = maxWidth;
                params.height = maxWidth;
            } else {
                params.width = ViewGroup.LayoutParams.MATCH_PARENT;
                params.height = ViewGroup.LayoutParams.MATCH_PARENT;
            }
            playerView.setLayoutParams(params);
        }
    }


  

    /**
     * 获取当前列表布局控件,一会计算时候需要用
     *
     * @param recyclerImage
     * @param itemViewHolder
     * @param communalImageBean
     */
    public boolean recyclerViewScrollVideo(RecyclerView recyclerImage, CommonViewHolder itemViewHolder, int itemPlayPosition, CommunalImageBean communalImageBean) {
        if (recyclerImage != null && itemViewHolder != null && communalImageBean != null) {
            FrameLayout frameLayout = itemViewHolder.getView(R.id.video);
            ImageView logo = itemViewHolder.getView(R.id.logo);
            ImageView play = itemViewHolder.getView(R.id.play);
            ProgressBar loading = itemViewHolder.getView(R.id.loading);
            ImageView volume = itemViewHolder.getView(R.id.volume);
            setVolumeViewChange(volume);
            setVolume(CommonParam.getInstance().isVideoVolumeChange());
            return calculateVideoPlay(recyclerImage, frameLayout, play, logo, loading, itemPlayPosition, communalImageBean);
        }
        return false;
    }

    /**
     * 计算是否滑动自动播放视频
     *
     * @param view
     * @param frameLayout
     * @param play
     * @param logo
     * @param loading
     * @param videoDataBean
     */
    public boolean calculateVideoPlay(View view, FrameLayout frameLayout, ImageView play, ImageView logo, ProgressBar loading, int itemPlayPosition,VideoDataBean videoDataBean ) {
        view.getLocalVisibleRect(mItemRect);
        visibleHeight = mItemRect.bottom - mItemRect.top;
        totalHeight = view.getHeight();
        visibleRatio = visibleHeight / totalHeight;
        if (mItemRect.top >= 0 && visibleRatio > BaseConstantValue.VIDEO_START_VISIBLE_RATIO) {
            playVideo(frameLayout, play, logo, loading, itemPlayPosition, videoDataBean);
            return true;
        } else {
            //不满足播放
            if (play != null) {
                play.setVisibility(View.VISIBLE);
            }
            if (loading != null) {
                loading.setVisibility(View.GONE);
            }
            if (logo != null) {
                logo.setVisibility(View.VISIBLE);
            }
            if (frameLayout != null) frameLayout.removeAllViews();

        }
        return false;
    }

    /**
     * 满足播放视频,需要再判断,是不是已经还在播放当前视频
     *
     * @param layout
     * @param play
     * @param logo
     * @param loading
     * @param itemPlayPosition
     * @param videoDataBean
     */
    public void playVideo(FrameLayout layout, ImageView play, ImageView logo, ProgressBar loading, int itemPlayPosition, VideoDataBean videoDataBean) {
        if (mItemPlayPosition != itemPlayPosition) {
            //不满足当前播放那么需要停止播放,做部分资源保存
            if (videoDataBean != null && mExoPlayer.isPlaying()) {
                //视频已经播放位置
                videoDataBean.setSeekToPositionMs(mExoPlayer.getContentPosition());
            }
            //显示暂停不播布局
            stopShowView();
            //暂停播放
            stopVideo();
        }
        //重新复制相关控件
        mLayout = layout;
        mPlay = play;
        mLogo = logo;
        mLoading = loading;

        //获取当前播放状态,如果未播放,则直接设置资源播放,如果已经播放,则不做处理
        if (!mExoPlayer.isPlaying()) {
            //设置播放布局
            loadingShowView();
            //移除播放View
            if (mUserPlayerView != null) {
                ViewParent parent = mUserPlayerView.getParent();
                if (parent != null && parent instanceof FrameLayout) {
                    ((FrameLayout) parent).removeAllViews();
                }
            }

            //将PlayerView 添加 FrameLayout上
            if (layout != null) {
                layout.removeAllViews();
                layout.addView(mUserPlayerView);
            }
            if (videoDataBean != null) {
                String videoUrl = videoDataBean.getVideoUrl();
                long seekToPositionMs = videoDataBean.getSeekToPositionMs();
                long durationMs = videoDataBean.getDurationMs();
                mUserPlayerView.setVideoPosition(seekToPositionMs, durationMs);
                MediaItem mediaItem = MediaItem.fromUri(videoUrl != null ? videoUrl : "");
                mExoPlayer.setMediaItem(mediaItem, seekToPositionMs);
            }

            mUserPlayerView.setPlayer(mExoPlayer);

            mExoPlayer.prepare();
//            mExoPlayer.play();
            mExoPlayer.setPlayWhenReady(true);
        }

        mItemPlayPosition = itemPlayPosition;
        mVideoDataBean = videoDataBean;
    }


    public ExoPlayer exoPlayer() {
        return mExoPlayer;
    }

    /**
     * 是否正在播放
     *
     * @return
     */
    public boolean isPlaying() {
        return mExoPlayer != null ? mExoPlayer.isPlaying() : false;
    }

    /**
     * 获取当前播放进度
     *
     * @return
     */
    public long getCurrentPositionMs() {
        if (mExoPlayer != null && mExoPlayer.isPlaying()) {
            return mExoPlayer.getCurrentPosition();
        }
        return -1;
    }

    /**
     * 获取总时长
     *
     * @return
     */
    public long getDurationMs() {
        if (mExoPlayer != null) {
            return mExoPlayer.getDuration();
        }
        return 0l;
    }

    /**
     * 设置进度
     *
     * @param seekToCurrentPositionMs
     */
    public void seekTo(long seekToCurrentPositionMs) {
        if (mExoPlayer != null) {
            mExoPlayer.seekTo(seekToCurrentPositionMs);
            if (!isPlaying()) {
                mExoPlayer.play();
            }
        }
    }

    /**
     * 设置是否有视频控制器
     *
     * @param useController
     */
    private void setUseController(boolean useController) {
        mUserPlayerView.setUseController(useController);

    }

    /**
     * 绑定全屏播放
     *
     * @param videoUrl
     * @param currentPositionMs
     * @return
     */
    private UserPlayerView bindVideoFullScreen(String videoUrl, long currentPositionMs) {
        mItemPlayPosition = -1;
        mExoPlayer.setMediaItem(MediaItem.fromUri(videoUrl == null ? "" : videoUrl), currentPositionMs);
        mUserPlayerView.setPlayer(mExoPlayer);
        mExoPlayer.prepare();
        mVideoDataBean = null;
        return mUserPlayerView;
    }


    /**
     * 开始播放
     */
    public void startVideo() {
        if (mExoPlayer != null && !mExoPlayer.isPlaying()) {
            mExoPlayer.play();
        }
    }

    /**
     * 开始播放
     */
    public void startVideo(long currentPositionMs) {
        if (mExoPlayer != null && !mExoPlayer.isPlaying()) {
            mExoPlayer.seekTo(currentPositionMs);
            mExoPlayer.play();
        }
    }

    /**
     * 开始播放
     */
    public void startVideo(String videoUrl, long currentPositionMs) {
        if (mExoPlayer != null) {
            if (!mExoPlayer.isPlaying()) {
                mExoPlayer.stop();
            }
            mExoPlayer.setMediaItem(MediaItem.fromUri(videoUrl == null ? "" : videoUrl), currentPositionMs);
            mUserPlayerView.setPlayer(mExoPlayer);
            mExoPlayer.prepare();
            mExoPlayer.play();
        }

    }

    /**
     * 暂停播放
     */
    public void pauseVideo() {
        if (mExoPlayer != null && mExoPlayer.isPlaying()) {
            mExoPlayer.pause();
        }
    }

    /**
     * 停止播放
     */
    public void stopVideo() {
        mItemPlayPosition = -1;
        if (mExoPlayer != null && mExoPlayer.isPlaying()) {
            if (mVideoDataBean != null) {
                mVideoDataBean.setSeekToPositionMs(mExoPlayer.getContentPosition());
            }
            mExoPlayer.stop();
        }
        releaseView();
    }

    /**
     * 页面关闭,释放资源
     */
    public void releaseVideo() {
        if (mExoPlayer != null) {
            mExoPlayer.removeAnalyticsListener(mAnalyticsListener);
            mExoPlayer.release();
            mExoPlayer = null;
        }
        releaseView();
    }

    private void releaseView() {
        if (mUserPlayerView != null) {
            ViewParent parent = mUserPlayerView.getParent();
            if (parent != null && parent instanceof FrameLayout) {
                ((FrameLayout) parent).removeAllViews();
            }
        }
        //将PlayerView 添加 FrameLayout上
        if (mLayout != null) {
            mLayout.removeAllViews();
            mLayout = null;
        }
        if (mPlay != null) {
            mPlay = null;
        }
        if (mLogo != null) {
            mLogo = null;
        }
        if (mLoading != null) {
            mLoading = null;
        }
        mVideoDataBean = null;
    }

    /**
     * 设置播放器是否开启声音
     *
     * @param volumeChange
     */
    public void setVolume(boolean volumeChange) {
        if (volumeChange) {
            //设置声音
            if (mExoPlayer.getVolume() == 0f) {
                AudioManager audioManager = (AudioManager) CommonParam.getInstance().getApplication().getSystemService(Context.AUDIO_SERVICE);
                float streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                float streamMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
                float volume = (streamMaxVolume != 0 && streamVolume != 0) ? streamVolume / streamMaxVolume : 0.3f;
                mExoPlayer.setVolume(volume);
            }
        } else {
            //设置声音为0
            mExoPlayer.setVolume(0f);
        }
        CommonParam.getInstance().setVideoVolumeChange(volumeChange);
    }

    /**
     * 设置 音量开关状态
     *
     * @param volumeView
     */
    public void setVolumeViewChange(View volumeView) {
        if (volumeView != null) {
            volumeView.setSelected(CommonParam.getInstance().isVideoVolumeChange());
        }
    }

    /**
     * 视频正在播放,设置相关布局show or hide
     */
    public void startShowView() {
        if (mLoading != null) {
            mLoading.setVisibility(View.GONE);
        }
        if (mLogo != null) {
            mLogo.setVisibility(View.GONE);
        }
        if (mPlay != null) {
            mPlay.setVisibility(View.GONE);
        }
    }

    /**
     * 视频正在加载中,设置相关布局show or hide
     */
    public void loadingShowView() {
        if (mLoading != null) {
            mLoading.setVisibility(View.VISIBLE);
        }
        if (mLogo != null) {
            mLogo.setVisibility(View.VISIBLE);
        }
        if (mPlay != null) {
            mPlay.setVisibility(View.GONE);
        }
    }

    /**
     * 视频停止播放,设置相关布局show or hide
     */
    public void stopShowView() {
        if (mLoading != null) {
            mLoading.setVisibility(View.GONE);
        }
        if (mLogo != null) {
            mLogo.setVisibility(View.VISIBLE);
        }
        if (mPlay != null) {
            mPlay.setVisibility(View.VISIBLE);
        }
    }

    /**
     * 显示视频控制器
     */
    public void showController() {
        if (mUserPlayerView != null) {
            UserPlayerControlView controller = mUserPlayerView.getController();
            if (controller != null) {
                controller.show();
            }
        }
    }

    /**
     * 设置监听
     *
     * @param exoPlayerListener
     */
    public void setExoPlayerListener(ExoPlayerListener exoPlayerListener) {
        mExoPlayerListener = exoPlayerListener;
    }
}

5、建议我们在开发视频时自定义PlayerView,只需要把源码中,这三个文件拷贝一份,然后自己根据具体需求,实现对应功能。

①、PlayerView

②、PlayerControlView

③、PlayerControlViewLayoutManager

6、如果项目是appBarLayout+RecyclerView的话。我们需要对appBarLayout滑动事件进行监听,从而实现appBarLayout滑动,也能播放视频

  mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.BaseOnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                //appBarLayout 滑动监听
                int newOffset = Math.abs(verticalOffset);
                if (mVerticalOffset != newOffset && adapter != null) {
                    Fragment fragment = adapter .getFragment(viewPagerShowType);
                    if (fragment != null && fragment.isOnResume()) {
                        fragment.startVideo();
                    }
                    mVerticalOffset = newOffset;
                }

            }
        });

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/784534.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手写简单模拟mvc

目录结构&#xff1a; 两个注解类&#xff1a; Controller&#xff1a; package com.heaboy.annotation;import java.lang.annotation.*;/*** 注解没有功能只是简单标记* .RUNTIME 运行时还能看到* .CLASS 类里面还有&#xff0c;构建对象久没来了&#xff0c;这个说明…

Java信号量semaphore的原理与使用方法

Semaphore的基本概念 在Java中&#xff0c;Semaphore是位于java.util.concurrent包下的一个类。它的核心就是维护了一个许可集。简单来说&#xff0c;就是有一定数量的许可&#xff0c;线程需要先获取到许可&#xff0c;才能执行&#xff0c;执行完毕后再释放许可。 那么&…

Django 新增数据 create()方法

1&#xff0c;添加模型 Test/app11/models.py from django.db import modelsclass Book(models.Model):title models.CharField(max_length100)author models.CharField(max_length100)publication_date models.DateField()price models.DecimalField(max_digits5, decim…

意得辑ABSJU202优惠15%啦,新用户注册直减哦

不得不说&#xff0c;还得是意得辑&#xff0c;钱不白花&#xff0c;润色的挺好~ 第一篇SCI终于成功见刊&#xff01;&#xff01;&#xff01; 都来接accept&#xff01;&#xff01;&#xff01;谢谢accept小狗&#xff0c;接accept 求求accept小狗&#xff0c;真的想要双证毕…

消防认证-防火窗

一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准&#xff0c;且通过了国家认证认可监督管理委员会审批&#xff0c;获得消防认证资质的认证机构颁发的证书&#xff0c;消防产品具有完好的防火功能&#xff0c;是住房和城乡建设领域验收的重要指标。 二、认证依据…

绝地求生PUBG没有开始游戏按钮的解决办法

绝地求生是一款特别热门的战术竞技型射击类游戏&#xff0c;游戏中玩家需要在游戏地图上收集各种资源&#xff0c;并在不断缩小的安全区域内持武器对抗其他玩家&#xff0c;让自己生存到最后。当游戏最后场上只剩下一支队伍的时候即可获得游戏胜利。然而一些玩家在游玩绝地求生…

深入探索 Python 中的数据维数:高维数据处理方法与应用

Python 数据维数 在数据科学和机器学习领域&#xff0c;理解数据的维度是至关重要的。Python作为一种强大而灵活的编程语言&#xff0c;提供了丰富的工具和库来处理各种维度的数据。本文将介绍Python中数据维数的概念&#xff0c;以及如何使用Python库来处理不同维度的数据。 什…

YARN运行流程源码分析

一、yarn任务执行流程图 在分析任务之前先走一下yarn内部的流程细节。 二、RM 内部处理提交阶段运行流程 如上图流程所示&#xff1a; 1.client 提交任务给yarn&#xff0c;yarn 这边会获取任务的AM相关资源&#xff0c;client在提交阶段会上传job.split &#xff08;数据切分…

SpringCloud第一篇Docker基础

文章目录 一、常见命令二、数据卷三、数据挂载四、自定义镜像五、网络 一、常见命令 Docker最常见的命令就是操作镜像、容器的命令&#xff0c;详见官方文档&#xff1a; https://docs.docker.com/ 需求&#xff1a; 在DockerHub中搜索Nginx镜像&#xff0c;查看镜像的名称 …

企业如何从无序管理走向精益生产管理?

先来看看企业生产管理无序的弊端有哪些&#xff1f; 数据统计不及时&#xff1a;纸质生产工单&#xff0c;数据难统计&#xff0c;各业务环节问题难定位&#xff0c;影响车间生产效率。生产过程不透明&#xff1a;生产过程数据难监控&#xff0c;生产派工管理混乱&#xff0c;…

百度网盘非会员,享受视频倍速

百度网盘会员过期了&#xff0c;看视频不能倍速很难受&#xff0c;下面就是跨过会员机制&#xff0c;享受倍速的方法。 Edge浏览器 在浏览器设置中找到扩展选项 在扩展中搜索视频速度控制 global speed&#xff0c;安装后即可使用

在Linux操作系统中去修复/etc/fstab文件引起的系统故障。

如果/etcfstab文件中发生错误&#xff0c;有可能导致系统无法正常启动。 比如&#xff1a;系统里的一块磁盘被删除&#xff0c;但是/etc/fstab中关于这块磁盘的信息依然被保存在文件/etc/fstab中。 主要看倒数后两行&#xff0c;系统提示&#xff0c;敲ctrlD或者是直接输入密码…

2通道音频ADC解码芯片ES7243L、ES7243E、ES7243,用于低成本实现模拟麦克风转换为IIS数字话筒

前言&#xff1a; 音频解码芯片某创参考价格&#xff1a; ES7243L 500&#xff1a;&#xffe5;1.36 / 个 ES7243E 500&#xff1a;&#xffe5;1.66 / 个 ES7243 500&#xff1a; &#xffe5;1.91 / 个 其中ES7243L工作电压为1.8V&#xff0c;与其他两款的3.3V工作电压不同&…

推荐3款免费电脑工具

Tools-Web Tools-Web是一个在线工具箱&#xff0c;提供丰富的工具和功能&#xff0c;适用于日常工作和学习。根据用户评价&#xff0c;Tools-Web的工具种类丰富且操作简单&#xff0c;是日常工作和学习的好帮手。该工具箱涵盖了开发运维、文本处理、图片处理、图表处理、随机工…

大模型知识问答: 文本分块要点总结

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、算法项目落地经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接如…

昇思MindSpore学习笔记6-01LLM原理和实践--FCN图像语义分割

摘要&#xff1a; 记录MindSpore AI框架使用FCN全卷积网络理解图像进行图像语议分割的过程、步骤和方法。包括环境准备、下载数据集、数据集加载和预处理、构建网络、训练准备、模型训练、模型评估、模型推理等。 一、概念 1.语义分割 图像语义分割 semantic segmentation …

【易捷海购-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【2024华为HCIP831 | 高级网络工程师之路】刷题日记(BGP)

个人名片:🪪 🐼作者简介:一名大三在校生,喜欢AI编程🎋 🐻‍❄️个人主页🥇:落798. 🐼个人WeChat:hmmwx53 🕊️系列专栏:🖼️ 零基础学Java——小白入门必备🔥重识C语言——复习回顾🔥计算机网络体系———深度详讲HCIP数通工程师-刷题与实战🔥🔥

windows obdc配置

进入控制面板&#xff1a; 进入管理工具&#xff1a;

java —— JSP 技术

一、JSP &#xff08;一&#xff09;前言 1、.jsp 与 .html 一样属于前端内容&#xff0c;创建在 WebContent 之下&#xff1b; 2、嵌套的 java 语句放置在<% %>里面&#xff1b; 3、嵌套 java 语句的三种语法&#xff1a; ① 脚本&#xff1a;<% java 代码 %>…