标签:
关于倒计时的实现,可以说有很多的方法,比较常见的就是Timer+TimerTask+Handler了,或者还可以配合Runnable。例如下面的代码:
- import java.util.Timer;
- import java.util.TimerTask;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class MainActivity extends Activity {
-
- Timer timer;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- final TextView tv = (TextView) findViewById(R.id.textView1);
- Button b = (Button) findViewById(R.id.button1);
-
- // 定义Handler
- final Handler handler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- //handler处理消息
- if(msg.what>0){
- tv1.setText("" + msg.what);
- }else{
- //在handler里可以更改UI组件
- tv.setText("倒时");
- timer.cancel();
- }
- }
- };
-
- b.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- // 定义计时器
- timer = new Timer();
-
- // 定义计划任务,根据参数的不同可以完成以下种类的工作:在固定时间执行某任务,在固定时间开始重复执行某任务,重复时间间隔可控,在延迟多久后执行某任务,在延迟多久后重复执行某任务,重复时间间隔可控
- timer.schedule(new TimerTask() {
- int i = 10;
-
- // TimerTask 是个抽象类,实现的是Runable类
- @Override
- public void run() {
-
- //定义一个消息传过去
- Message msg = new Message();
- msg.what = i--;
- handler.sendMessage(msg);
- }
-
- }, 1000, 200);
- }
- });
-
- }
-
- }
基本逻辑就是这样,需要注意一点是 timer.schedule(task,1000,5000),如果设置为 timer.schedule(task,5000)是不会工作的。因为timer.schedule(task,5000) 是表示执行一次的任务。timer.schedule(task,1000,5000)表示1 秒钟后开始 5 秒钟为周期 的重复执行任务。
这个例子北京简单,下面给出一个完整的例子:
布局:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/daojishitvTime"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_above="@+id/daojishibuttonlinear"
- android:layout_centerInParent="true"
- android:text="00:00.0"
- android:textSize="35sp"
- android:textStyle="bold" />
-
- <LinearLayout
- android:id="@+id/daojishibuttonlinear"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:orientation="vertical" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="74sp"
- android:background="@drawable/v5_bottom_bar_bg_light"
- android:orientation="horizontal" >
-
- <Button
- android:id="@+id/daojishistartbutton"
- android:layout_width="wrap_content"
- android:layout_height="50sp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="8sp"
- android:layout_marginRight="3sp"
- android:layout_weight="1"
- android:background="@drawable/startbutton"
- android:text="开始" />
-
- <Button
- android:id="@+id/daojishijicubutton"
- android:layout_width="wrap_content"
- android:layout_height="50sp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="3sp"
- android:layout_marginRight="8sp"
- android:layout_weight="1"
- android:background="@drawable/startbutton"
- android:text="取消" />
- </LinearLayout>
- </LinearLayout>
-
- </RelativeLayout>
显然,这个方式比较笨拙,我们可以对此进行一个封装,利用Handler和Eunnable,看下面的代码:
- package com.example.daojishi;
-
- import android.os.Handler;
- import android.util.Log;
-
- public class MyCountDownTimer {
- private long millisInFuture;
- private long countDownInterval;
- private boolean status;
-
- public MyCountDownTimer(long pMillisInFuture, long pCountDownInterval) {
- this.millisInFuture = pMillisInFuture;
- this.countDownInterval = pCountDownInterval;
- status = false;
- Initialize();
- }
-
- public void Stop() {
- status = false;
- }
-
- public long getCurrentTime() {
- return millisInFuture;
- }
-
- public void Start() {
- status = true;
- }
-
- public void Initialize() {
- final Handler handler = new Handler();
- Log.v("status", "starting");
- final Runnable counter = new Runnable() {
-
- public void run() {
- long sec = millisInFuture / 1000;
- if (status) {
- if (millisInFuture <= 0) {
- Log.v("status", "done");
- } else {
- Log.v("status", Long.toString(sec) + " seconds remain");
- millisInFuture -= countDownInterval;
- handler.postDelayed(this, countDownInterval);
- }
- } else {
- Log.v("status", Long.toString(sec)
- + " seconds remain and timer has stopped!");
- handler.postDelayed(this, countDownInterval);
- }
- }
- };
-
- handler.postDelayed(counter, countDownInterval);
- }
- }
这个类就是负责倒计时的类,下面结合Activity,看一下怎么用:
- package com.example.daojishi;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class CounterActivity extends Activity {
- /** Called when the activity is first created. */
- TextView timeText;
- Button startBut;
- Button stopBut;
- MyCountDownTimer mycounter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- timeText = (TextView) findViewById(R.id.time);
- startBut = (Button) findViewById(R.id.start);
- stopBut = (Button) findViewById(R.id.stop);
- mycounter = new MyCountDownTimer(20000, 1000);
- RefreshTimer();
- }
-
- public void StartTimer(View v) {
- Log.v("startbutton", "开始倒计时");
- mycounter.Start();
- }
-
- public void StopTimer(View v) {
- Log.v("stopbutton", "暂停倒计时");
- mycounter.Stop();
- }
-
- public void RefreshTimer() {
- final Handler handler = new Handler();
- final Runnable counter = new Runnable() {
-
- public void run() {
- timeText.setText(Long.toString(mycounter.getCurrentTime()));
- handler.postDelayed(this, 100);
- }
- };
-
- handler.postDelayed(counter, 100);
- }
- }
布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
- android:weightSum="1" >
-
- <TextView
- android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="TextView"
- android:textAppearance="?android:attr/textAppearanceLarge" >
- </TextView>
-
- <Button
- android:id="@+id/start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="StartTimer"
- android:text="Start" >
- </Button>
-
- <Button
- android:id="@+id/stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="StopTimer"
- android:text="Stop" >
- </Button>
-
- </LinearLayout>
这样就可以比较方便地使用倒计时功能了。但是还有一个更简单的方法。
在Android中有一个CountDownTimer类,这个类就是用来实现类似倒计时方面的功能。使用的时候,只需要继承自CountDownTimer并实现它的方法。
- import android.app.Activity;
- import android.os.Bundle;
- import android.content.Intent;
- import android.os.CountDownTimer;
- import android.widget.TextView;
- import android.widget.Toast;
- public class NewActivity extends Activity {
- private MyCount mc;
- private TextView tv;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tv = (TextView)findViewById(R.id.show);
- mc = new MyCount(30000, 1000);
- mc.start();
- }
-
- /*定义一个倒计时的内部类*/
- class MyCount extends CountDownTimer {
- public MyCount(long millisInFuture, long countDownInterval) {
- super(millisInFuture, countDownInterval);
- }
- @Override
- public void onFinish() {
- tv.setText("done");
- }
- @Override
- public void onTick(long millisUntilFinished) {
- tv.setText("seconds remaining: " + millisUntilFinished / 1000);
-
- }
- }
- }
onFinish()方法是本次倒计时结束的时候调用的,onTick是每隔1秒钟执行的,我们就是在这里执行重复的任务,像本例子的显示时间。执行完后会自动取消,如果在期间停止的话,可以调用cancel()方法。看一下它的源码就会发现,它是使用Handler+SystemClock来实现的。
- /*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package android.os;
-
- import android.util.Log;
-
- /**
- * Schedule a countdown until a time in the future, with
- * regular notifications on intervals along the way.
- *
- * Example of showing a 30 second countdown in a text field:
- *
- * <pre class="prettyprint">
- * new CountDownTimer(30000, 1000) {
- *
- * public void onTick(long millisUntilFinished) {
- * mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
- * }
- *
- * public void onFinish() {
- * mTextField.setText("done!");
- * }
- * }.start();
- * </pre>
- *
- * The calls to {@link #onTick(long)} are synchronized to this object so that
- * one call to {@link #onTick(long)} won‘t ever occur before the previous
- * callback is complete. This is only relevant when the implementation of
- * {@link #onTick(long)} takes an amount of time to execute that is significant
- * compared to the countdown interval.
- */
- public abstract class CountDownTimer {
-
- /**
- * Millis since epoch when alarm should stop.
- */
- private final long mMillisInFuture;
-
- /**
- * The interval in millis that the user receives callbacks
- */
- private final long mCountdownInterval;
-
- private long mStopTimeInFuture;
-
- /**
- * @param millisInFuture The number of millis in the future from the call
- * to {@link #start()} until the countdown is done and {@link #onFinish()}
- * is called.
- * @param countDownInterval The interval along the way to receive
- * {@link #onTick(long)} callbacks.
- */
- public CountDownTimer(long millisInFuture, long countDownInterval) {
- mMillisInFuture = millisInFuture;
- mCountdownInterval = countDownInterval;
- }
-
- /**
- * Cancel the countdown.
- */
- public final void cancel() {
- mHandler.removeMessages(MSG);
- }
-
- /**
- * Start the countdown.
- */
- public synchronized final CountDownTimer start() {
- if (mMillisInFuture <= 0) {
- onFinish();
- return this;
- }
- mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
- mHandler.sendMessage(mHandler.obtainMessage(MSG));
- return this;
- }
-
-
- /**
- * Callback fired on regular interval.
- * @param millisUntilFinished The amount of time until finished.
- */
- public abstract void onTick(long millisUntilFinished);
-
- /**
- * Callback fired when the time is up.
- */
- public abstract void onFinish();
-
-
- private static final int MSG = 1;
-
-
- // handles counting down
- private Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
-
- synchronized (CountDownTimer.this) {
- final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
-
- if (millisLeft <= 0) {
- onFinish();
- } else if (millisLeft < mCountdownInterval) {
- // no tick, just delay until done
- sendMessageDelayed(obtainMessage(MSG), millisLeft);
- } else {
- long lastTickStart = SystemClock.elapsedRealtime();
- onTick(millisLeft);
-
- // take into account user‘s onTick taking time to execute
- long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
-
- // special case: user‘s onTick took more than interval to
- // complete, skip to next interval
- while (delay < 0) delay += mCountdownInterval;
-
- sendMessageDelayed(obtainMessage(MSG), delay);
- }
- }
- }
- };
- }
所以,如果你的程序需要执行一些周期性的任务,就可以考虑使用CountDownTimer这个类了。需要注意的是,在上面的这个例子中,最后显示时间是1,也就是说其实上执行了29次。所以这个地方一定要注意,如果你的任务次数是n,那么设置的时候一定要注意设置成n+1的时间。
最后,欢迎大家评论交流,谢谢。
Android 关于倒计时功能的说说
标签:
原文地址:http://www.cnblogs.com/dongweiq/p/4290351.html