感谢之前的所有文章我们有一个简单的 Reddit 客户端,显示从 Reddit 获取的 Top 新闻.现在我们需要用户不只看到前10个新闻.我们将为这个 App 添加无限滑动加载更多数据.
全部章节:
Kotlin — Part 0:关于这个系列
Kotlin — Part 1:配置 Android Studio
Kotlin — Part 2:语法,空安全,静态类型
Kotlin — Part 3:扩展函数、Android 扩展、委托属性
Kotlin — Part 4:RecyclerView— Kotlin 适配器委托&数据类
Kotlin — Part 5:Kotlin,RxJava&RxAndroid
Kotlin — Part 6:API-Retrofit&Kotlin)
Kotlin — Part 7:无限滑动:高阶函数& Lambdas
Kotlin — Part 8:方向改变(序列化&数据类)
Kotlin — Part 9:单元测试与 Kotlin(Mockito,RxJava)
Github 仓库:https://github.com/imuhao/KedditBySteps
无限滑动的实现是受Mohamed Sobhy的启发,但是不幸的是它将不再可用.我做了几个改变提供高阶函数的例子,通过一个 lambda 表达式参数
高阶函数
一个高阶函数是一个函数接受一个函数作为参数或返回一个函数.
让我们查看Kotlin 如何运行一个函数接受一个函数作为参数或返回.
这个函数”logExecution“允许你将一个函数作为参数,然后再在这个函数的之前和之后执行这个函数.
1 | fun logExecution(func: () -> Unit) { |
func:()->Unit
你已经知道,” func“是这个参数的名字 “()->Unit“是它的类型,在这种情况func将是一个函数,它不接受任何参数,没有返回任值.
你可以通过 lambda 表达式调用这个函数,它必须没有接受和返回任何值.像下面的方法:
1 | logExecution( { Log.d("tag", "I'm a function") } ) |
但是 Kotlin 运行你在只有一个参数时删除括号或者如果最后这个参数是函数:
1 | logExecution { Log.d("tag", "I'm a function") } |
如果我们改变 logExecution 函数接受另一个参数,我们将函数参数放在最后,我们可以这样做
1 | // 添加一个 tag 参数 |
或者:
1 | logExecution("tag"){ |
你也可以使这个函数接受和返回一个值
1 | fun logExecution(func: (String, String) -> Int) { |
你可以看到 Kotlin 的高阶函数给你更大的功能.这将允许你在函数执行之前执行一些初始化,或关闭游标等操作.它可以做的更多.
Async 函数例子
让我们查看一个实用的例子.我们将创建一个新的函数,它将接受一个函数,执行它到其它线程.
1 | fun runAsync(func:()->Unit){ |
现在我们可以在主线程中执行这个函数:
1 | runAsync { |
在 Lollipop 例子
可能你需要运行一些代码在 Lollipop 设备,而不像做一些常规的检查,你可以使用这个函数:
1 | fun isLollipopOrAbove(func: () -> Unit) { |
使用这个方法:
1 | isLollipopOrAbove { |
无限滑动
现在让我们看看如何利用这一新概念,创建我们自己的无线滑动行为;
RecyclerView 允许你设置一个 ScrollListener, 所以我创建了InfiniteScrollListener.
1 | class InfiniteScrollListener(func: () -> Unit, |
在这里我们做的是接受一个函数作为参数,每当我们的 RecyclerView 滑动到底部时.事实上,它将在滑动到底部之前调用,你可以设置一个阈值,使我们的函数在底部 item 多少之前调用.这是一个很好的用户体验,避免用户查看到我们请求数据时所有的加载时间.
我们作为参数传递过来的函数用来加载更多的新闻和更新 NewsAdapter.
1 | news_list.addOnScrollListener( |
requestNews()是我们之前的代码,我更新它使用分页,请求下一个从 Reddit 获取的有效数据.
Commit
总结
我们现在已经可以滑动从 Reddit 加载更多数据,所有的这些实现你可以送前面的 commit 中查看.
高阶函数是一个不可思议的特征,希望通过这个例子你可以更加清晰.