Day15 - Ptt换页及新增文章列表项目

今天的内容算是当初一时没考虑到的东西。

主要是Ptt一页的文章最多列出20篇,若要搜寻到20篇以前的文章就需要换页,幸运的是文章列表这边换页的指令蛮简单的。

Ptt文章列表的换页指令

https://ithelp.ithome.com.tw/upload/images/20210929/20124602b1MadN95Nr.png
可以看到在这边可以简单的用"P"和"N"换页。

Adapter

实作上首先在SearchArticleResultAdapter新增callback来通知更新

//...
var needMoreArticleCallback: (() -> Unit)? = null

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bindView(articleList[position])
    if (position == articleList.size - 1 && articleList[position].number != "1") {
        needMoreArticleCallback?.invoke()
    }
}
//...

如果目前列表的最後一项编号不是1的话代表还有旧的内容,此时呼叫通知更新的方法。

needMoreArticleCallback

//...
articleAdapter.needMoreArticleCallback = {
    if (PttClient.getInstance().expect(inBoardPattern) == 2) {
        (requireActivity() as MainActivity).showLoading("")
        viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
            val ret = withContext(Dispatchers.IO) {
                PttClient.getInstance().send("P")
                delay(200L)
                PttClient.getInstance().expect(inBoardPattern)
            }
            if (ret == 2) {
                parseBoardArticle(PttClient.getInstance().getScreen())
            }
            (requireActivity() as MainActivity).dismissLoading()
        }
    }
}
//...

首先先用inBoardPattern确认目前画面在看板内再送後续指令,如前面所述送出P後确认画面依旧在看板内就送入parseBoardArticle方法内了。

改写parseBoardArticle

为了保留现有内容并在後面新增文章,对此方法作了一点修改。

private val articleList = mutableListOf<Article>()

private fun parseBoardArticle(result: String) {
    val articlePattern =
        Pattern.compile("([●]|[ ])*(?<no>[0-9]+)[ ].([0-9 X]+|爆)(?<date>../..)[ ](?<author>.*?)([\\s□转]|R:)+(?<title>.*)")
    val rows = result.split("\n")
    val currentArticleList = mutableListOf<Article>()
    for (row in rows) {
        val matcher = articlePattern.matcher(row)
        if (matcher.find()) {
            val article = Article(
                matcher.group("no")?.trim(),
                matcher.group("date")?.trim(),
                matcher.group("author")?.trim(),
                matcher.group("title")?.trim()
            )
            if (!articleList.any { it.number == article.number }) {
                currentArticleList.add(0, article)
            }
            Log.d(mTag, "article=$article")
        }
    }

    articleList.addAll(currentArticleList)
    articleAdapter.setData(articleList)
}

首先将articleList提出成全域变数,在解析目前页面时另外宣告currentArticleList来储存,最後再加入到articleList中。过程中则是用any来找出目前解析出的文章编号是否已经被加入过了,这是因为若剩余未显示的文章篇数不到20篇的话,在切换页面後会用已显示过的文章来补足20篇的篇数,因此有重复的可能。

articleList除了这边使用到以外,再先前的搜寻操作前要注意先将内容清除掉,以避免重复。

private suspend fun searchDetailProcess(command: String): Boolean {
    articleList.clear()
    //...
}

private fun refreshSearch() {
    articleList.clear()
    //...
}

articleAdapter.setData

最後稍微看一下设置及更新资料的部分。

fun setData(newList: List<Article>) {
    val result = DiffUtil.calculateDiff(ArticleDiffUtilCallbackImpl(articleList, newList))
    articleList.clear()
    articleList.addAll(newList)
    result.dispatchUpdatesTo(this)
}

主要就是使用Android提供的DiffUtil来做更新,并实作DiffUtil.Callback

ArticleDiffUtilCallbackImpl

class ArticleDiffUtilCallbackImpl(
    private val oldList: List<Article>,
    private val newList: List<Article>
) : DiffUtil.Callback() {
    override fun getOldListSize(): Int = oldList.size

    override fun getNewListSize(): Int = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].number == newList[newItemPosition].number
    }
}

目前画面

https://i.imgur.com/6fLHCim.gif


<<:  D20 - 用 Swift 和公开资讯,打造投资理财的 Apps { 移动平均线(MA线)实作.3 }

>>:  Day 30 - Summary

[从0到1] C#小乳牛 练成基础程序逻辑 Day 8 - 变数 运算子 运算元

变数..装啊~再装啊~ | 一元 二元 ++ -- | 算术->数值 | 逻辑->T/...

过了一年,我更能享受其中了 谢谢你们

想想距离去年参加铁人也过了一年了,记得当时我才刚到职大概满半年吧,到现在也一年半了,我发生了哪些变化...

Day27影片教学:Azure小白如何使用Azure Kubernetes Service部署Container应用程序

在昨天我们谈完如何使用Azure Container Registry异地复写建立多份Contain...

多媒体电脑风潮从未结束

(因为题目在分类上是MobileDevelopment,所以就义务性的来讲APP开发吧!) (以下部...