【IT168技术】今天Android123通过DigitalClock类讲解下Android平台下自绘TextView类,演示下相关的Handler、Runnable线程和Observer观察者类。首先我们回忆下上次 Android自定义View实例AnalogClock源码 一文中的自绘控件,上次主要是重写View类onDraw方法实现自己绘制,本次我们直接从TextView控件来实现自己的数字时钟控件。
1. 将涉及Android平台UI线程的更新原理 Handler、Runnable
2. 对于Content数据存储对象可以使用Observer观察者类来获取SQLite数据库的变化
3. 由于本次没有改变控件的外观显示特性,所以没有重写TextView的onDraw方法,当然TextView也是从View中继承的所以可以直接调用基类的onDraw方法。Android开发网提示目前所有Android控件包android.widget.XXX都是从android.view.View类继承的。
1 public class DigitalClock extends TextView {
2
3 Calendar mCalendar;
4 private final static String m12 = "h:mm:ss aa";
5 private final static String m24 = "k:mm:ss";
6 private FormatChangeObserver mFormatChangeObserver;
7
8 private Runnable mTicker;
9 private Handler mHandler;
10
11 private boolean mTickerStopped = false;
12
13 String mFormat;
14
15 public DigitalClock(Context context) {
16 super(context);
17 initClock(context); //资源初始化,本次为了清晰直接放到独立的initClock方法中实现。
18 }
19
20 public DigitalClock(Context context, AttributeSet attrs) {
21 super(context, attrs);
22 initClock(context); //同上
23 }
24
25 private void initClock(Context context) {
26 Resources r = mContext.getResources();
27
28 if (mCalendar == null) {
29 mCalendar = Calendar.getInstance();
30 }
31
32 mFormatChangeObserver = new FormatChangeObserver(); //构造一个Observer
33 getContext().getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver); //注册该对象,用于检查小时制
34
35 setFormat();
36 }
37
38 @Override
39 protected void onAttachedToWindow() {
40 mTickerStopped = false;
41 super.onAttachedToWindow();
42 mHandler = new Handler();
43
44 mTicker = new Runnable() { //开一个线程获取系统时间变化,这点和上次接收action而言性能更高,可以获取到毫秒的精度
45
46 public void run() {
47 if (mTickerStopped) return;
48 mCalendar.setTimeInMillis(System.currentTimeMillis());
49 setText(DateFormat.format(mFormat, mCalendar));
50 invalidate();
51 long now = SystemClock.uptimeMillis();
52 long next = now + (1000 - now % 1000);
53 mHandler.postAtTime(mTicker, next);
54 }
55 };
56 mTicker.run();
57 }
58
59 @Override
60 protected void onDetachedFromWindow() { //Android开发网上次的AnalogClock中已经详细讲述,这里CWJ不再赘述
61 super.onDetachedFromWindow();
62 mTickerStopped = true;
63 }
64
65 private boolean get24HourMode() {
66 return android.text.format.DateFormat.is24HourFormat(getContext());
67 }
68
69 private void setFormat() { //设置小时制
70 if (get24HourMode()) {
71 mFormat = m24;
72 } else {
73 mFormat = m12;
74 }
75 }
76
77 private class FormatChangeObserver extends ContentObserver { //Android123提示大家应该多了解下ContentObserver,用处很大
78 public FormatChangeObserver() {
79 super(new Handler());
80 }
81
82 @Override
83 public void onChange(boolean selfChange) {
84 setFormat();
85 }
86 }
87 }
88
2
3 Calendar mCalendar;
4 private final static String m12 = "h:mm:ss aa";
5 private final static String m24 = "k:mm:ss";
6 private FormatChangeObserver mFormatChangeObserver;
7
8 private Runnable mTicker;
9 private Handler mHandler;
10
11 private boolean mTickerStopped = false;
12
13 String mFormat;
14
15 public DigitalClock(Context context) {
16 super(context);
17 initClock(context); //资源初始化,本次为了清晰直接放到独立的initClock方法中实现。
18 }
19
20 public DigitalClock(Context context, AttributeSet attrs) {
21 super(context, attrs);
22 initClock(context); //同上
23 }
24
25 private void initClock(Context context) {
26 Resources r = mContext.getResources();
27
28 if (mCalendar == null) {
29 mCalendar = Calendar.getInstance();
30 }
31
32 mFormatChangeObserver = new FormatChangeObserver(); //构造一个Observer
33 getContext().getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver); //注册该对象,用于检查小时制
34
35 setFormat();
36 }
37
38 @Override
39 protected void onAttachedToWindow() {
40 mTickerStopped = false;
41 super.onAttachedToWindow();
42 mHandler = new Handler();
43
44 mTicker = new Runnable() { //开一个线程获取系统时间变化,这点和上次接收action而言性能更高,可以获取到毫秒的精度
45
46 public void run() {
47 if (mTickerStopped) return;
48 mCalendar.setTimeInMillis(System.currentTimeMillis());
49 setText(DateFormat.format(mFormat, mCalendar));
50 invalidate();
51 long now = SystemClock.uptimeMillis();
52 long next = now + (1000 - now % 1000);
53 mHandler.postAtTime(mTicker, next);
54 }
55 };
56 mTicker.run();
57 }
58
59 @Override
60 protected void onDetachedFromWindow() { //Android开发网上次的AnalogClock中已经详细讲述,这里CWJ不再赘述
61 super.onDetachedFromWindow();
62 mTickerStopped = true;
63 }
64
65 private boolean get24HourMode() {
66 return android.text.format.DateFormat.is24HourFormat(getContext());
67 }
68
69 private void setFormat() { //设置小时制
70 if (get24HourMode()) {
71 mFormat = m24;
72 } else {
73 mFormat = m12;
74 }
75 }
76
77 private class FormatChangeObserver extends ContentObserver { //Android123提示大家应该多了解下ContentObserver,用处很大
78 public FormatChangeObserver() {
79 super(new Handler());
80 }
81
82 @Override
83 public void onChange(boolean selfChange) {
84 setFormat();
85 }
86 }
87 }
88
通过本次DigitalClock类的了解,可以看到Android平台的控件重绘以及消息处理很简单吧,其实本节的涉及到的Observer类可以做很多底层的事情,由于可以捕获SQLite数据库的变化,聪明的你可以想象到设计哪些安全产品了吧。