zoukankan      html  css  js  c++  java
  • Android实现多个倒计时优化与源代码分析


    由于之前有个项目需求是须要时时刻去更新UI倒计时,之前想到的,这简单嘛,用计时或者Handler就能够搞定,并且性能也不错,可是需求要ListView,什么,?大量的View都须要,那Handle处理不好会挂的啊,那轮训呢,?太消耗内存和Cpu,突然之前仅仅有想到用Handle去处理,可是Item太多怎样管理呢.?

    带着这种问题,思考着纠结着,今天无意中看到一个源代码还不错,

    这个类是Google原生提供的数字时钟,能够实现时时刻刻的更新,我想里面肯定封装了一些实现的逻辑就跟着開始研究学习,以下是该类的主要结构:

    /**
     * Like AnalogClock, but digital.  Shows seconds.
     *
     * FIXME: implement separate views for hours/minutes/seconds, so
     * proportional fonts don't shake rendering
     */
    
    public class DigitalClock extends TextView {
    
        Calendar mCalendar;
        private final static String m12 = "h:mm:ss aa";
        private final static String m24 = "k:mm:ss";
        private FormatChangeObserver mFormatChangeObserver;
    
        private Runnable mTicker;
        private Handler mHandler;
    
        private boolean mTickerStopped = false;
    
        String mFormat;
    
        public DigitalClock(Context context) {
            super(context);
            initClock(context);
        }
    
        public DigitalClock(Context context, AttributeSet attrs) {
            super(context, attrs);
            initClock(context);
        }
    
        private void initClock(Context context) {
            Resources r = mContext.getResources();
    
            if (mCalendar == null) {
                mCalendar = Calendar.getInstance();
            }
    
            mFormatChangeObserver = new FormatChangeObserver(); //格式观察者,開始第一眼我看到这儿以为是通过观察者去实现的,结果仅仅是一个格式的观察.
            getContext().getContentResolver().registerContentObserver( //注冊
                    Settings.System.CONTENT_URI, true, mFormatChangeObserver);
    
            setFormat(); // 设置格式
        }
    


    /**
     *这种方法就是更新的核心,该方法是能正常的call onDraw或者onMeasure后便会回调.
     *
     */
     @Override
        protected void onAttachedToWindow() {
            mTickerStopped = false;
            super.onAttachedToWindow();
            mHandler = new Handler(); // 用于Post一个runable.
    
            /**
             * requests a tick on the next hard-second boundary
             */
            mTicker = new Runnable() {
                    public void run() {
                        if (mTickerStopped) return;
                        mCalendar.setTimeInMillis(System.currentTimeMillis()); // 之前创建日历对象获取时间.
                        setText(DateFormat.format(mFormat, mCalendar)); // 设置时间
                        invalidate(); // 更新UI
                        long now = SystemClock.uptimeMillis();
                        long next = now + (1000 - now % 1000);// 这儿算法不错,保证一秒更新一次,
                        mHandler.postAtTime(mTicker, next);
                    }
                };
            mTicker.run();
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            mTickerStopped = true;// 保证复用的时候,runable被系统回收.
        }
    
        /**
         * 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();
            }
        }
    
        @Override
        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
            super.onInitializeAccessibilityEvent(event);
            event.setClassName(DigitalClock.class.getName());
        }
    
        @Override
        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
            super.onInitializeAccessibilityNodeInfo(info);
            info.setClassName(DigitalClock.class.getName());
        }
    }


    看到OnAttachedToWindow方法后,能够借鉴出来一个自己定义的好的写法.我就不用Calender去获取时间更新,把它封装出来给用户使用.我就临时仅仅贴出核心代码吧

    @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 - 1 * 60) { // 判定是否到了指定时间
    					mClockListener.remainOneMinutes(); // 指定时间的CallBack
    				}
    				long distanceTime = endTime - currentTime;// 计算差值
    				distanceTime /= 1000; // 转为秒
    				if (distanceTime == 0) {
    					setText("00:00:00");
    					onDetachedFromWindow(); // 保证该runnable不在被继续执行.
    					mClockListener.timeEnd(); // 结束call back.
    				} else if (distanceTime < 0) {
    					setText("00:00:00");
    				} else {
    					setText(dealTime(distanceTime));// 设置倒计时.
    				}
    				invalidate();
    				long now = SystemClock.uptimeMillis();
    				long next = now + (1000 - now % 1000);// 够不够一秒,保证一秒更新一次
    				mHandler.postAtTime(mTicker, next);
    			}
    		};
    		mTicker.run();
    	}



    上面是核心展示UI工具类,真正的回收机制在以下处理,

    在ListView中设置一个setRecyclerListener,该监听会依据手指滑动一个View移除屏幕外的时候会callback.

    @Override
        public void onMovedToScrapHeap(View view) {
            try {
                ((ClockView)((LinearLayout) view).getChildAt(0)).changeTicker();//寻找时钟,并启动.
            }catch (Exception e){
                e.printStackTrace();
            }
        }


    回收的推断,

    <pre name="code" class="java">/**
         * 回收后启动
         */
        public void changeTicker() {
            mTickerStopped = !mTickerStopped;
            if (!mTickerStopped) {
                mHandler.post(mTicker);
            }else{
                mHandler.removeCallbacks(mTicker);
            }
        }


    
    

    在适配器中:

    @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            ViewHolder holder;
            if (null == convertView) {
                holder = new ViewHolder();
                convertView = View.inflate(context, R.layout.item_list, null);
                holder.cv = (ClockView) convertView.findViewById(R.id.cv);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
                holder.cv.changeTicker(); // 从回收中拿的时候启动一次.
            }
            holder.cv.setEndTime(mTimes.get(position));
            return convertView;
        }



    github:https://github.com/q422013/ListClock

  • 相关阅读:
    Python股票分析系列——系列介绍和获取股票数据.p1
    快速相关
    特别长序列的快速卷积
    长序列的快速卷积
    快速卷积
    素因子快速傅里叶变换
    用一个N点复序列的FFT同时计算两个N点实序列离散傅里叶变换
    实序列快速傅里叶变换(二)
    实序列快速傅里叶变换(一)
    java 对于手机号码、邮箱、银行卡号脱敏一条龙服务
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7136125.html
Copyright © 2011-2022 走看看