Bài viết này sẽ hướng dẫn bạn cách triển khai một đối tượng CountDownTimer
trong Android, kết hợp nó với ProgressBar
để tạo ra một bộ đếm ngược trực quan và thân thiện. Chúng ta sẽ xây dựng một thành phần hữu ích, đặc biệt phù hợp cho các ứng dụng Quiz, nơi việc hiển thị thời gian còn lại một cách đồ họa có thể cải thiện đáng kể UX.
Android CountDownTimer
Lớp Android CountDownTimer
cho phép chúng ta lên lịch một bộ đếm ngược đến một thời điểm trong tương lai do người dùng định nghĩa, cùng với các thông báo định kỳ trong suốt quá trình. Đây là một abstract class
, đòi hỏi bạn phải ghi đè các phương thức của nó để triển khai trong dự án. Bạn cần thêm dòng sau vào Activity của mình để nhập lớp:
import android.os.CountDownTimer;
Các phương thức quan trọng của lớp CountDownTimer
bao gồm:
synchronized final void cancel()
: Phương thức này hủy bỏ bộ đếm ngược.abstract void onFinish()
: Phương thức callback này kích hoạt khi bộ đếm giờ kết thúc.abstract void onTick(long millisUntilFinished)
: Phương thức callback này kích hoạt theo các khoảng thời gian đều đặn. Tham sốmillisUntilFinished
cung cấp số mili giây còn lại cho đến khi bộ đếm kết thúc.synchronized final CountDownTimer start()
: Phương thức này dùng để bắt đầu bộ đếm ngược.
Chữ ký của constructor công khai của lớp CountDownTimer
là:
CountDownTimer(long millisInFuture, long countDownInterval)
Các tham số của constructor được định nghĩa như sau:
millisInFuture
: Số mili giây từ thời điểm gọistart()
cho đến khi bộ đếm ngược hoàn tất và phương thứconFinish()
được gọi.countDownInterval
: Khoảng thời gian (tính bằng mili giây) để nhận các callbackonTick(long)
.
Trong dự án này, chúng ta sẽ cập nhật các giá trị thời gian trong một ProgressBar
mỗi khi phương thức onTick()
được gọi lặp đi lặp lại.
Cấu trúc dự án Android countdown timer đơn Giản
Cấu trúc dự án của chúng ta khá đơn giản, bao gồm một tệp layout XML và một tệp Java cho Activity chính.
Tệp activity_main.xml
chứa hai nút (Button
) là “Start Timer” và “Stop Timer”, cùng với một ProgressBar
để hiển thị thời gian.
<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
xmlns:tools="<https://schemas.android.com/tools>" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="false"
android:max="10"
android:minHeight="50dp"
android:minWidth="200dp"
android:progress="0"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Timer"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="61dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop Timer"
android:id="@+id/button2"
android:layout_centerHorizontal="true"
android:layout_marginTop="46dp"
android:layout_below="@+id/progressBar" />
</RelativeLayout>
Dưới đây là mã nguồn cho MainActivity.java
:
package com.journaldev.countdowntimer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView; // Not used in this specific code, but often included.
public class MainActivity extends AppCompatActivity {
ProgressBar progressBar;
Button start_timer,stop_timer;
MyCountDownTimer myCountDownTimer; // Khai báo đối tượng CountDownTimer của chúng ta
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Ánh xạ các thành phần UI từ layout
progressBar=(ProgressBar)findViewById(R.id.progressBar);
start_timer=(Button)findViewById(R.id.button);
stop_timer=(Button)findViewById(R.id.button2);
// Thiết lập OnClickListener cho nút "Start Timer"
start_timer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Khởi tạo CountDownTimer với 10 giây (10000ms) và cập nhật mỗi 1 giây (1000ms)
myCountDownTimer = new MyCountDownTimer(10000, 1000);
myCountDownTimer.start(); // Bắt đầu bộ đếm ngược
}
});
// Thiết lập OnClickListener cho nút "Stop Timer"
stop_timer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Hủy bỏ bộ đếm ngược
if (myCountDownTimer != null) { // Đảm bảo đối tượng đã được khởi tạo
myCountDownTimer.cancel();
}
}
});
}
// Định nghĩa lớp MyCountDownTimer kế thừa từ CountDownTimer
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval); // Gọi constructor của lớp cha
}
@Override
public void onTick(long millisUntilFinished) {
// Phương thức này kích hoạt mỗi khi có một "tick"
int progress = (int) (millisUntilFinished/1000); // Chuyển đổi mili giây sang giây
// Cập nhật ProgressBar. Để hiển thị tiến độ tăng dần, chúng ta lấy giá trị max trừ đi thời gian còn lại.
progressBar.setProgress(progressBar.getMax()-progress);
}
@Override
public void onFinish() {
// Phương thức này kích hoạt khi bộ đếm ngược kết thúc
finish(); // Đóng Activity hiện tại
}
}
}
Trong đoạn mã trên, chúng ta định nghĩa một lớp MyCountDownTimer
là một lớp con (inner class) kế thừa từ CountDownTimer
. Trong ví dụ này, chúng ta đặt một bộ đếm thời gian 10 giây và cập nhật nó sau mỗi giây. Theo mặc định, CountDownTimer
hiển thị/cập nhật thời gian theo thứ tự giảm dần (đúng như tên gọi của nó là CountDown!). Do đó, để hiển thị tiến độ tăng dần trên ProgressBar
, chúng ta lấy giá trị progressBar.getMax()
trừ đi thời gian còn lại đã chuyển đổi. Lưu ý rằng, khi bộ đếm dừng, nếu bạn khởi động lại, nó sẽ bắt đầu từ đầu.
Kết luận
Như vậy, chúng ta đã cùng nhau tìm hiểu và triển khai thành công một bộ đếm ngược trong Android sử dụng CountDownTimer
và ProgressBar
. Bạn đã nắm vững cách định nghĩa tổng thời gian đếm ngược (millisInFuture
), khoảng thời gian cập nhật (countDownInterval
), và xử lý các sự kiện onTick()
cũng như onFinish()
. Khả năng tùy chỉnh hiển thị thông qua ProgressBar
mở ra nhiều ứng dụng thực tế, từ việc hiển thị thời gian còn lại trong các bài kiểm tra trắc nghiệm, các màn chơi trong game, đến việc tạo ra các bộ hẹn giờ tập luyện hay nhắc nhở công việc hàng ngày.