1.简单数字时钟
学习通过Handler +线程刷新UI,时钟或者计时器练习
下面这段简短的代码就可以实现(关键代码就只有Handler的post和postDelayed方法),其中的机制(消息队列等)还要继续学习
public class RefreshActivity extends Activity implements Runnable { private TextView tv; private Handler h = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_refresh); tv = (TextView) findViewById(R.id.tv); h.post(this); /* * Handler的post方法 * final boolean post(Runnable r) * Causes the Runnable r to be added to the message queue. * 把RefreshActivity这个线程加到消息队列中 */ } @Override public void run() { // 线程体 Date date = new Date(System.currentTimeMillis()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(date); tv.setText(time); h.postDelayed(this, 1000); /* * Handler的postDelayed方法 * final boolean postDelayed(Runnable r, long delayMillis) * Causes the Runnable r to be added to the message queue, to be run after the * specified amount of time elapses. * * 把RefreshActivity这个线程延时1秒加入到消息队列 */ } }
这个是常规的比较完整的写法了,比较容易理解
/** * 整个Activity开启一个UI主线程,负责子线程的管理、UI的更新 * */ public class NewRefreshActivity extends Activity { private TextView tv; private Handler handler; private String time; private boolean isRunning = true;//用这个标志位来让线程不断运行下去 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_refresh); tv = (TextView) findViewById(R.id.tv); /** * Handler属于主线程,把子线程中传递过来的数据用来更新UI * * Handler之所以存在,是因为子线程是不能够更改创建UI的线程中的UI的 * */ handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); tv.setText(msg.obj ""); } }; /** * 用来处理时间增长的子线程(匿名内部类) * 在这里让时间以1秒为单位增长,并把改变了的时间放到msg的obj属性中,通过Handler传给主线程 * * */ new Thread() { @Override public void run() { super.run(); while(isRunning){ try { sleep(1000);//睡眠1秒 Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss"); time = sdf.format(date); Message msg = new Message(); msg.obj = time; handler.sendMessage(msg); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } }
2.关于android自带时钟小工具
Android自带的只有时针和分针的AnalogClock,只要在上面的代码中初始化就能走了,为什么呢?
4.关于自定义时钟
把需要的图片资源都放到drawable中,在自定义的View(继承自View类)中,用BitmapDrawble加载图片,在线程中每隔秒就重绘秒针图片、60秒重绘分针图片、360秒重绘时针图片(关于重绘的位置,还有点复杂,感觉)
下载了一个筒子写的自定义时钟源码,没怎么明白,差不多就是这么个思路
@RemoteView public class AnalogClock extends View { private BitmapDrawable mDialDrawable; private BitmapDrawable mHourHandDrawable; private BitmapDrawable mMinuteHandDrawable; private BitmapDrawable mSecondHandDrawable; private int mDialWidth; private int mDialHeight; private boolean mAttached = false; private float mHours; private float mMinutes; private float mSeconds; private int totaltime; /** * 标志时间、时钟布局大小等是否有改变 */ private boolean mChanged; /** * 线程队列管理,消息传递和处理机制 */ private Handler loopHandler = new Handler(); /** * 标志页面刷新线程尚未执行 */ private boolean isRun = false; /** * 时钟运行 */ private void run() { /** * 将线程加入队列 */ loopHandler.post(tickRunnable); } private Runnable tickRunnable = new Runnable() { public void run() { /** * 在非UI线程调用,强制刷新界面 */ postInvalidate(); totaltime++; /** * 将线程加入队列,1000毫秒后启动 */ loopHandler.postDelayed(tickRunnable, 1000); } }; /** * 构造方法 */ public AnalogClock(Context context) { this(context, null); } public AnalogClock(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AnalogClock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); totaltime = 0; Resources r = this.getContext().getResources(); InputStream is =null; /** * 初始化表盘,时针,分针, 秒针 */ is = r.openRawResource(R.drawable.clockdroid2_dial); mDialDrawable = new BitmapDrawable(is); is = r.openRawResource(R.drawable.clockdroid2_hour); mHourHandDrawable = new BitmapDrawable(is); is = r.openRawResource(R.drawable.clockdroid2_minute); mMinuteHandDrawable = new BitmapDrawable(is); is = r.openRawResource(R.drawable.clockdroid2_second); mSecondHandDrawable = new BitmapDrawable(is); /** * 获取表盘有效像素宽高 */ mDialWidth = mDialDrawable.getIntrinsicWidth(); mDialHeight = mDialDrawable.getIntrinsicHeight(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null, loopHandler); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { getContext().unregisterReceiver(mIntentReceiver); mAttached = false; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); float hScale = 1.0f; float vScale = 1.0f; if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) { hScale = (float) widthSize / (float) mDialWidth; } if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) { vScale = (float )heightSize / (float) mDialHeight; } float scale = Math.min(hScale, vScale); setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec), resolveSize((int) (mDialHeight * scale), heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mChanged = true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(!isRun) { run(); isRun = true; return; } onTimeChanged(); boolean changed = mChanged; if (changed) { mChanged = false; } int availableWidth = getWidth(); int availableHeight = getHeight(); int x = availableWidth / 2; int y = availableHeight / 2; final Drawable dial = mDialDrawable; int w = dial.getIntrinsicWidth(); int h = dial.getIntrinsicHeight(); if (changed) { dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } dial.draw(canvas); canvas.save(); canvas.rotate(mHours / 12.0f * 360.0f, x, y); final Drawable hourHand = mHourHandDrawable; if (changed) { w = hourHand.getIntrinsicWidth(); h = hourHand.getIntrinsicHeight(); hourHand.setBounds(x - (w / 2), y - (h * 53 / 100), x + (w / 2), y + (h * 47 / 100)); } hourHand.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mMinutes / 60.0f * 360.0f, x, y); final Drawable minuteHand = mMinuteHandDrawable; if (changed) { w = minuteHand.getIntrinsicWidth(); h = minuteHand.getIntrinsicHeight(); minuteHand.setBounds(x - (w / 2), y - (h * 53 / 100), x + (w / 2), y + (h * 47 / 100)); } minuteHand.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mSeconds / 60.0f * 360.0f, x, y); final Drawable scendHand = mSecondHandDrawable; if (changed) { w = scendHand.getIntrinsicWidth(); h = scendHand.getIntrinsicHeight(); scendHand.setBounds(x - (w / 2), y - (h * 53 / 100), x + (w / 2), y + (h * 47 / 100)); } scendHand.draw(canvas); canvas.restore(); } private void onTimeChanged() { mSeconds = totaltime % 60; mMinutes = totaltime / 60; mHours = totaltime / 3600; mChanged = true; } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onTimeChanged(); invalidate(); } }; }
这个显示,貌似不正确,两个钟显示不一样,数字时钟就按12小时制也不是当前的时间
相关推荐
Handler在android里负责发送和处理消息。它的主要用途有(或者是干什么的): 1)执行计划任务,按计划(定时)发送消息或执行某个Runnanble(使用POST方法); 2)线程间通信,把从其他线程中发送来的消息放入消息...
在这个"Android学习笔记三:第一个应用程序的扩充"中,我们将深入探讨如何扩展这个基础,以更好地理解和掌握Android应用开发的核心概念。 首先,Android Studio作为Google官方推荐的集成开发环境(IDE),是Android...
1. Handler:是消息处理的核心,它定义了一个消息队列,并处理来自该队列的消息。通常,我们会在主线程中创建一个Handler实例,这样它就能接收到主线程的消息并进行处理。 2. Looper:每个线程都有一个消息循环,...
1. **用户体验**:如果Splash页面显示时间过长,可能会让用户感到等待不耐烦,影响用户体验。 2. **内存占用**:由于创建了额外的Activity,会占用更多的系统资源。 3. **不符合Material Design规范**:Google推荐的...
这是Pro Android学习系列中Android Service部分的例子源代码。相关学习笔记见:http://blog.csdn.net/flowingflying/article/details/6212512
在安卓开发的学习过程中,积累详尽的笔记是提升技能的关键步骤。这份名为“安卓笔记——安卓详细笔记汇总”的资源,无疑是安卓开发者或者学习者的重要参考资料。以下将对这个压缩包中可能包含的知识点进行深入解析。...
Handler、Message和Looper是Android特有的用于线程间通信的机制。通常,主线程(UI线程)拥有一个Looper,而其他线程没有。当在工作线程中创建一个Handler并关联到主线程的Looper时,可以在工作线程中发送Message,...
在Android开发中,Socket通信是实现设备间数据传输的重要手段,尤其在构建网络服务和进行设备间的实时交互时。本文将深入探讨如何在Android平台上创建一个Socket客户端,以及如何通过TCP协议进行数据的发送和接收。 ...
【Android开发笔记:Handler使用总结】 在Android应用开发中,Handler是处理线程间通信和UI更新的关键组件。当应用程序启动时,Android系统会默认创建一个主线程(UI线程),该线程主要负责管理界面中的UI控件,...
在开始安卓开发之前,你需要安装并配置Android Studio,这是Google官方推荐的集成开发环境(IDE)。它包括了Java Development Kit (JDK)、Android SDK、模拟器和必要的工具。你需要设置Android SDK路径,选择合适的...
除此之外,笔记还涉及了Android的多线程处理,包括Handler、Looper、Message的使用,以及AsyncTask的介绍。这些内容对于优化应用性能和实现后台操作至关重要。 网络编程是现代应用不可或缺的一部分,笔记中详细讲述...
【安卓基础笔记-超详细】 在安卓开发领域,学习基础知识是至关重要的,因为它是构建强大应用的基石。这篇笔记详细地涵盖了安卓开发的基本概念、环境搭建、编程语言、UI设计、事件处理、数据存储以及网络通信等多个...
【标题】"黑马程序员安卓 笔记代码(包含源码) 第76期" 提供的是安卓开发的相关学习资料,其中包含了源码,这通常意味着我们可以深入理解代码的实现细节和设计思路。作为第76期,这可能是一个长期系列教程的一部分...
7. **服务(Service)**:Service是Android中用于在后台长时间运行的组件,适用于音乐播放、后台下载等场景。学习启动服务、绑定服务及其生命周期管理。 8. **BroadcastReceiver**:广播接收器可以监听系统或自定义...
《Android开发笔记全集》是一份综合性的学习资源,涵盖了Android应用开发的多个核心领域,旨在帮助开发者系统地掌握Android平台的开发技能。这个压缩包包含的文件名为“Android开发笔记”,暗示着它可能是一个系列的...
Android教程笔记涵盖了大量的知识点,是学习Android开发的重要资源。以下是对这些笔记的详细解析: 1. **Android基础知识**:这是Android开发的起点,包括对Java语言的理解,因为Android应用程序主要用Java编写。...
8. **服务和服务生命周期**:Android服务在后台运行,不与用户界面直接交互,用于执行长时间运行的任务。 9. **BroadcastReceiver**:广播接收器允许应用接收并响应系统或自定义广播事件,增强应用的响应能力。 10...