android特卖列表倒计时卡顿问题的解决方法

在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成。当然也可以使用Android系统控件CountDownTimer,这里我们封装成一个控件,也方便大家的使用。

首先上一张效果图吧:

说一下造成卡顿的原因,由于滑动的时候,adapter的getView频繁的创建和销毁,就会出现卡顿和数据错位问题,那么我们每一个item的倒计时就需要单独维护,这里我用的Handler与timer及TimerTask结合的方法,我们知道TimerTask运行在自己子线程,然后通过Timer的schedule()方法实现倒计时功能,最后通过Hander实现View的刷新,其核心代码如下:

public class CountDownView extends LinearLayout {

 @BindView(R.id.tv_day)
 TextView tvDay;
 @BindView(R.id.tv_hour)
 TextView tvHour;
 @BindView(R.id.tv_minute)
 TextView tvMinute;
 @BindView(R.id.tv_second)
 TextView tvSecond;

 @BindView(R.id.day)
 TextView day;
 @BindView(R.id.hour)
 TextView hour;
 @BindView(R.id.minute)
 TextView minute;

 private Context context;

 private int viewBg;//倒计时的背景
 private int cellBg;//每个倒计时的背景
 private int cellTextColor;//文字颜色
 private int textColor;//外部:等颜色
 private int textSize = 14;//外部文字大小
 private int cellTextSize = 12;//cell文字大小

 private TimerTask timerTask = null;
 private Timer timer = new Timer();
 private Handler handler = new Handler() {

  public void handleMessage(Message msg) {
   countDown();
  }
 };

 public CountDownView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
  this.context = context;
 }

 public CountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  this.context = context;
  initAttrs(attrs, defStyleAttr);
  initView(context);
 }

 private void initAttrs(AttributeSet attrs, int defStyle) {
  TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CountDownView, defStyle,0);
  viewBg = typedArray.getColor(R.styleable.CountDownView_viewBg, Color.parseColor("#FFFFFF"));
  cellBg = typedArray.getColor(R.styleable.CountDownView_cellBg, Color.parseColor("#F4F4F4"));
  cellTextColor = typedArray.getColor(R.styleable.CountDownView_cellTextColor, Color.parseColor("#646464"));
  textColor = typedArray.getColor(R.styleable.CountDownView_TextColor, Color.parseColor("#B3B3B3"));
  textSize = (int) typedArray.getDimension(R.styleable.CountDownView_TextSize, UIUtils.dp2px(getContext(), 14));
  cellTextSize = (int) typedArray.getDimension(R.styleable.CountDownView_cellTextSize, UIUtils.dp2px(getContext(), 12));
  typedArray.recycle();

 }

 private void initView(Context context) {
  LayoutInflater inflater = (LayoutInflater) context
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  View view = inflater.inflate(R.layout.layout_countdown_layout, this);
  ButterKnife.bind(view);

  initProperty();
 }

 private void initProperty() {
  tvDay.setBackgroundColor(cellBg);
  tvHour.setBackgroundColor(cellBg);
  tvMinute.setBackgroundColor(cellBg);
  tvSecond.setBackgroundColor(cellBg);

  tvDay.setTextColor(cellTextColor);
  tvHour.setTextColor(cellTextColor);
  tvMinute.setTextColor(cellTextColor);
  tvSecond.setTextColor(cellTextColor);

  day.setTextColor(textColor);
  hour.setTextColor(textColor);
  minute.setTextColor(textColor);
 }

 public void setLeftTime(long leftTime) {
  if (leftTime <= 0) return;
  long time = leftTime / 1000;
  long day = time / (3600 * 24);
  long hours = (time - day * 3600 * 24) / 3600;
  long minutes = (time - day * 3600 * 24 - hours * 3600) / 60;
  long seconds = time - day * 3600 * 24 - hours * 3600 - minutes * 60;

  setTextTime(time);
 }

 public void start() {
  if (timerTask == null) {
   timerTask = new TimerTask() {
    @Override
    public void run() {
     handler.sendEmptyMessage(0);
    }

   };
   timer.schedule(timerTask, 1000, 1000);
//   timer.schedule(new TimerTask() {
//    @Override
//    public void run() {
//     handler.sendEmptyMessage(0);
//    }
//   }, 0, 1000);
  }
 }

 public void stop() {
  if (timer != null) {
   timer.cancel();
   timer = null;
  }
 }

 //保证天,时,分,秒都两位显示,不足的补0
 private void setTextTime(long time) {
  String[] s = TimeUtils.formatTimer(time);
  tvDay.setText(s[0]);
  tvHour.setText(s[1]);
  tvMinute.setText(s[2]);
  tvSecond.setText(s[3]);
 }

 private void countDown() {
  if (isCarry4Unit(tvSecond)) {
   if (isCarry4Unit(tvMinute)) {
    if (isCarry4Unit(tvHour)) {
     if (isCarry4Unit(tvDay)) {
      stop();
     }
    }
   }
  }
 }

 private boolean isCarry4Unit(TextView tv) {
  int time = Integer.valueOf(tv.getText().toString());
  time = time - 1;
  if (time < 0) {
   time = 59;
   tv.setText(time + "");
   return true;
  } else if (time < 10) {
   tv.setText("0" + time);
   return false;
  } else {
   tv.setText(time + "");
   return false;
  }
 }
}

另一种写法:

public class CountDownTimerView extends LinearLayout {

 private TextView hourView, minuteView, secondView;
 private LimitTimer mTimer;
 private Handler handler;
 public static final int START_LIMIT_TIME_MSG = 0x0111;
 public static final int END_LIMIT_TIME_MSG = 0x0112;
 private long endTime, leftTime;
 private LimitTimeListener listener=null;

 public CountDownTimerView(Context context) {
  super(context);
  initView(context);
 }

 public CountDownTimerView(Context context, AttributeSet attrs) {
  super(context, attrs);
  initView(context);
 }

 private void initView(Context context) {
  setOrientation(HORIZONTAL);
  setGravity(Gravity.CENTER_VERTICAL);
  inflate(context, R.layout.layout_countdown_layout, this);
  hourView = (TextView) findViewById(R.id.tv_hour);
  minuteView = (TextView) findViewById(R.id.tv_minute);
  secondView = (TextView) findViewById(R.id.tv_second);
 }

 public long getLeftTime() {
  return leftTime;
 }

 //设置剩余时间
 public void initLeftTime(long endTime) {
  endTime=endTime*1000;
  if (null != mTimer) {
   mTimer.cancel();
   mTimer = null;
  }
  this.endTime = endTime;
  mTimer = new LimitTimer(endTime, 1000);
  mTimer.start();
  if (handler != null) {
   handler.sendEmptyMessage(START_LIMIT_TIME_MSG);
  }
 }

 /**
  * 如果该控件使用在碎片中,返回时,则最好还是要stop
  */
 public void stopTimeCount() {
  if (null != mTimer) {
   mTimer.cancel();
   mTimer = null;
  }
 }

 public Handler getHandler() {
  return handler;
 }

 public void setHandler(Handler handler) {
  this.handler = handler;
 }

 private class LimitTimer extends CountDownTimer {

  public LimitTimer(long millisInFuture, long countDownInterval) {
   super(0 != leftTime ? leftTime : endTime, countDownInterval);
  }

  @Override
  public void onTick(long millisUntilFinished) {
   leftTime = millisUntilFinished;
   long totalSecond = millisUntilFinished / 1000;
   int second = (int) (totalSecond % 60);
   int minute = (int) ((totalSecond / 60) % 60);
   int hour = (int) ((totalSecond / 3600) % 24);
   int day = (int) (totalSecond / (3600 * 24));

   formatView(hourView, hour);
   formatView(minuteView, minute);
   formatView(secondView, second);
  }

  @Override
  public void onFinish() {
   String zero = "00";
   hourView.setText(zero);
   minuteView.setText(zero);
   secondView.setText(zero);
   if (null != handler) {
    handler.sendEmptyMessage(END_LIMIT_TIME_MSG);
   }
   if (listener!=null){
    listener.onTimeOver(true);
   }
  }

  private void formatView(TextView view, int time) {
   DecimalFormat df = new DecimalFormat("#00");
   view.setText(df.format(time));
  }
 }

 //倒计时结束监听
 public void setOnLimitTimeListener(LimitTimeListener listener) {
  this.listener = listener;
 }
 public interface LimitTimeListener {
  void onTimeOver(boolean flag);
 }

 @Override
 protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
  if (handler != null) {
   handler.removeMessages(START_LIMIT_TIME_MSG);
  }
 }
}

涉及到的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal">

 <TextView
  android:id="@+id/tv_hour"
  style="@style/style_countdown" />

 <TextView
  style="@style/style_wrap_content"
  android:layout_marginLeft="3dp"
  android:layout_marginRight="3dp"
  android:layout_gravity="center_vertical"
  android:text="时"
  android:textColor="@color/color_646464" />

 <TextView
  android:id="@+id/tv_minute"
  style="@style/style_countdown" />

 <TextView
  style="@style/style_wrap_content"
  android:layout_marginLeft="3dp"
  android:layout_marginRight="3dp"
  android:layout_gravity="center_vertical"
  android:text="分"
  android:textColor="@color/color_646464" />

 <TextView
  android:id="@+id/tv_second"
  style="@style/style_countdown" />

 <TextView
  style="@style/style_wrap_content"
  android:layout_marginLeft="3dp"
  android:layout_marginRight="3dp"
  android:layout_gravity="center_vertical"
  android:text="秒"
  android:textColor="@color/color_646464" />
</LinearLayout>

附上源码地址:点击打开链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android如何利用RecyclerView实现列表倒计时效果实例代码

    前言 最近面试时,面试官问了一个列表倒计时效果如何实现,然后脑袋突然懵的了O(∩_∩)O,现在记录一下. 运行效果图 实现思路 实现方法主要有两个: 1.为每个开始倒计时的item启动一个定时器,再做更新item处理: 2.只启动一个定时器,然后遍历数据,再做再做更新item处理. 经过思考,包括性能.实现等方面,决定使用第2种方式实现. 实现过程 数据实体 /** * 总共的倒计时的时间(结束时间-开始时间),单位:毫秒 * 例: 2019-02-23 11:00:30 与 2019-02-2

  • Android RecyclerView实现拼团倒计时列表实例代码

    前言 最近一直被需求赶着走,有些功能经过测试上线后就没再review.闲下来还是重新优化下老代码,温故而知新,还是有点收获和进步的 需求TODO 团购这种促销方式已经很普遍,尤其是大家熟悉的"并夕夕"更是玩的很6.现在我们就要实现一个团购倒计时列表,并以"剩余:09:12:24.8"这种样式来展示该团距离结束时间的倒计时. 技术初步分析 首先,有关时间变化的,首先想到TimerTask+Timer这个定时器组合,列表不用多说RecyclerView.其中涉及到UI更

  • Android利用RecyclerView实现列表倒计时效果

    最近面试时,面试官问了一个列表倒计时效果如何实现,现在记录一下. 运行效果图 实现思路 实现方法主要有两个: 1.为每个开始倒计时的item启动一个定时器,再做更新item处理: 2.只启动一个定时器,然后遍历数据,再做再做更新item处理. 经过思考,包括性能.实现等方面,决定使用第2种方式实现. 实现过程 数据实体 /** * 总共的倒计时的时间(结束时间-开始时间),单位:毫秒 * 例: 2019-02-23 11:00:30 与 2019-02-23 11:00:00 之间的相差的毫秒数

  • Android 列表倒计时的实现的示例代码(CountDownTimer)

    实习一段时间了,一直想写点技术总结,但一直没找到合适的主题.刚好,最近版本中我负责的模块遇到了个线程相关问题(之前一直画界面,做点基础功能,有点乏味),列表项倒计时的实现. 于是乎,我的第一篇android技术文章就诞生了. [醒目]该demo用Kotlin语言实现. 背景介绍 需要在ListView的item里实现倒计时,初看还挺简单的,但是真正做的时候也遇到了不少坑. 网上有不少类似文章,有用对TextView扩展实现的,也有用自带的CountDownTimer实现的,本文就是用CountD

  • Android ListView列表实现倒计时

    本文实例为大家分享了Android ListView列表实现倒计时的具体代码,供大家参考,具体内容如下 效果图: 1. Activity package com.s296267833.ybs.activity.firstPage.timedown; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ListView; import com.s296267

  • android特卖列表倒计时卡顿问题的解决方法

    在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成.当然也可以使用Android系统控件CountDownTimer,这里我们封装成一个控件,也方便大家的使用. 首先上一张效果图吧: 说一下造成卡顿的原因,由于滑动的时候,adapter的getView频繁的创建和销毁,就会出现卡顿和数据错位问题,那么我们每一个item的倒计时就需要单独维护,这里我用的Handler与timer及TimerTask结合的方法,我们知道TimerTask运行在自己子

  • Android ListView与getView调用卡顿问题解决办法

    Android ListView与getView调用卡顿问题解决办法 解决办法1,设置ListView高度为固定值或者match_parent/ifll_parent @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.d("onMeasure", "onMeasure"); isOnMeasure = true; super.onMeasure(

  • Unity中Instantiate实例化物体卡顿问题的解决

    本文实例为大家分享了Unity中Instantiate实例化物体卡顿问题的解决方法,供大家参考,具体内容如下 一.前言 当在执行多次Instantiate实例化物体时,会卡顿严重甚至在移动端会导致程序崩溃 因为Instantiate会产生大量的GC,使CPU过高,导致崩溃 下面是一段测试代码:当我们按下按键时实例化100000个预制体 using UnityEngine; public class Test : MonoBehaviour { public GameObject prefab;

  • iOS App使用GCD导致的卡顿现象及解决方法

    最近在调研 iOS app 中存在的各种卡顿现象以及解决方法. iOS App 出现卡顿(stall)的概率可能超出大部分人的想象,尤其是对于大公司旗舰型 App.一方面是由于业务功能不停累积,各个产品团队之间缺乏协调,大家都忙着增加功能,系统资源出现瓶颈.另一方面的原因是老设备更新换代太慢,iOS 设备的耐用度极好,现在还有不少 iPhone 4S 在服役,iPhone 6 作为问题设备持有量很高,据估计,现在 iPhone 6s 以前的设备占有比高达 40%. 所以,如果尝试在线上 App

  • Android程序启动时出现黑屏问题的解决方法

    本文实例讲述了Android程序启动时出现黑屏问题的解决方法.分享给大家供大家参考,具体如下: 关于黑屏: 默认的情况下,程序启动时,会有一个黑屏的时期,原因是,首个activity会加载一些数据,比如初始化列表数据.向服务器发送请求获取数据等等. 去除方法: 1.在style里面添加一个style: <style name="ContentOverlay"parent="@android:style/Theme.Light"> <itemname

  • android studio更新gradle错误构建项目失败的解决方法

    一.版本错误 对应版本,修改gradle version,和plusing version两个地方修改gradle version,和plusing version的方法有两种,一种是在 project.build.这里plusing version的设置 buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.0' } } allprojects

  • Android Force Close 出现的异常原因分析及解决方法

    一.原因: forceclose,意为强行关闭,当前应用程序发生了冲突. NullPointExection(空指针),IndexOutOfBoundsException(下标越界),就连Android API使用的顺序错误也可能导致(比如setContentView()之前进行了findViewById()操作)等等一系列未捕获异常 二.如何避免 如何避免弹出Force Close窗口 ,可以实现Thread.UncaughtExceptionHandler接口的uncaughtExcepti

  • php倒计时出现-0情况的解决方法

    本文实例讲述了php倒计时出现-0情况的解决方法.分享给大家供大家参考,具体如下: 问题:今天有反馈,说倒计时出现了-0天的情况,我看了看程序,卧槽,当时怎么没测试到 原因是PHP的逻辑判断中 -0 > 0 分析:贴出错的代码 $starttime = 1362585600; //3.7凌晨 $nowtime = 1362618921;//3.7早上 $off = ceil(($starttime - $nowtime)/86400); //倒计时 if ($off < 0) { $off =

  • Android实现QQ新用户注册界面遇到问题及解决方法

    在上篇文章给大家介绍了Android实现QQ登录界面遇到问题及解决方法,本篇文章继续给大家介绍有关android qq界面知识. 先给大家展示下效果图: 问题: 1.下拉列表(因为还没看到这里...) 2.标题栏显示问题 3.按钮的 Enable 设置 以下是代码: 布局 fragment_main(问题1) <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools

  • Android 5.1 WebView内存泄漏问题及快速解决方法

    问题背景 在排查项目内存泄漏过程中发现了一些由WebView引起的内存泄漏,经过测试发现该部分泄漏只会出现在android 5.1及以上的机型.虽然项目使用WebView的场景并不多,但秉承着一个泄漏都不放过的精神,我们肯定要把它给解决了. 遇到的问题 项目中使用WebView的页面主要在FAQ页面,问题也出现在多次进入退出时,发现内存占用大,GC频繁.使用LeakCanary观察发现有两个内存泄漏很频繁: 我们分析一下这两个泄漏: 从图一我们可以发现是WebView的ContentViewCo

随机推荐