listview倒计时

  记录一个我花了较长时间解决的一个需求,在listview的每个item里加上倒计时,精确到秒,具体看图

listview倒计时_第1张图片

这只是有一个item的时候有倒计时,当这里有好几个倒计时,并且每个时间都不一样,很容易想到会出现的问题:

1.倒计时显示不准确

2.由于listview的getView方法里会复用convertView导致每次滑动listview时,数据混乱,尤其是,第二页的item会复用第一页的item的倒计时啊!!

我之前的解决方法是参考了网上找的demo,然而引起了第二个问题,一度我把这个需求给搁置了,后期才解决

下面附demo,是在网上找的demo的基础上,自己做了修改,成功解决了问题:

1.首先我们需要一个自定义的倒计时控件,完整demo如下:CustomDigitalClock.class

 
  
public class CustomDigitalClock extends DigitalClock {

   Calendar mCalendar;
   private final static String m12 = "h:mm aa";
   private final static String m24 = "k:mm";
   private FormatChangeObserver mFormatChangeObserver;

   private Runnable mTicker;
   private Handler mHandler;
   private long endTime;
   private ClockListener mClockListener;

   private boolean mTickerStopped = false;

   @SuppressWarnings("unused")
   private String mFormat;

   public CustomDigitalClock(Context context) {
      super(context);
      initClock(context);
   }

   public CustomDigitalClock(Context context, AttributeSet attrs) {
      super(context, attrs);
      initClock(context);
   }

   private void initClock(Context context) {

      if (mCalendar == null) {
         mCalendar = Calendar.getInstance();
      }

      mFormatChangeObserver = new FormatChangeObserver();
      if (getContext()!=null){
         getContext().getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);

         setFormat();
      }

   }

   @Override
   protected void onAttachedToWindow() {
      mTickerStopped = false;
      super.onAttachedToWindow();
      mHandler = new Handler();

      /**
       * requests a tick on the next hard-second boundary
       */
      mTicker = new Runnable() {
         public void run() {
            if (mTickerStopped)
               return;
            long currentTime = System.currentTimeMillis();
            if (currentTime / 1000 == endTime / 1000 - 5 * 60) {
               mClockListener.remainFiveMinutes();
            }
            long distanceTime = endTime - currentTime;
            distanceTime /= 1000;
            if (distanceTime == 0) {
               //setText("00:00:00");
               setText("00:00");//设置时间




               onDetachedFromWindow();
               mClockListener.timeEnd();
            } else if (distanceTime < 0) {
               setText("00:00");
            } else {
               setText(dealTime(distanceTime));
            }
            invalidate();
            long now = SystemClock.uptimeMillis();
            long next = now + (1000 - now % 1000);
            mHandler.postAtTime(mTicker, next);
         }
      };
      mTicker.run();
   }

   /**
    * @param time
    * @return
    */
   public static String dealTime(long time) {
      StringBuffer returnString = new StringBuffer();
      long day = time / (24 * 60 * 60);
      long hours = (time % (24 * 60 * 60)) / (60 * 60);
      long minutes = ((time % (24 * 60 * 60)) % (60 * 60)) / 60;
      long second = ((time % (24 * 60 * 60)) % (60 * 60)) % 60;
      //String dayStr = String.valueOf(day);
      //String hoursStr = timeStrFormat(String.valueOf(hours));
      String minutesStr = timeStrFormat(String.valueOf(minutes));
      String secondStr = timeStrFormat(String.valueOf(second));
      returnString.append(minutesStr).append(":").append(secondStr);

      return returnString.toString();//此处不需要天数倒计时和小时的倒计时,可根据需要添加
   }

   /**
    * format time
    * 
    * @param timeStr
    * @return
    */
   private static String timeStrFormat(String timeStr) {
      switch (timeStr.length()) {
      case 1:
         timeStr = "0" + timeStr;
         break;
      }
      return timeStr;
   }

   @Override
   protected void onDetachedFromWindow() {
      super.onDetachedFromWindow();
      mTickerStopped = true;
   }

   /**
    * Clock end time from now on.
    * 
    * @param endTime
    */
   public void setEndTime(long endTime) {
      this.endTime = endTime;
   }

   /**
    * Pulls 12/24 mode from system settings
    */
   private boolean get24HourMode() {
      return android.text.format.DateFormat.is24HourFormat(getContext());
   }

   private void setFormat() {
      if (get24HourMode()) {
         mFormat = m24;
      } else {
         mFormat = m12;
      }
   }

   private class FormatChangeObserver extends ContentObserver {
      public FormatChangeObserver() {
         super(new Handler());
      }

      @Override
      public void onChange(boolean selfChange) {
         setFormat();
      }
   }

   public void setClockListener(ClockListener clockListener) {
      this.mClockListener = clockListener;
   }

   public interface ClockListener{
      void timeEnd();
      void remainFiveMinutes();
   }

}
2.在布局文件里引用这个自定义view
 
  

3.在adapter的getView方法里给这个控件,设置值
 
  
//产生一个当前的毫秒,这个毫秒其实就是自1970年1月1日0时起的毫秒数
        long curTime = System.currentTimeMillis();

        //获取系统当前时间,精确到秒
        String systemhms = DateFormatUtils.getSystemhms();

        //得到剩余时间和系统当前时间的剩余时间,精确到秒
        List list = DateFormatUtils.calculateTime(systemhms, listEntity.getExpireTime());
        Long hour=new Long(list.get(0));
        Long min=new Long(list.get(1));
        Long s=new Long(list.get(2));
        Long totalLong=hour*3600*1000+min*60*1000+s*1000;//有4秒的误差,在这里暂且加上4000

        holder.tv_timer_o.setEndTime(curTime +totalLong);

        holder.tv_timer_o.setClockListener(new CustomDigitalClock.ClockListener() { // register the clock's listener

            @Override
            public void timeEnd() {
                // The clock time is ended.
            }

            @Override
            public void remainFiveMinutes() {
                // The clock time is remain five minutes.
            }
        });

其中 listEntity.getExpireTime()是由json解析得到的字段,本身是一个“2016-03-17 10:57:12”的格式,代表到
“2016-03-17 10:57:12”时结束倒计时,下面附上日期util的calculateTime()方法,该方法是用来计算时差的:
public static List  calculateTime(String firstTime,String secondTime){
        SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long between = 0;
        try {
            /*java.util.Date begin = dfs.parse("2009-07-10 10:22:21.214");
            java.util.Date end = dfs.parse("2009-07-20 11:24:49.145");*/
            Date begin=dfs.parse(firstTime);
            Date end= dfs.parse(secondTime);

            between = (end.getTime() - begin.getTime());// 得到两者的毫秒数
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        long day = between / (24 * 60 * 60 * 1000);
        long hour = (between / (60 * 60 * 1000) - day * 24);
        long min = ((between / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (between / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        long ms = (between - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000
                - min * 60 * 1000 - s * 1000);//毫秒
        /*System.out.println(day + "天" + hour + "小时" + min + "分" + s + "秒"
                + "毫秒");*/
        List list=new ArrayList<>();
        list.add(hour);
        list.add(min);
        list.add(s);
        return list;
        //return hour + ":" + min + ":" + s ;
    }

以上,解决了listview的倒计时的准确性以及滑动时数据混乱。


你可能感兴趣的:(倒计时,自定义View,listview,DigitalClock)