SmartRefreshLayout使用记录

之前在简书上面的一篇文章,挪到CSDN上来。

前言

此开源控件高度省力、美观,理应不会有太多的问题。奈何该项目的主页上面的说明并不能满足我的需求,因此大致翻看了其中的源码,得到了满足自己需求的用法。因此特意地记录下来自己对其的理解,算是对此控件使用的一个小小笔记吧。

需求

所涉及的需求很简单,也是非常常见的一种用法。下拉刷新,刷新完毕之后关闭刷新动画

开始分析

为了达到这个小小的需求,首先翻看了其的说明文件。并没有与我的需求对应的说明,其上的说明也没有详细说明每个函数的更多用法,多的只是一笔带过的感觉。也许是作者相信我们的能力吧! 这一番得到的结果是:

  • autoRefresh()应该可以让刷新的动画显示;finishRefresh()应该可以让正在显示的刷新动画停止并消失;下拉刷新类似。
  • 可以通过SmartRefreshLayout.setDefaultRefreshFooterCreater()设置默认的刷新时的动画;下拉加载类似。除此之外,还可以通过其的setRefreshHeader()方法,来设置;下拉加载类似。
  • 可以通过setOnRefreshListener设置监听事件。这是说明中给的一段代码:
RefreshLayout refreshLayout = (RefreshLayout)findViewById(R.id.refreshLayout);
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
    @Override
    public void onRefresh(RefreshLayout refreshlayout) {
        refreshlayout.finishRefresh(2000);
    }
});
refreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
    @Override
    public void onLoadmore(RefreshLayout refreshlayout) {
        refreshlayout.finishLoadmore(2000);
    }
});

但是当时并没有仔细看这个,才导致了我后来使用时有点摸不着方向啊!其实在使用过程中对此也是有疑问的,这个监听事件到底是什么时候触发的?所以接下来的一段曲折的经历都是基于此上,谁让我没仔细看这个代码~ 其实我一直以为在onRefresh中调用的是finishRefresh()onLoadMore()中调用的是finishLoadmore(), 所以这根本就说不通啊,啥时候触发这监听事件的都不知道。

由一个小小的不仔细引发的旅程

虽然缘由是无厘头的,但是我喜欢接下来的这个过程。

首先,从autoRefresh()看起

这个函数的用法到底是怎么样的?它到底是用来干什么的? 为了回答自己心中的这个问题,只能习惯性地按着Ctrl点开这个函数。

开源库中的源码为:

/**
 * 自动刷新
 */
@Override
public boolean autoRefresh() {
    return autoRefresh(400);
}

这个400是什么,看了这个兄弟函数之后,发现是delay,也就是延迟。为啥要这个?很是疑惑,但是心中想到的也就是,在过完了400/1000秒之后,可能会显示刷新的动画吧。接着看,

/**
 * 自动刷新
 */
@Override
public boolean autoRefresh(int delayed) {
    return autoRefresh(delayed, 1f * (mHeaderHeight + mHeaderExtendHeight / 2) / mHeaderHeight);
}

大致的意思也就是,说句实话不太想知道这个到底是干啥的,感觉与我想知道的无关。接着看,

 * 自动刷新
 */
@Override
public boolean autoRefresh(int delayed, final float dragrate) {
    if (mState == RefreshState.None && mEnableRefresh) {
        if (reboundAnimator != null) {
            reboundAnimator.cancel();
        }
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reboundAnimator = ValueAnimator.ofInt(mSpinner, (int) (mHeaderHeight * dragrate));
                reboundAnimator.setDuration(mReboundDuration);
                reboundAnimator.setInterpolator(new DecelerateInterpolator());
                reboundAnimator.addUpdateListener(new AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        moveSpinner((int) animation.getAnimatedValue(), false);
                    }
                });
                reboundAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        mLastTouchX = getMeasuredWidth() / 2;
                        setStatePullDownToRefresh();
                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        reboundAnimator = null;
                        if (mState != RefreshState.ReleaseToRefresh) {
                            setStateReleaseToRefresh();
                        }
                        overSpinner();
                    }
                });
                reboundAnimator.start();
            }
        };
        if (delayed > 0) {
            reboundAnimator = new ValueAnimator();
            postDelayed(runnable, delayed);
        } else {
            runnable.run();
        }
        return true;
    } else {
        return false;
    }
}

中间一大堆是初始化了一个Runnable对象,关键的代码在下面:

if (delayed > 0) {
    reboundAnimator = new ValueAnimator();
    postDelayed(runnable, delayed);
} else {
    runnable.run();
}

如果delayed是小于等于0的数,就直接运行刚才初始化的Runnable对象的run()方法。否则又看到了delayed,很明显,小于等于0就会直接执行Runnable对象的run(),也就是会立刻显示刷新动画。**因此只需要调用autoRefresh(0)方法,便可立刻开启刷新动画。**抱着试试看的心态,好奇地点开了当delayed大于0时会执行的postDelayed()。源码如下:

@Override
public boolean postDelayed(Runnable action, long delayMillis) {
    if (handler == null) {
        mDelayedRunables = mDelayedRunables == null ? new ArrayList<DelayedRunable>() : mDelayedRunables;
        mDelayedRunables.add(new DelayedRunable(action, delayMillis));
        return false;
    }
    return handler.postDelayed(new DelayedRunable(action), delayMillis);
}

果然将Runnable对象交给了handler,然后是handler进行的一些延时执行的操作。 至此,autoRefresh()的用法便了然于心。

再者,finishRefresh()是到底干啥的?

它竟然和上者基本上是同样的套路! 了然!

那么,setOnRefreshListener到底是个什么??

在阅读该项目的WiKi时,看见过默认3秒的说法。可是,我了解到的是,持续3秒,没办法实现啊!我了解到的是,延迟3秒之后再进行某个操作啊!

突然,翻到了源码中的一段代码,一语惊醒梦中人:

if (mRefreshListener == null) {
    mRefreshListener = new OnRefreshListener() {
        @Override
        public void onRefresh(RefreshLayout refreshlayout) {
            refreshlayout.finishRefresh(3000);
        }
    };
}
if (mLoadmoreListener == null) {
    mLoadmoreListener = new OnLoadmoreListener() {
        @Override
        public void onLoadmore(RefreshLayout refreshlayout) {
            refreshlayout.finishLoadmore(2000);
        }
    };
}

如果监听事件为空,也就是我们没有设置默认的监听事件,那么它就会为我们创建一个监听事件,而且执行的是3000,这不就是3秒吗!所以啊,原来这个监听事件就是下拉的时候就会触发的啊。等等,

尴尬

这不是finishRefresh()吗?就是延迟3秒钟之后,关闭刷新动画的显示。那么,也就是说,autoRefresh()就只会(延迟)开启动画咯。我还特意去验证了,真是可爱?。 突然间看到了说明中的那段设置监听事件的代码,瞬间笑得哭了起来。

结论

所以,如果设置监听事件的话,并且它为空的话,那么就会一直显示刷新动画。因此,我只需要在开启刷新动画之后,在其中的监听事件的某个时间点关闭刷新动画即可! 坑了我的人就只有自己啊!为自己的一时sb买单。 附上成功地完成了需求之后的动图:

结果终究还算是好的

Read more

Volcano 与 Kubernetes GPU 调度学习笔记

本笔记系统整理 Volcano 调度器、Kubernetes 调度框架、GPU Device Plugin、HAMi 等云原生 AI 调度领域的核心知识,适合用于学习、复习和工程实践参考。 目录 * 第一部分:Volcano 入门 * 1. Volcano 是什么 * 2. 安装与快速使用 * 3. 核心特性一览 * 第二部分:Volcano 整体架构 * 4. Volcano 解决的核心问题 * 5. 整体架构与数据流 * 6. 三层抽象模型 * 第三部分:Volcano 核心实现原理 * 7. Session 机制 * 8. Gang Scheduling 实现 * 9. Queue 与 DRF 公平调度

容器镜像(4):镜像的常用工具箱

容器镜像(4):镜像的常用工具箱

前几篇在讲多架构镜像时已经用过 skopeo 和 crane 做镜像复制,这篇系统整理这两个工具的完整能力,同时介绍几个日常操作镜像时同样好用的工具。 一、skopeo:不依赖 Daemon 的镜像瑞士军刀 skopeo 的核心价值是绕过 Docker daemon,直接与 Registry API 交互。上一篇用它做镜像复制和离线传输,但它的能力远不止于此。 1.1 安装 # Ubuntu / Debian sudo apt install -y skopeo skopeo --version # skopeo version 1.15.1 1.2 inspect:免拉取检查镜像元数据 docker inspect 需要先把镜像拉到本地,skopeo inspect 直接向 Registry

容器镜像(3):多架构镜像构建

容器镜像(3):多架构镜像构建

一、什么是多架构镜像 1.1 OCI Image Index 上一篇介绍了单平台镜像的结构:一个 Manifest 指向 Config 和若干 Layer blob。多架构镜像在此之上多了一层——OCI Image Index(也叫 Manifest List),是一个轻量的索引文件,把多个单平台 Manifest 组织在一起: $ docker manifest inspect golang:1.22-alpine { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests&

容器镜像(2):containerd 视角下的镜像

容器镜像(2):containerd 视角下的镜像

一、为什么需要了解 containerd 如果你只用 docker run 跑容器,从来不关心底层,那可以不了解 containerd。但如果你在用 Kubernetes,或者想真正理解"容器运行时"是什么,containerd 是绕不开的。 事实上,当你执行 docker run 的时候,containerd 早就在后台悄悄工作了——Docker 从 1.11 版本开始,就把核心运行时剥离出来交给 containerd 负责。 1.1 Docker 的架构演变 早期的 Docker(1.10 及之前)是一个"大一统"的单体程序:一个 dockerd