`
crazysumer
  • 浏览: 49690 次
社区版块
存档分类
最新评论

【安卓笔记】Handler:显示时间

阅读更多



 

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小时制也不是当前的时间

 

  • 大小: 46.1 KB
分享到:
评论

相关推荐

    android_handler学习笔记

    Handler在android里负责发送和处理消息。它的主要用途有(或者是干什么的):  1)执行计划任务,按计划(定时)发送消息或执行某个Runnanble(使用POST方法);  2)线程间通信,把从其他线程中发送来的消息放入消息...

    Android学习笔记三:第一个应用程序的扩充

    在这个"Android学习笔记三:第一个应用程序的扩充"中,我们将深入探讨如何扩展这个基础,以更好地理解和掌握Android应用开发的核心概念。 首先,Android Studio作为Google官方推荐的集成开发环境(IDE),是Android...

    xamarin学习笔记A13(安卓Handler异步消息处理)

    1. Handler:是消息处理的核心,它定义了一个消息队列,并处理来自该队列的消息。通常,我们会在主线程中创建一个Handler实例,这样它就能接收到主线程的消息并进行处理。 2. Looper:每个线程都有一个消息循环,...

    Android开发笔记之:Splash的实现详解

    1. **用户体验**:如果Splash页面显示时间过长,可能会让用户感到等待不耐烦,影响用户体验。 2. **内存占用**:由于创建了额外的Activity,会占用更多的系统资源。 3. **不符合Material Design规范**:Google推荐的...

    Pro Android学习:了解Handler小例子

    这是Pro Android学习系列中Android Service部分的例子源代码。相关学习笔记见:http://blog.csdn.net/flowingflying/article/details/6212512

    安卓笔记——安卓详细笔记汇总

    在安卓开发的学习过程中,积累详尽的笔记是提升技能的关键步骤。这份名为“安卓笔记——安卓详细笔记汇总”的资源,无疑是安卓开发者或者学习者的重要参考资料。以下将对这个压缩包中可能包含的知识点进行深入解析。...

    Android开发笔记之:Handler Runnable与Thread的区别详解

    Handler、Message和Looper是Android特有的用于线程间通信的机制。通常,主线程(UI线程)拥有一个Looper,而其他线程没有。当在工作线程中创建一个Handler并关联到主线程的Looper时,可以在工作线程中发送Message,...

    Android笔记:Socket客户端收发数据

    在Android开发中,Socket通信是实现设备间数据传输的重要手段,尤其在构建网络服务和进行设备间的实时交互时。本文将深入探讨如何在Android平台上创建一个Socket客户端,以及如何通过TCP协议进行数据的发送和接收。 ...

    Android开发笔记 Handler使用总结

    【Android开发笔记:Handler使用总结】 在Android应用开发中,Handler是处理线程间通信和UI更新的关键组件。当应用程序启动时,Android系统会默认创建一个主线程(UI线程),该线程主要负责管理界面中的UI控件,...

    安卓开发笔记

    在开始安卓开发之前,你需要安装并配置Android Studio,这是Google官方推荐的集成开发环境(IDE)。它包括了Java Development Kit (JDK)、Android SDK、模拟器和必要的工具。你需要设置Android SDK路径,选择合适的...

    最新最全的Android开发笔记

    除此之外,笔记还涉及了Android的多线程处理,包括Handler、Looper、Message的使用,以及AsyncTask的介绍。这些内容对于优化应用性能和实现后台操作至关重要。 网络编程是现代应用不可或缺的一部分,笔记中详细讲述...

    安卓基础笔记-超详细

    【安卓基础笔记-超详细】 在安卓开发领域,学习基础知识是至关重要的,因为它是构建强大应用的基石。这篇笔记详细地涵盖了安卓开发的基本概念、环境搭建、编程语言、UI设计、事件处理、数据存储以及网络通信等多个...

    黑马程序员安卓 笔记代码(包含源码) 第76期

    【标题】"黑马程序员安卓 笔记代码(包含源码) 第76期" 提供的是安卓开发的相关学习资料,其中包含了源码,这通常意味着我们可以深入理解代码的实现细节和设计思路。作为第76期,这可能是一个长期系列教程的一部分...

    android 非常全培训笔记

    7. **服务(Service)**:Service是Android中用于在后台长时间运行的组件,适用于音乐播放、后台下载等场景。学习启动服务、绑定服务及其生命周期管理。 8. **BroadcastReceiver**:广播接收器可以监听系统或自定义...

    Android开发笔记全集

    《Android开发笔记全集》是一份综合性的学习资源,涵盖了Android应用开发的多个核心领域,旨在帮助开发者系统地掌握Android平台的开发技能。这个压缩包包含的文件名为“Android开发笔记”,暗示着它可能是一个系列的...

    超全android 教程 笔记

    Android教程笔记涵盖了大量的知识点,是学习Android开发的重要资源。以下是对这些笔记的详细解析: 1. **Android基础知识**:这是Android开发的起点,包括对Java语言的理解,因为Android应用程序主要用Java编写。...

    android开发笔记入门级

    8. **服务和服务生命周期**:Android服务在后台运行,不与用户界面直接交互,用于执行长时间运行的任务。 9. **BroadcastReceiver**:广播接收器允许应用接收并响应系统或自定义广播事件,增强应用的响应能力。 10...

Global site tag (gtag.js) - Google Analytics