怎么在Android中實現(xiàn)列表倒計時?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
10多年的河曲網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。成都全網(wǎng)營銷的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整河曲建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)公司從事“河曲網(wǎng)站設(shè)計”,“河曲網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。
CountDownTimer類用法
private CountDownTimer timer = new CountDownTimer(30000, 1000) {
//根據(jù)間隔時間來不斷回調(diào)此方法,這里是每隔1000ms調(diào)用一次
@Override
public void onTick(long millisUntilFinished) {
//todo millisUntilFinished為剩余時間,也就是30000 - n*1000
}
//結(jié)束倒計時調(diào)用
@Override
public void onFinish() {
//todo
}
};
//開始倒計時
timer.start();
//取消倒計時(譯者:取消后,再次啟動會重新開始倒計時)
timer.cancel();;代碼實現(xiàn)
先看核心,也就是CountDownAdapter類,這里就簡化UI,每個item只有一個textView來顯示倒計時,布局XML就不放了,直接放代碼
class CountDownAdapter(private var activity: ListActivity, private var data: ArrayList<Date>, private var systemDate: Date) : BaseAdapter() {
private val timeMap = HashMap<TextView, MyCountDownTimer>()
private val handler = Handler()
private val runnable = object : Runnable {
override fun run() {
if (systemDate != null) {
systemDate.time = systemDate.time + 1000
Log.i("xujf", "服務(wù)器時間線程===" + systemDate + "==for==" + this)
handler.postDelayed(this, 1000)
}
}
}
init {
handler.postDelayed(runnable, 1000)
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var v: View
var tag: ViewHolder
var vo = data[position]
if (null == convertView) {
v = activity.layoutInflater.inflate(R.layout.item_count_down, null)
tag = ViewHolder(v)
v.tag = tag
} else {
v = convertView
tag = v.tag as ViewHolder
}
//獲取控件對應(yīng)的倒計時控件是否存在, 存在就取消, 解決時間重疊問題
var tc: MyCountDownTimer? = timeMap[tag.tvTime]
if (tc != null) {
tc.cancel()
tc = null
}
//計算時間差
val time = getDistanceTimeLong(systemDate, vo)
//創(chuàng)建倒計時,與控件綁定
val cdu = MyCountDownTimer(position, time, 1000, tag.tvTime)
cdu.start()
//[醒目]此處需要map集合將控件和倒計時類關(guān)聯(lián)起來
timeMap.put(tag.tvTime, cdu)
return v
}
/**
* 退出時清空所有item的計時器
*/
fun cancelAllTimers() {
var s: Set<MutableMap.MutableEntry<TextView, MyCountDownTimer>>? = timeMap.entries
var it: Iterator<*>? = s!!.iterator()
while (it!!.hasNext()) {
try {
val pairs = it.next() as MutableMap.MutableEntry<*, *>
var cdt: MyCountDownTimer? = pairs.value as MyCountDownTimer
cdt!!.cancel()
cdt = null
} catch (e: Exception) {
}
}
it = null
s = null
timeMap.clear()
}
fun removeTimer(){
handler?.removeCallbacks(runnable)
}
fun reSetTimer(date: Date) {
removeTimer()
systemDate = date
handler.postDelayed(runnable, 1000)
}
override fun getItem(position: Int): Any = data[position]
override fun getItemId(position: Int): Long = 0L
override fun getCount(): Int = data.size
internal inner class ViewHolder(view: View) {
var tvTime = view.findViewById<TextView>(R.id.tv_time)
}
/**
* 倒計時類,每間隔countDownInterval時間調(diào)用一次onTick()
* index參數(shù)可去除,在這里只是為了打印log查看倒計時是否運行
*/
private inner class MyCountDownTimer(internal var index: Int, millisInFuture: Long,
internal var countDownInterval: Long, internal var tv: TextView
) : CountDownTimer(millisInFuture, countDownInterval) {
override fun onTick(millisUntilFinished: Long) {
//millisUntilFinished為剩余時間長
Log.i("xujf", "====倒計時還活著===第 $index 項item======")
//設(shè)置時間格式
val m = millisUntilFinished / countDownInterval
val hour = m / (60 * 60)
val minute = (m / 60) % 60
val s = m % 60
tv.text = "倒計時 (${hour}小時${minute}分${s}秒)"
}
override fun onFinish() {
tv.text = "倒計時結(jié)束"
//todo 可以做一些刷新動作
}
}
/**
* 時間工具,返回間隔時間長
*/
fun getDistanceTimeLong(one: Date, two: Date): Long {
var diff = 0L
try {
val time1 = one.time
val time2 = two.time
if (time1 < time2) {
diff = time2 - time1
} else {
diff = time1 - time2
}
} catch (e: Exception) {
e.printStackTrace()
}
return diff
}
}這里主要的創(chuàng)建一個線程來保持服務(wù)器時間和N個item倒計時的“走”動。
保持服務(wù)器時間沒什么好說的,就是Handler配合Runnable的循環(huán)調(diào)用,注意的是,當activity銷毀時,別忘了調(diào)用CountDownAdapter的removeTimer()方法來取消handler的回調(diào),防止內(nèi)存泄漏。
重點就是item里的倒計時的線程控制,這里參照網(wǎng)上的一個比較好的方法,就是用HashMap<TextView, MyCountDownTimer>()來讓MyCountDownTimer和item里的TextView關(guān)聯(lián)起來,也就是每個item對應(yīng)一個CountDownTimer,當關(guān)閉頁面時或者刷新list時,可利用cancelAllTimers()方法來清除所有關(guān)聯(lián),避免內(nèi)存泄漏。
以下是ListActivity,偽造一些時間數(shù)據(jù)
class ListActivity : AppCompatActivity() {
private val list: ArrayList<Date> = ArrayList()
private var countDownAdapter: CountDownAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
getDate()
setDate()
}
private fun setDate() {
if (countDownAdapter == null) {
countDownAdapter = CountDownAdapter(this, list, Date())
lv_count_down.adapter = countDownAdapter
lv_count_down.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, i, l ->
val intent = Intent(ListActivity@this, Main2Activity::class.java)
startActivity(intent)
}
} else {
//刷新數(shù)據(jù)時,重置本地服務(wù)器時間
countDownAdapter!!.reSetTimer(Date())
countDownAdapter!!.notifyDataSetChanged()
}
}
private fun getDate() {
for (i in 1..20) {
var date = Date(Date().time + i * 1000 * 60 * 30)
list.add(date)
}
}
override fun onDestroy() {
countDownAdapter?.cancelAllTimers()
countDownAdapter?.removeTimer()
super.onDestroy()
}
}這里在銷毀activity前,清除了服務(wù)器時間線程和所有item計時器,防止關(guān)閉頁面后線程失控而導致的內(nèi)存泄漏。但是并沒有在打開其他頁面時清除,因為如果清除了的話,那么從其他界面返回至此activity時,倒計時已停止。
當然如果你的需求允許返回界面時重新請求加載數(shù)據(jù)的,可以在onStop()中,只不過這樣體驗不好
countDownAdapter?.cancelAllTimers() countDownAdapter?.removeTimer()
運行效果
這里就看下我跑模擬機運行demo打印的Log:

嗯,本地的服務(wù)器時間每秒一次再跑著,沒毛病。
再來看看item里的倒計時Log:

看完上述內(nèi)容,你們掌握怎么在Android中實現(xiàn)列表倒計時的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
當前題目:怎么在Android中實現(xiàn)列表倒計時
URL地址:http://chinadenli.net/article38/goidpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、品牌網(wǎng)站設(shè)計、動態(tài)網(wǎng)站、做網(wǎng)站、網(wǎng)站制作、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)