class MyAdapter(private val data: List<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private val progressMap = mutableMapOf<Int, Int>() // 保存每个 item 的加载进度
private var textData: String = ""
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val startIndex = progressMap[position] ?: 0 // 获取上次停止的位置
holder.bind(data[position], startIndex)
}
override fun getItemCount(): Int = data.size
fun updateData(newData: String) {
textData = newData
notifyDataSetChanged() // 通知数据更新
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.textView)
private val handler: Handler = Handler(Looper.getMainLooper())
private var currentIndex: Int = 0
private var accumulatedData: String = ""
private var updateRunnable: Runnable? = null
private var isUpdating: Boolean = false
fun bind(data: String, startIndex: Int) {
accumulatedData = data
currentIndex = startIndex
textView.text = "" // 清空之前的数据
if (!isUpdating) {
startTimer()
}
}
private fun startTimer() {
isUpdating = true
updateRunnable = object : Runnable {
override fun run() {
if (currentIndex < accumulatedData.length) {
val endIndex = (currentIndex + 2).coerceAtMost(accumulatedData.length)
val textToUpdate = accumulatedData.substring(currentIndex, endIndex)
handler.post {
textView.append(textToUpdate)
}
currentIndex += 2
handler.postDelayed(this, 250) // 每250ms更新2个字符
} else {
isUpdating = false
}
}
}
handler.post(updateRunnable!!)
}
override fun onViewRecycled() {
super.onViewRecycled()
handler.removeCallbacks(updateRunnable!!)
// 保存当前的加载进度
(itemView.context as MainActivity).progressMap[adapterPosition] = currentIndex
isUpdating = false
}
}
}
class MainActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: MyAdapter
private lateinit var handler: Handler
private var currentIndex = 0
private var accumulatedData = "This is a long string that will be updated gradually over time."
private val delay = 250L // 定时器更新的时间间隔
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
val data = List(10) { "Item ${it + 1}" } // 示例数据
adapter = MyAdapter(data)
recyclerView.adapter = adapter
handler = Handler(Looper.getMainLooper())
startTimer() // 启动定时器
}
private fun startTimer() {
// 定时器定时更新每 250 毫秒更新 2 个字符
handler.postDelayed(object : Runnable {
override fun run() {
if (currentIndex < accumulatedData.length) {
val endIndex = (currentIndex + 2).coerceAtMost(accumulatedData.length)
val textToUpdate = accumulatedData.substring(currentIndex, endIndex)
// 通知 Adapter 更新指定的 item
adapter.updateData(currentIndex, textToUpdate)
currentIndex += 2
handler.postDelayed(this, delay)
}
}
}, delay)
}
}
class MyAdapter(private val data: List<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private val updatedData = mutableListOf<String>().apply {
addAll(data) // 初始化数据列表
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = updatedData[position]
holder.bind(item)
}
override fun getItemCount(): Int = updatedData.size
fun updateData(index: Int, text: String) {
// 更新指定位置的文本,并通知更新
updatedData[index] += text
notifyItemChanged(index) // 更新指定的 item
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.textView)
fun bind(data: String) {
textView.text = data
}
}
}
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_view" />
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textSize="16sp"
android:layout_margin="16dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>