Android 列表倒計時的實現的示例代碼(CountDownTimer)

分類:IT技術 時間:2017-09-27

實習一段時間了,一直想寫點技術總結,但一直沒找到合適的主題。剛好,最近版本中我負責的模塊遇到了個線程相關問題(之前一直畫界面,做點基礎功能,有點乏味),列表項倒計時的實現。

於是乎,我的第一篇android技術文章就誕生了。

【醒目】該demo用Kotlin語言實現。


背景介紹

需要在ListView的item裏實現倒計時,初看還挺簡單的,但是真正做的時候也遇到了不少坑。
網上有不少類似文章,有用對TextView擴展實現的,也有用自帶的CountDownTimer實現的,本文就是用CountDownTimer,只不過多了對服務器時間的刷新控制,更貼近項目需求吧。

剛學了點kotlin,就拿這個來練練手。所以這個demo的源碼就用koltin實現了,想了解學習kotlin的也可以來交流下,剛學,代碼裏可能有些細節語法用的不好。

要點分析:

    倒計時需要根據請求所得服務器時間和結束時間確定(所以要一個線程來維持服務器時間的運行,而且還有n個線程來維持item項的倒計時刷新顯示)。 既然是多線程,那麽線程的控制就要註意

了解CountDownTimer

在看代碼前,先來了解下android自帶的CountDownTimer類用法

  private CountDownTimer timer = new CountDownTimer(30000, 1000) { 
    //根據間隔時間來不斷回調此方法,這裏是每隔1000ms調用一次
    @Override 
    public void onTick(long millisUntilFinished) { 
      //todo millisUntilFinished為剩余時間,也就是30000 - n*1000
    } 
    
    //結束倒計時調用  
    @Override 
    public void onFinish() { 
      //todo
    } 
}; 

//開始倒計時
timer.start();

//取消倒計時(譯者:取消後,再次啟動會重新開始倒計時)
timer.cancel();;

這裏的入參再解釋下new CountDownTimer(30000, 1000)。

第一個參數30000代表倒計時的總時間,單位為ms,這裏是30000ms,也就是30s。第二個參數1000就是刷新間隔,也就是回調onTick方法的間隔,單位也是ms,這裏就是1s回調一次。

CountDownTimer相關參考文章:http://www.jb51.net/article/119729.htm

OK,基礎結束,接下來直接實現代碼了。

代碼實現

先看核心,也就是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", "服務器時間線程===" + systemDate + "==for==" + this)
        handler.postDelayed(this, 1000)
      }
    }
  }

  init {
    handler.postDelayed(runnable, 1000)
  }

  override fun getView(position: Int, convertView: View"xujf", "====倒計時還活著===第 $index 項item======")
      //設置時間格式
      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 = "倒計時結束"
      //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
  }
}

這裏主要的創建一個線程來保持服務器時間和N個item倒計時的“走”動。

保持服務器時間沒什麽好說的,就是Handler配合Runnable的循環調用,註意的是,當activity銷毀時,別忘了調用CountDownAdapter的removeTimer()方法來取消handler的回調,防止內存泄漏。

重點就是item裏的倒計時的線程控制,這裏參照網上的一個比較好的方法,就是用HashMap<TextView, MyCountDownTimer>()來讓MyCountDownTimer和item裏的TextView關聯起來,也就是每個item對應一個CountDownTimer,當關閉頁面時或者刷新list時,可利用cancelAllTimers()方法來清除所有關聯,避免內存泄漏。

以下是ListActivity,偽造一些時間數據

class ListActivity : AppCompatActivity() {

  private val list: ArrayList<Date> = ArrayList()
  private var countDownAdapter: CountDownAdapter"jb51code">
countDownAdapter"text-align: center">

嗯,本地的服務器時間每秒一次再跑著,沒毛病。

再來看看item裏的倒計時Log:


也沒毛病,只有顯示的那幾項再跑,沒出現失控線程。

關閉ListActivity頁面後所有線程全銷毀。點擊item後進入新界面,所有計時線程都在運行,然後返回ListActivity倒計時也是再跑的(模擬機跑demo的時候由於性能問題,長時間可能會出現倒計時不統一,用真機會好很多。)

OK,最後給出源碼地址:https://github.com/xjf1128/ListCountDownDemo

小結&感想

剛接到這個需求時,感覺肯定不少坑。最終做完再理一理思路,其實也還好。最初的思路正確的話,能少踩點坑。其實就是線程的控制和CountDownTimer的使用,難度也不大。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持電腦玩物。


Tags: CountDownTimer 倒計時 實現 線程 時間 一直

文章來源:


ads
ads

相關文章
ads

相關文章

ad