怎么在Android中實(shí)現(xiàn)列表倒計(jì)時?相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
10多年的河曲網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(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è)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“河曲網(wǎng)站設(shè)計(jì)”,“河曲網(wǎng)站推廣”以來,每個客戶項(xiàng)目都認(rèn)真落實(shí)執(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é)束倒計(jì)時調(diào)用 @Override public void onFinish() { //todo } }; //開始倒計(jì)時 timer.start(); //取消倒計(jì)時(譯者:取消后,再次啟動會重新開始倒計(jì)時) timer.cancel();;
代碼實(shí)現(xiàn)
先看核心,也就是CountDownAdapter類,這里就簡化UI,每個item只有一個textView來顯示倒計(jì)時,布局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)的倒計(jì)時控件是否存在, 存在就取消, 解決時間重疊問題 var tc: MyCountDownTimer? = timeMap[tag.tvTime] if (tc != null) { tc.cancel() tc = null } //計(jì)算時間差 val time = getDistanceTimeLong(systemDate, vo) //創(chuàng)建倒計(jì)時,與控件綁定 val cdu = MyCountDownTimer(position, time, 1000, tag.tvTime) cdu.start() //[醒目]此處需要map集合將控件和倒計(jì)時類關(guān)聯(lián)起來 timeMap.put(tag.tvTime, cdu) return v } /** * 退出時清空所有item的計(jì)時器 */ 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) } /** * 倒計(jì)時類,每間隔countDownInterval時間調(diào)用一次onTick() * index參數(shù)可去除,在這里只是為了打印log查看倒計(jì)時是否運(yùn)行 */ 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", "====倒計(jì)時還活著===第 $index 項(xiàng)item======") //設(shè)置時間格式 val m = millisUntilFinished / countDownInterval val hour = m / (60 * 60) val minute = (m / 60) % 60 val s = m % 60 tv.text = "倒計(jì)時 (${hour}小時${minute}分${s}秒)" } override fun onFinish() { tv.text = "倒計(jì)時結(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倒計(jì)時的“走”動。
保持服務(wù)器時間沒什么好說的,就是Handler配合Runnable的循環(huán)調(diào)用,注意的是,當(dāng)activity銷毀時,別忘了調(diào)用CountDownAdapter的removeTimer()方法來取消handler的回調(diào),防止內(nèi)存泄漏。
重點(diǎn)就是item里的倒計(jì)時的線程控制,這里參照網(wǎng)上的一個比較好的方法,就是用HashMap<TextView, MyCountDownTimer>()來讓MyCountDownTimer和item里的TextView關(guān)聯(lián)起來,也就是每個item對應(yīng)一個CountDownTimer,當(dāng)關(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計(jì)時器,防止關(guān)閉頁面后線程失控而導(dǎo)致的內(nèi)存泄漏。但是并沒有在打開其他頁面時清除,因?yàn)槿绻宄说脑?,那么從其他界面返回至此activity時,倒計(jì)時已停止。
當(dāng)然如果你的需求允許返回界面時重新請求加載數(shù)據(jù)的,可以在onStop()中,只不過這樣體驗(yàn)不好
countDownAdapter?.cancelAllTimers() countDownAdapter?.removeTimer()
運(yùn)行效果
這里就看下我跑模擬機(jī)運(yùn)行demo打印的Log:
嗯,本地的服務(wù)器時間每秒一次再跑著,沒毛病。
再來看看item里的倒計(jì)時Log:
看完上述內(nèi)容,你們掌握怎么在Android中實(shí)現(xiàn)列表倒計(jì)時的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
當(dāng)前題目:怎么在Android中實(shí)現(xiàn)列表倒計(jì)時
URL地址:http://bm7419.com/article38/goidpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、品牌網(wǎng)站設(shè)計(jì)、動態(tài)網(wǎng)站、做網(wǎng)站、網(wǎng)站制作、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)