由于之前有个项目需求是须要时时刻去更新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. filezilla server FTP 安装报错 "could not load TLS network. Aborting start of administration interface"

    filezilla server FTP 安装报错   "could not load TLS network. Aborting start of administration inter ...

  2. JavaScript异步编程解决方案探究

    javascript的天生单线程特性,使得异步编程对它异常重要,早期的通常做法是用回调函数来解决.但是随着逻辑的复杂,和javascript在服务端的大显神通,使得我们很容易就陷入“回调陷井”的万丈深 ...

  3. 用PHP的GD库画五星红旗来玩玩

    1 header("Content-Type:image/jpeg"); $img=imagecreatetruecolor(999,667); $color=imagecolor ...

  4. [Python3网络爬虫开发实战] 1.9.4-Scrapyd API的安装

    安装好了Scrapyd之后,我们可以直接请求它提供的API来获取当前主机的Scrapy任务运行状况.比如,某台主机的IP为192.168.1.1,则可以直接运行如下命令获取当前主机的所有Scrapy项 ...

  5. word 给段落添加背景色

    word 2007 单击"页面布局"选项卡->单击"页面背景"一栏中的"页面边框"->(弹出边框与底纹对话框)->点击底纹 ...

  6. 史上最全Java多线程面试题及答案

    多线程有什么用? 线程和进程的区别是什么? Java实现线程有哪几种方式? 启动线程方法start()和run()有什么区别? 怎么终止一个线程?如何优雅地终止线程? 一个线程的生命周期有哪几种状态? ...

  7. Archive log restore using RMAN for Logminer (http://www.dba-village.com/village/dvp_forum.OpenThread?ThreadIdA=26816)

    Subject: Archive log restore using RMAN for Logminer Author: Edwin Weele van der, Netherlands Date: ...

  8. Online IDE & Public URLs & turbo

    Online IDE powered by Visual Studio Code https://stackblitz.com/ https://www.polymer-project.org/3.0 ...

  9. bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

    [bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...

  10. MTK平台添加防止误触代码

    ltr559_old: #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/slab. ...