android 计算活动倒计时及配合Timer在RecyclerView中的应用

今天做一个活动倒计时,挺简单的,但是在计算间隔时间到秒的时候,却发现不精确,只能精确到分,但是需求需要,之后发现在计算小时的d_time/1000/60是有余的,给丢失了,丢失的刚好是需要的秒数,不仔细很难发现,记录一下

一,倒计时

 /**
     * 活动倒计时
     * @param end_time
     * @return
     */
    public static HashMap<Object,Object> activitiesCountdownTime(String end_time){
        HashMap<Object,Object> map=new HashMap<>();
        String start_time=getCurrentTime();
        long d_time=getLongtime(end_time)-getLongtime(start_time);
        if(d_time>0){
            long h=d_time/1000/60/60;//时
            long s=d_time/1000%60;//秒
            long m=d_time/1000/60%60;//分
            if(h<10){
                map.put("hour","0"+h);
            }else {
                map.put("hour",h);
            }
            if(m<10){
                map.put("minute","0"+m);
            }else {
                map.put("minute",m);
            }
            if(s<10){
                map.put("second","0"+s);
            }else {
                map.put("second",s);
            }
        }else {//防止显示负数
            map.put("hour","00");
            map.put("minute","00");
            map.put("second","00");
        }

      return map;
    }

//将时间装换毫秒

 public static long getLongtime(String str){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long millionSeconds = 0;//毫秒
        try {
            millionSeconds = sdf.parse(str).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return millionSeconds;
    }

二,3种常用的定时器

1.Handler类的postDelayed方法:

Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //do something

        }
    };
                 Runnable r = new Runnable() {

                    @Override
                    public void run() {
                           mHandler.sendEmptyMessage(msg.what);
                            //每隔1s循环执行run方法
                            mHandler.postDelayed(this, 1000);
                    }
                };


主线程中调用:  mHandler.post(r);//启动

2.用handler+timer+timeTask方法:

Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1){
                //do something
            }
            super.handleMessage(msg);
        }
    };

    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            Message message = new Message();
            message.what = 1;
            handler.sendMessage(message);
        }
    };
 主线程中调用:timer.schedule(timerTask,0,1000);//每隔1000毫秒执行一次run方法

3.Thread+handler方法:

Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1){
                //do something
            }
            super.handleMessage(msg);

        }
    };

    class MyThread extends Thread {//这里也可用Runnable接口实现
        @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(1000);//每隔1s执行一次
                    Message msg = new Message();
                    msg.what = 1;
                    handler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
主线程中调用:new Thread(new MyThread()).start();

三,计算活动倒计时及配合Timer在RecyclerView中的应用

最初的想法是利用Timer在adapter中开启定时器,每一个item开启一个timer,功能也是初步实现了,但是导致了一下问题:

1.下拉刷新活动倒计时会跳动显示其他时间(原因:每次下拉刷新都会重新创建Timer,导致一个item执行多个timer);

2.容易出现ANR(原因:每一个item创建一个timer,非常消耗内存);

当然有人会这么处理,及时取消Timer不久可以了吗?

  private List<Timer> timerList;//用于每开启一个Timer,便添加到list中,timerList.add(timer)

    public FreshProductListAdapter(@LayoutRes int layoutResId, @Nullable List<ItemMenu<ResponseSearchFresh.ListfreshBean>> data, Activity context, int width) {
        super(layoutResId, data);
        this.context = context;
        this.width = width;
        timerList = new ArrayList<>();
    }

    /**
     * 清空资源
     */
    public void cancelAllTimers() {
        if (timerList == null) {
            return;
        }
        LogUtils.e("定时器", "size :  " + timerList.size());
        for (int i = 0, length = timerList.size(); i < length; i++) {
            Timer cdt = timerList.get(i);
            if (cdt != null) {
                cdt.cancel();
                cdt = null;
            }
        }
    }

//每滑动便取消不显示item的timer
  @Override
    public void onViewRecycled(BaseViewHolder holder) {
        super.onViewRecycled(holder);
        cancelAllTimers();
    }

这样处理了问题一跳动的问题和滑动创建多个timer的问题,但也带来了新问题:

1.重新滑动之后发现时间不跳动了(原因把timer都给cancel()了);

2.进入页面之后不滑动,过一段时间页面还是ANR了(原因存在多个item,还是存在多个Timer);

正确处理方法:

在Activity中开启一个线程来处理所有的倒计时:

 private Runnable r;//定时器线程
    private boolean timerIsInit=false;//判断数据是否初始化
    final Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            for (int i=0;i<productData .size();i++){
                if(productData.get(i)!=null&&productData.get(i).getData()!=null&&!TextUtil.isEmpty(productData.get(i).getData().getEndTime())){
           //获取显示的数据,由个人的数据实体决定
                    HashMap<Object, Object> map = DateUtil.activitiesCountdownTime(productData.get(i).getData().getEndTime().replace("T", " "));
                    productData.get(i).getData().setHour(map.get("hour").toString());
                    productData.get(i).getData().setMinute(map.get("minute").toString());
                    productData.get(i).getData().setSecond(map.get("second").toString());
    
                    BaseViewHolder holder = (BaseViewHolder) productRecycleList.findViewHolderForAdapterPosition(i);//获取当前item的位置,这个是关键

                    if(holder!=null){//这种方式只刷新了显示时间相关的控件,并不需要去做很复杂的操作来刷新数据,甚至都不需要 notifyDataSetChanged();

                        timerIsInit=true;
                        holder .setText(R.id.tv_limit_time_hour, productData.get(i).getData().getHour());
                        holder .setText(R.id.tv_limit_time_minute, productData.get(i).getData().getMinute());
                        holder .setText(R.id.tv_limit_time_second, productData.get(i).getData().getSecond());
                    }
                }
            }

        }
    };


     在oncreat()方法中:

        r = new Runnable() {

            @Override
            public void run() {
                mHandler.sendEmptyMessage(200);
                if(timerIsInit){//数据初始化成功,则延迟1秒
                    mHandler.postDelayed(this, 1000);
                }else {
                    mHandler.post(this);
                }
            }
        };
        mHandler.post(r);


     //页面销毁时,销毁线程
 @Override
    protected void onDestroy() {
        super.onDestroy();
       
        if(mHandler!=null&&r!=null){
            mHandler.removeCallbacks(r);
        }
    }

完美解决。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值