RecyclerView自定义LayoutManager从0到1实践

news2024/11/18 17:52:17

此前大部分涉及到 RecyclerView 页面的 LayoutManager基本上用系统提供的 LinearLayoutManager 、GridLayoutManager 就能解决,但在一些特殊场景上还是需要我们自定义 LayoutManager。之前基本上没有自己写过,在网上看各种源码各种文章,刚开始花了好多时间去理解整体流程,因为它们都给我一种非常非常复杂的感觉,包括相关的博客文章也是。经过一段时间摸索,也慢慢能理解为什么要那么复杂了,这的确不是特别容易入门。所以对整体的流程进行了一个拆解,尽量原子化一点,对自己学习的一个总结,也希望能帮助到一部分人能对 LayoutManager 入门。

本文最终实现一个简单的 LinearLayoutManager(只支持 VERTICAL)方向,适合对 LayoutManager 整体流程的学习与理解,整体代码分为多个文件,每个文件都是对前一段代码的补充,方便理解,整体项目源码已提交 Github: LayoutManagerGradually,代码里面写了很多很多注释,如果不想浪费时间,可以直接看代码运行,跳过这篇文章,把每一个 LayoutManager 都跑一下体验结合代码看看。

自定义 LayoutManager 的必要元素

  • 继承 RecyclerView.LayoutManager 并实现 generateDefaultLayoutParams() 方法

  • 重写onLayoutChildren 第一次数据填充的时候数据添加

  • 重写 canScrollHorizontally()canScrollVertically()方法设定支持滑动的方向

  • 重写 scrollHorizontallyBy()scrollVerticallyBy()方法,在滑动的时候对屏幕以外的 View 进行回收,以及填充即将滑动进入屏幕范围内的 View 进行填充

  • 重写 scrollToPosition()smoothScrollToPosition()方法支持

其中onLayoutChildrenscrollHorizontallyBy/scrollVerticallyBy 是最核心且最复杂的方法,这里稍微拎出来讲一下

onLayoutChildren

这个方法类似于自定义 ViewGroup 的 onLayout() 方法,RecyclerView 的 LayoutManager.onLayoutChildren 在以下几个时机会被触发:

  • RecyclerView 首次附加到窗口时
  • Adapter 的数据集发生变化
  • RecyclerView 被 执行 RequetLayout的时候
  • LayoutManager 发生变化时

scrollHorizontallyBy/scrollVerticallyBy

方法的主要作用包括:

  1. 更新 ItemView 的位置:根据传入的垂直滚动距离(dy 参数),更新子视图在屏幕上的位置。通常调用 offsetChildrenVertical 方法。

  2. 回收不可见的 ItemView:在滚动过程中,一些 ItemView 可能会离开屏幕,变得不可见。scrollVerticallyBy 方法需要负责回收这些子视图并将它们放入回收池,以便稍后复用。

  3. 添加新的 ItemView:在滚动过程中,新的 ItemView 可能需要显示在屏幕上。scrollVerticallyBy 方法需要从回收池中获取可复用的视图并将它们添加到屏幕上。这通常涉及到调用 RecyclerView.RecyclergetViewForPosition 方法。

  4. 返回实际滚动距离:由于 ItemView 的数量有限,滚动可能会受到限制。例如,当滚动到列表顶部或底部时,滚动可能会停止。在这种情况下,实际滚动的距离可能会小于传入的 dy 参数。scrollVerticallyBy 方法需要返回实际滚动的距离,以便 RecyclerView 可以正确地更新滚动条和触发滚动事件。

概念就简单讲这么多, talk is cheap show me the code,直接看代码理解会比较深刻

逐步实现

要实现一个可用的 LayoutManger 通常我们需要实现以下流程

  • 数据填充并且只需要填充屏幕范围内的 ItemView
  • 回收掉屏幕以外的 ItemView
  • 屏幕外 ItemView 再回到屏幕后,需要重新填充
  • 对滑动边界边界进行处理
  • 对 scrollToPosition 和 smoothScrollToPosition进行支持

我们不用一上来就实现最终的效果,而是一步一步来,看看 LayoutManger 是怎么渐渐地变化,最终能跑起来的。

0 最简单的 LayoutManager

代码查看:MostSimpleLayoutManager,我们关注 onLayoutChildren 方法:

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State?) {
    // 垂直方向的偏移量
    var offsetTop = 0
    // 实际业务中最好不要这样一次性加载所有的数据,这里只是最简单地演示一下整体是如何工作的
    for (itemIndex in 0 until itemCount) {
        // 从适配器获取与给定位置关联的视图
        val itemView = recycler.getViewForPosition(itemIndex)
        // 将视图添加到 RecyclerView 中
        addView(itemView)
        // 测量并布局视图
        measureChildWithMargins(itemView, 0, 0)
        // 拿到宽高(包括ItemDecoration)
        val width = getDecoratedMeasuredWidth(itemView)
        val height = getDecoratedMeasuredHeight(itemView)
        // 对要添加的子 View 进行布局
        layoutDecorated(itemView, 0, offsetTop, width, offsetTop + height)
        offsetTop += height
    }
}

上面的代码主要演示了,如何利用addView layoutDecorated等方法,将 ItemView 添加到 RecyclerView 上。代码可见是 将所有的 ItemView(即使它在屏幕上不可见)一次性全部加载到了 RecyclerView上, 这里一般不这么做,只是这里这里只是最简单地演示一下整体是如何工作的。

运行在手机上能看到这样的效果:Item数据已经被全部添加到界面上了,并且各个方向的滑动都支持。

1 更合理的数据添加方式

代码查看:LinearLayoutManager1.kt

对最开始的代码进行优化,只在屏幕范围内的区域进行数据的添加,这样就不需要一次性将所有数据就添加上去,如果 Adapter 的 ItemCount 足够巨大,for all addView 的话,很容易就 OOM。

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
    // 垂直方向上的的空间大小
    var remainSpace = height - paddingTop
    //垂直方向的偏移量
    var offsetTop = 0
    var currentPosition = 0
    while (remainSpace > 0 && currentPosition < state.itemCount) {
        // 从适配器获取与给定位置关联的视图
        val itemView = recycler.getViewForPosition(currentPosition)
        // 将视图添加到 RecyclerView 中
        addView(itemView)
        // 测量并布局视图
        measureChildWithMargins(itemView, 0, 0)
        // 拿到宽高(包括ItemDecoration)
        val itemWidth = getDecoratedMeasuredWidth(itemView)
        val itemHeight = getDecoratedMeasuredHeight(itemView)
        // 对要添加的子 View 进行布局
        layoutDecorated(itemView, 0, offsetTop, itemWidth, offsetTop + itemHeight)
        offsetTop += itemHeight
        currentPosition++
        // 可用空间减少
        remainSpace -= itemHeight
    }
}

2 对屏幕外的View回收

代码查看:LinearLayoutManager2

RecylerView 没有 recycler 怎么行呢?当 RecylerView 的 ItemView 滑出屏幕后我们需要对齐进行回收,实现的话需要在 scrollVerticallyBy中,比较复杂的逻辑就是怎么去判断:ItemView 在屏幕以外,最后利用:removeAndRecycleView方法进行回收

override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {
      // 在这里处理上下的滚动逻辑,dy 表示滚动的距离
      // 平移所有子视图
      offsetChildrenVertical(-dy)
      // 如果实际滚动距离与 dy 相同,返回 dy;如果未滚动,返回 0
      recycleInvisibleView(dy, recycler)
      return dy
}

/**
 * 回收掉在界面上看不到的 ItemView
 *
 * @param dy
 * @param recycler
 */
private fun recycleInvisibleView(dy: Int, recycler: RecyclerView.Recycler) {
    val totalSpace = orientationHelper.totalSpace

    // 将要回收View的集合
    val recycleViews = hashSetOf<View>()
    // 从下往上滑
    if (dy > 0) {
        for (i in 0 until childCount) {
            val child = getChildAt(i)!!
            // 从下往上滑从最上面的 item 开始计算
            val top = getDecoratedTop(child)
            // 判断最顶部的 item 是否已经完全不可见,如何可见,那说明底下的 item 也是可见
            val height = top - getDecoratedBottom(child)
            if (height - top < 0) {
                break
            }
            recycleViews.add(child)
        }
    } else if (dy < 0) {   // 从上往下滑
        for (i in childCount - 1 downTo 0) {
            val child = getChildAt(i)!!
            // 从上往下滑从最底部的 item 开始计算
            val bottom = getDecoratedBottom(child)
            // 判断最底部的 item 是否已经完全不可见,如何可见,那说明上面的 item 也是可见
            val height = bottom - getDecoratedTop(child)
            if (bottom - totalSpace < height) {
                break
            }
            recycleViews.add(child)
        }
    }

    // 真正把 View 移除掉的逻辑
    for (view in recycleViews) {
        // [removeAndRecycleView]
        // 用于从视图层次结构中删除某个视图,并将其资源回收,以便在需要时重新利用
        removeAndRecycleView(view, recycler)
    }
    recycleViews.clear()
}

运行在手机上能看到这样的效果:滑出屏幕外的ItemView 被回收掉了

3 向上滑动的时View的填充

代码查看:LinearLayoutManager3

override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {
    // 填充 view
    fillView(dy, recycler)
    // 移动 view
    offsetChildrenVertical(-dy)
    // 回收 View
    recycleInvisibleView(dy, recycler)
    return dy
}

/**
 * 填充重新进入屏幕内的 ItemView
 *     getChildCount():childCount-> 当前屏幕内RecyclerView展示的 ItemView 数量
 *     getItemCount():itemCount-> 最大的 ItemView 数量,也就是 Adapter 传递的数据的数量
 */
private fun fillView(dy: Int, recycler: RecyclerView.Recycler) {
    val verticalSpace = orientationVerticalHelper.totalSpace
    var remainSpace = 0
    var nextFillPosition = 0
    //垂直方向的偏移量
    var offsetTop = 0
    var offsetLeft = 0
    // 从下往上滑,那么需要向底部添加数据
    if (dy > 0) {
        val anchorView = getChildAt(childCount - 1) ?: return
        val anchorPosition = getPosition(anchorView)
        val anchorBottom = getDecoratedBottom(anchorView)
        val anchorLeft = getDecoratedLeft(anchorView)
        remainSpace = verticalSpace - anchorBottom
        // 垂直可用的数据为<0,意外着这时候屏幕底部的位置刚好在最底部的 ItemView 上,还需要向上滑动一点点...我们才能添加 View
        if (remainSpace < 0) {
            return
        }
        nextFillPosition = anchorPosition + 1
        offsetTop = anchorBottom
        offsetLeft = anchorLeft
        if (nextFillPosition >= itemCount) {
            return
        }
    } else if (dy < 0) {  // 从上往下滑,那么需要向顶部添加数据
        //no-op 暂时不实现从上往下滑的底部数据填充
    }

    while (remainSpace > 0 && nextFillPosition < itemCount) {
        // 从适配器获取与给定位置关联的视图
        val itemView = recycler.getViewForPosition(nextFillPosition)
        // 将视图添加到 RecyclerView 中
        addView(itemView)
        // 测量并布局视图
        measureChildWithMargins(itemView, 0, 0)
        // 拿到宽高(包括ItemDecoration)
        val itemWidth = getDecoratedMeasuredWidth(itemView)
        val itemHeight = getDecoratedMeasuredHeight(itemView)
        // 对要添加的子 View 进行布局,相比onLayoutChildren 里面的实现添加了:offsetLeft(因为我们没有禁止掉 左右的滑动)
        // 试着把 offsetLeft 改成0,也就是最原始的样子,然后左右上下滑滑,你会有意外收获
        layoutDecorated(itemView, offsetLeft, offsetTop, itemWidth + offsetLeft, offsetTop + itemHeight)
        offsetTop += itemHeight
        nextFillPosition++
        // 可用空间减少
        remainSpace -= itemHeight
    }
}

运行在手机上能看到这样的效果:向上滑动的时候,底部陆续有元素填充,但向下滑动的时候没有填充数据

4 两个方向的View填充

代码查看:LinearLayoutManager4

补齐从上往下滑之后添加的逻辑

private fun fillView(dy: Int, recycler: RecyclerView.Recycler) {
    val verticalSpace = orientationVerticalHelper.totalSpace
    var remainSpace = 0
    var nextFillPosition = 0
    //垂直方向的偏移量
    var offsetTop = 0
    var offsetLeft = 0

    // 从下往上滑,那么需要向底部添加数据
    if (dy > 0) {
        ……
    } else if (dy < 0) {  // 从上往下滑,那么需要向顶部添加数据
        val anchorView = getChildAt(0) ?: return
        val anchorPosition = getPosition(anchorView)
        val anchorTop = getDecoratedTop(anchorView)
        offsetLeft = getDecoratedLeft(anchorView)
        remainSpace = anchorTop
        // 垂直可用的数据为<0,意外着这时候屏幕顶部的位置刚好在最底部的 ItemView 上,还需要向下滑动一点点...我们才能添加 View
        if (anchorTop < 0) {
            return
        }
        nextFillPosition = anchorPosition - 1
        if (nextFillPosition < 0) {
            return
        }
        val itemHeight = getDecoratedMeasuredHeight(anchorView)
        // 新的布局的itemView 的顶部位置应该以 anchorTop - itemHeight 开始
        offsetTop = anchorTop - itemHeight
    }

    while (remainSpace > 0 &&
        ((nextFillPosition < itemCount) && (nextFillPosition >= 0))
    ) {
        // 从适配器获取与给定位置关联的视图
        val itemView = recycler.getViewForPosition(nextFillPosition)
        // 将视图添加到 RecyclerView 中k,从顶部添加的话,需要加到最前的位置
        if (dy > 0) {
            addView(itemView)
        } else {
            addView(itemView, 0)
        }
        ……
        if (dy > 0) {
            offsetTop += itemHeight
            nextFillPosition++
        } else {
            offsetTop -= itemHeight
            nextFillPosition--
        }
        // 可用空间减少
        remainSpace -= itemHeight
    }

运行在手机上能看到这样的效果:向上或者滑动的时候,底部陆续都有元素填充

5 对顶部和底部滑动边界处理

代码查看:LinearLayoutManager5

对于前面的实现会发现会:不停地下滑或者上滑会留出来巨大的空白。这里对填充 View 的逻辑进行改造,需要进行边界检测。

override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {
    // 填充 view
    val adjustedDy = fillView(dy, recycler)
    // 移动 view
    offsetChildrenVertical(-adjustedDy)
    // 回收 View
    recycleInvisibleView(adjustedDy, recycler)
    // 由于需要对边界进行限制,所以需要对原始的 dy 进行修正,这里不再直接返回 dy
    return adjustedDy
}

这里的整体注释我写在了代码里面,可以看图稍微理解一下,以向上滑动为例:假设这一次滑动的距离非常非常大(想象成10000像素),如果直接滑动的话,我们有50个元素,每个元素高度100像素,最大高度也只有50x100=5000,那么滑动后一定会留下大量空区域。需要对当前传入的这 10000 像素做调整:只给到可滑动的最大距离,如果不能滑动了就返回0。

运行在手机上能看到这样的效果:向上或者滑动的时候,达到最大的位置时候是不能再滑动的。

6 实现 scrollToPosition

代码查看:LinearLayoutManager6

到这里这个 LinearLayoutManager 看着已经能正常运行了,但一般还需要支持scrollToPositionsmoothScrollToPositio

private var mPendingScrollPosition = RecyclerView.NO_POSITION

override fun scrollToPosition(position: Int) {
    super.scrollToPosition(position)
    if (position < 0 || position >= itemCount) {
        return
    }
    mPendingScrollPosition = position
    requestLayout()
}

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
    ……
    var currentPosition = 0
    if (mPendingScrollPosition != RecyclerView.NO_POSITION) {
        currentPosition = mPendingScrollPosition
    }

    while (remainSpace > 0 && currentPosition < state.itemCount) {
      …… // 填充View 的逻辑
    }
}

scrollToPosition 的实现比较简单,如上代码所示:在 scrollToPosition 的时候记录一次目标position,再 requestLayout 一波,还记得之前有提到过:onLayoutChildren 会在 requestLayout 的时候调用一次,于是再将onLayoutChildren逻辑改写,不再从第0个元素开始,而是从目标位置进行布局。

运行在手机上能看到这样的效果:点击 scrollTo30 将会滑动到 第30个位置。

7 实现 smoothScrollToPosition

代码查看:LinearLayoutManager7

要实现自定义的 smoothScrollToPosition 动画效果,这一块如果要完全自己实现的话比较复杂,可以直接使用系统提供的 LinearSmoothScroller改造,也可以继承 RecyclerView.SmoothScroller 自定义,也可以完全不使用 SmoothScroller, 照着 SmoothScroller 的实现使用类似 ValueAnimator 自定义动画,添加动画 UpdateListener,在 onAnimationUpdate 的时候动态计算布局从而实现滑动动画,这里拿 LinearSmoothScroller 举例:

override fun smoothScrollToPosition(
    recyclerView: RecyclerView,
    state: RecyclerView.State,
    position: Int
) {
    if (position >= itemCount || position < 0) {
        return
    }

    val scroller: LinearSmoothScroller = object : LinearSmoothScroller(recyclerView.context) {
        /**
         * 这个方法用于计算滚动到目标位置所需的滚动向量。滚动向量是一个二维向量,包含水平和垂直方向上的滚动距离
         *
         * @param targetPosition 滑动的目标位置
         * @return  返回一个 PointF 对象,表示滚动向量。
         *              PointF.x 表示水平方向上的滚动距离,
         *              PointF.y 表示垂直方向上的滚动距离
         */
        override fun computeScrollVectorForPosition(targetPosition: Int): PointF {
            // 查找到屏幕里显示的第 1 个元素与
            val firstChildPos = getPosition(getChildAt(0)!!)
            val direction = if (targetPosition < firstChildPos) -1 else 1
            // x 左右滑动,由于我们只实现了垂直的滑动,所以 x方向为0即可
            // 整数代表正向移动,负数代表反向移动,这里的数值大小不重要,源码里面最终都会 normalize 归一化处理
            return PointF(0f, direction.toFloat())
        }

        /**
         * 计算每像素速度
         *
         * @param displayMetrics
         * @return 返回每一像素的耗时,单位ms,假设返回值是1.0 代表着:1ms 内会滑动 1像素,1s会滑动1000像素
         */
        override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float {
            return super.calculateSpeedPerPixel(displayMetrics)
        }

        /**
         * 滑动速度的插值(实现滑动速度随着滑动时间的变化)
         *
         * @param dx
         * @return
         */
        override fun calculateTimeForDeceleration(dx: Int): Int {
            return super.calculateTimeForDeceleration(dx)
        }
        // 很多方法可以使用,不再一一列举
        // ...
    }
    scroller.targetPosition = position
    // 执行默认动画的逻辑
    startSmoothScroll(scroller)
}

运行在手机上能看到这样的效果:点击 smoothScrollTo30 将会有个动画效果滑动到第30个位置。

以上基本上一个自定义 LayoutManager 的雏形就已经完成了,虽然只实现了一个方向的滑动,但是其原理都是一样的,剩下的就是各种细节的打磨了,可以加各种自己想要的效果,比如:指定位置 放大一定的系数,或者更炫酷的滑动动画…

总结

本文主要整理了自定义 LayoutManager 的必要元素,以及其核心方法 scrollHorizontallyBy/scrollVerticallyBy、onLayoutChildren 的作用与调用时机,接下对实现一个简单的 LinearLayoutManger 进行逻辑拆解,从最简单的不滑动回收和填充以及不含滑动边界检测,到最终一个具备基本功能的 LinearLayoutManger

源码:https://github.com/VomPom/LayoutManagerGradually

参考:

《看完这篇文章你还不会自定义LayoutManager,我吃X!》

《/LayoutManager分析与实践》

Building a RecyclerView LayoutManager – Part 1

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[MySQL]索引

目录 概念解释 作用/优点 缺点 适用场景 索引的创建,删除与查看 系统对索引的自动创建 索引建立的时机 索引存储的数据结构 选择B树的原因 B树的原理 查询流程 优点 B树 与B树的区别 优点 概念解释 索引就像是一本字典的目录,我们可以根据目录快速定位到我们想…

Java架构师前沿技术

目录 1 导学2 信息物理系统2.1CPS的体系架构2.2 CPS的技术体系3 人工智能4 机器人5 边缘计算6 数字李生体7 云计算7.1 云计算的部署模式8 大数据想学习架构师构建流程请跳转:Java架构师系统架构设计 1 导学 2 信息物理系统 信息物理系统(CPS)是控制系统、嵌入式系统的扩展与…

一张图讲清楚业务稳定性要如何做:SRE体系化稳定性方案

概述&#xff1a;作为一个SRE、运维工程师&#xff0c;当我们在治理系统稳定性时&#xff0c;方法有很多&#xff0c;但往往无从下手。本文以一张逻辑图的形式&#xff0c;为读者提供治理稳定性的体系化思路。 先上图&#xff1a; 1、治理目标 我们做稳定性的目标&#xff0c…

MySQL 基础学习笔记(二)

目录 1 约束1.1 约束概述1.2 非空约束1.3 唯一约束1.4 主键约束1.5 默认约束1.6 外键约束 2 数据库设计2.1 数据库设计概述2.2 表关系 3 多表查询3.1 多表查询概述3.2 内连接查询3.3 外连接查询3.4 子查询 4 事务4.1 事务概述4.2 四大特征 1 约束 1.1 约束概述 约束是作用于表…

Whatsapp企业号如何增粉?5个措施帮到你

收集粉丝关注的方法有很多种&#xff0c;本文将会介绍九种有效的方式&#xff0c;可以参考。 在传播信息的过程中&#xff0c;我们要需要把客户放在第一位&#xff0c;你能提供给客户什么&#xff0c;实用价值或情绪价格。给人的感觉真实吗&#xff1f;足够透明吗&#xff1f;…

[黑马程序员Pandas教程]——Pandas快速体验

目录&#xff1a; 为什么要使用Python做数据开发Python在数据开发领域的优势为什么要学习Pandas其他常用Python库介绍主要内容介绍Anaconda安装Anaconda的虚拟环境管理虚拟环境的作用可以通过Anaconda界面创建虚拟环境通过命令行创建虚拟环境通过Anaconda管理界面安装包也可以…

Linux C语言进阶-D2字符数组和字符串

字符数组&#xff1a;元素的数据类型为字符类型的数组 char c[10],ch[3][4]; 字符数组的初始化 逐个字符赋值,无\0 在下图中&#xff0c;剩余的会自动添加上\0&#xff0c;而在int中会自动添加0&#xff0c;和NULL其实是一个意思 用字符串常量有\0 字符数组长度计算 下图中&am…

你知道什么是 Ping 吗?

欢迎到我的博客浏览 胤凯 (oyto.github.io) 这次我们来看一下什么是 Ping 操作&#xff0c;以及它有什么用处&#xff0c;并且我们来动手实现一个简易版的 Ping 工具。 Ping 是什么&#xff1f; ​ ping 是一个计算机网络工具&#xff0c;通常用于测试网络连接的可达性和测…

服务器带宽忽然暴增,不停的触发告警

问题&#xff1a; 线上环境&#xff0c;服务器的外网下行带宽达到某个阈值&#xff0c;触发告警&#xff0c;查了下服务器的带宽监控信息&#xff0c;是从某个时间开始突然串上去的&#xff0c;然后监控图形非常有规律&#xff0c;都是每秒达到顶峰后&#xff0c;又立马下去了…

信息系统项目管理师教程 第四版【第9章-项目范围管理-思维导图】

信息系统项目管理师教程 第四版【第9章-项目范围管理-思维导图】 课本里章节里所有蓝色字体的思维导图

2023年云栖大会来啦!!(2022年就已经深受震撼)

2023云栖大会已经开始啦&#xff0c;让我们来回顾回顾去年的云栖大会吧。 云栖大会是中国阿里巴巴集团每年举办的一项技术盛会&#xff0c;前身可追溯到2009年的地方网站峰会&#xff0c;2011年演变为阿里云开发者大会&#xff0c;2015年正式更名为“云栖大会”&#xff0c;并且…

DL Homework 5

目录 习题4-1 对于一个神经元​编辑&#xff0c;并使用梯度下降优化参数w时&#xff0c;如果输入x恒大于0&#xff0c;其收敛速度会比零均值化的输入更慢。 习题4-5 如果限制一个神经网络的总神经元数量(不考虑输入层)为N1&#xff0c;输入层大小为​编辑&#xff0c;输出层大…

回归预测 | Matlab实现RIME-CNN-SVM霜冰优化算法优化卷积神经网络-支持向量机的多变量回归预测

回归预测 | Matlab实现RIME-CNN-SVM霜冰优化算法优化卷积神经网络-支持向量机的多变量回归预测 目录 回归预测 | Matlab实现RIME-CNN-SVM霜冰优化算法优化卷积神经网络-支持向量机的多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.RIME-CNN-SVM霜冰优化算…

[SHCTF 2023 校外赛道] reverse

week1 ez_asm 想不到第1题是个汇编&#xff0c;咱也不知道拿啥能弄成c&#xff0c;不过这题也不难&#xff0c;直接能看懂&#xff0c;关键部分。 取出异或0x1e然后保存&#xff0c;再取出-0xa再保存。 .text:0000000000401566 loc_401566: …

赛宁网安多领域创新成果亮相第五届“纵横”论坛

10月27日&#xff0c;第五届“纵横”网络空间安全创新论坛在安徽合肥举办&#xff0c;来自中央国家机关、地方政府、军队有关单位、高校、科研院所和部分高新技术企业的领导、专家和代表500余人参加。 本届论坛由军事科学院和国防科技大学等单位共同主办&#xff0c;国防科技大…

电脑出现找不到d3dcompiler_43.dll的情况怎么办,分享d3dcompiler_43.dll丢失的办法

在使用电脑时你是不是也遇到过“未找到d3dcompiler_43.dll”的情况&#xff1f;是使用电脑的过程中d3dcompiler_43.dll丢失是一个经常出现问题&#xff0c;是一件大概率的事情&#xff0c;但是对于不了解这个文件的小伙伴而言出现这个问题是一件棘手的事情&#xff0c;那么今天…

postman做接口测试

之前搞自动化接口测试&#xff0c;由于接口的特性&#xff0c;要验证接口返回xml中的数据&#xff0c;所以没找到合适的轮子&#xff0c;就自己用requests造了个轮子&#xff0c;用着也还行&#xff0c;不过就是case管理有些麻烦&#xff0c;近几天又回头看了看postman也可以玩…

悠络客携新品UMind亮相安博会,从深耕商业连锁出发,正式进军ToG、ToC领域

2023年10月25日&#xff0c;第十九届中国国际社会公共安全博览会&#xff08;CPSE安博会&#xff09;在深圳会展中心隆重开幕。悠络客作为以公有云为核心的人工智能企业&#xff0c;联合海外事业部以全新面貌亮相展会现场。 本次参展&#xff0c;对悠络客而言有着非同寻常的重要…

【c++|opencv】二、灰度变换和空间滤波---4.高斯滤波

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 1. 高斯滤波 #include <iostream> #include <opencv2/opencv.hpp> #include"Salt.h"using namespace std; using namespace cv;/…

Android 13 Handler详解

1.Handler 简介 Handler 是一套 Android 消息传递机制。在多线程应用场景中&#xff0c;将子线程中需要更新 UI 的操作消息&#xff0c;传递到 UI 主线程&#xff0c;从而实现子线程通知 UI 更新最终实现异步消息处理。说白了是用于线程之间的通信。 Handler主要有4个重要类&a…