【安卓笔记】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小时制也不是当前的时间

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值