本篇文章实现的功能就是在页面上分页加载双色球全部开奖数据,看着很简单,实现起来却很困难,是我低估了它的难度,还是我并不适合做程序员??不过经过多天的努力,最终还是实现了,在此记录一下。
知识来源主要有两个:
1,Jetpack新成员,Paging3从吐槽到真香
2, Github开源项目:NewzCompose
其中,
“1” => LotteryRepository(),LotteryViewModel(),LotteryPagingSource(),LotteryData()
"2" => LotteryActivity(),LotteryCompose()
主要引用到的资源,其中需要注意的是jsoup,使用代理的话会引入失败,需要开vpn或者通过jar包的方式引入
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha03' // viewModel()
implementation 'androidx.activity:activity-compose:1.3.0-alpha04' // setContent()
implementation "androidx.paging:paging-runtime:3.0.0-beta02"
implementation "androidx.paging:paging-compose:1.0.0-alpha08"
//jsoup
implementation 'org.jsoup:jsoup:1.13.1'
LotteryActivity()
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.lazy.LazyColumn
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemsIndexed
class LotteryActivity : ComponentActivity() {
private val lotteryViewModel: LotteryViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val lazyPagingItems: LazyPagingItems =
lotteryViewModel.getData().collectAsLazyPagingItems()
LazyColumn(reverseLayout=true) {
itemsIndexed(lazyPagingItems) { _, item ->
LotteryItem(item!!)
}
}
}
}
}
LotteryCompose()
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun LotteryItem(lottery: Lottery) {
Box(
modifier = Modifier
.padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
.clickable(onClick = {})
) {
Row(modifier = Modifier.fillMaxWidth()) {
Column(
modifier = Modifier.padding(start = 8.dp)
) {
Text(
lottery.code,//开奖号码
style = TextStyle(color = Color.Black, fontSize = 16.sp),
modifier = Modifier.padding(end = 8.dp),
maxLines = 1
)
}
Column(
modifier = Modifier.padding(start = 8.dp)
) {
Text(
lottery.issue,//期号
style = TextStyle(color = Color.Black, fontSize = 16.sp),
modifier = Modifier.padding(end = 8.dp),
maxLines = 1
)
}
}
}
}
LotteryData()
data class Lottery(
val code :String, //开奖号码
val issue :String,//期号
) : Serializable
LotteryViewModel()
class LotteryViewModel : ViewModel() {
fun getData(): Flow> {
return LotteryRepository.getPagingData().cachedIn(viewModelScope)
}
}
LotteryRepository()
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
object LotteryRepository {
private const val PAGE_SIZE = 50
fun getPagingData(): Flow> {
return Pager(
config = PagingConfig(
pageSize = PAGE_SIZE,
prefetchDistance = PAGE_SIZE.div(20)
),
pagingSourceFactory = { LotteryPagingSource() }
).flow
}
}
LotteryPagingSource()
import androidx.paging.PagingSource
import androidx.paging.PagingState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import love.matrix.lottory004.util.TimeUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
class LotteryPagingSource : PagingSource() {
private val year = TimeUtils.nowTime.substring(2, 4).toInt()//取年份最后两位 (2021 => 21)
private val lotterys = MutableStateFlow>(listOf())
override suspend fun load(params: LoadParams): LoadResult {
val page = params.key ?: year//一个年度的开奖数据为一页
val lotteryList: MutableList = mutableListOf()
withContext(Dispatchers.IO) {
val doc =
//"https://datachart.500.com/ssq/history/newinc/history.php?start=21001&end=21200"
Jsoup.connect(TARGET_URL + "?start=${page}001&end=${page}200").get()
val element: Element = doc.getElementById("tdata")
val elements: Elements = element.select("tr.t_tr1")
elements.forEach { item ->
val aaa: Elements = item.select("td")
if (!aaa.isNullOrEmpty()) {
val bbb = Lottery(
code = aaa[1].text() + "," +
aaa[2].text() + "," +
aaa[3].text() + "," +
aaa[4].text() + "," +
aaa[5].text() + "," +
aaa[6].text() + " " +
aaa[7].text(),
issue = aaa[0].text()
)
lotteryList.add(bbb)
}
}
lotterys.value = lotteryList
}
return try {
//使用了反转LazyColumn(reverseLayout=true),所以向上滑为nextKey
val prevKey = null
val nextKey = if (page > 3) page - 1 else null//"3"为2003年,双色球2003年开始的
LoadResult.Page(
data = lotterys.value,
prevKey = prevKey,
nextKey = nextKey,
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState): Int? {
TODO("Not yet implemented")
}
companion object {
const val TARGET_URL =
"https://datachart.500.com/ssq/history/newinc/history.php"
const val USER_AGENT =
"{Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Mobile Safari/537.36"
}
}
TimeUtils()
import android.util.Log
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
object TimeUtils {
val nowTime: String
get() {
val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINESE)
val date = Date(System.currentTimeMillis())
return simpleDateFormat.format(date)
}
}
完成后,感觉这些都是一些模版代码,没什么好说的,所以就不多说什么了。