由于之前有个项目需求是须要时时刻去更新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

Android实现多个倒计时优化与源代码分析的更多相关文章

  1. Android应用程序进程启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...

  2. Android系统进程Zygote启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6768304 在Android系统中,所有的应用 ...

  3. Android应用程序安装过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6766010 Android系统在启动的过程中, ...

  4. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

  5. Android KLog源代码分析

    Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直 ...

  6. android webview开发问题及优化汇总

    我们在native与网页相结合开发的过程中,难免会遇到关于WebView一些共通的问题.就我目前开发过程中遇到的问题以及最后得到的优化方案都将在这里列举出来.有些是老生常谈,有些则是个人摸索得出解决方 ...

  7. [FMX] Android APP 启动黑屏优化补丁

    使用说明 *************************************************** Android APP 启动黑屏优化补丁 作者: Swish, YangYxd 201 ...

  8. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  9. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...

随机推荐

  1. opencv笔记

    加载图像: OpenCV支持图像格式Windows位图(bmp),便携式图像格式(pbm,pgm,ppm)和Sun光栅(sr,ras). Mat image = imread( imageName, ...

  2. 【C语言】控制台窗口图形界面编程(四):文本输出

    目录 00. 目录 01. FillConsoleOutputAttribute函数 02. FillConsoleOutputCharacter函数 03. WriteConsoleOutputCh ...

  3. JVM优化(中)

    09.垃圾收集器之串行垃圾收集器: 1.-Xms512m 等价于 -XX:InitialHeapSize=512设置JVM初始堆内存大小:-Xmx2048m 等价于 -XX:MaxHeapSize=2 ...

  4. 学习 Qt 编程的好书精品推荐!

    最近一段时间,准备开始搞Qt方面的东西,想找几本书看看.网上介绍QT的书籍也有很多,不想浪费时间,所以想找几本精品的书籍来看.花了半天的时间找了几本非常不错的,这里面整理好之后推荐给大家! 下面介绍的 ...

  5. BZOJ4873 LuoguP3749 寿司餐厅

    题面太长,请诸位自行品尝—>寿司餐厅 分析: 首先题目中给了限制条件,假如选了D(i,j)(i<j),那么也就选了D(i+1,j)和D(i,j-1)两个点. 于是我们一下就明白了,哦,最大 ...

  6. 分布式集群算法 memcached 如何实现分布式?

    memcached 是一个”分布式缓存”,然后 memcached 并不像 mongoDB 那 样,允许配置多个节点,且节点之间”自动分配数据”. 就是说--memcached 节点之间,是不互相通信 ...

  7. jQuery的鼠标移入与移出事件

    mouseover与mouseenter 不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件. 只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件. mouseou ...

  8. 搭建Samba共享服务器

    [root@localhost ~]# yum -y install samba         #安装Samba [root@localhost ~]# rpm -qa | grep samba  ...

  9. MapReduce架构与执行流程

    一.MapReduce是用于解决什么问题的? 每一种技术的出现都是用来解决实际问题的,否则必将是昙花一现,那么MapReduce是用来解决什么实际的业务呢? 首先来看一下MapReduce官方定义: ...

  10. Linux 网卡配置

    网卡配置(环境CentOS 6.7) 图形界面修改: # 在命令行直接输入setup进入配置 1.[root@mingyaun ~]# setup 2.NetWork configuration 3. ...