Timertask hoặc Handler


103

Giả sử rằng tôi muốn thực hiện một số hành động cứ sau 10 giây và không nhất thiết phải cập nhật chế độ xem.

Câu hỏi đặt ra là: có tốt hơn không (ý tôi là hiệu quả và hiệu quả hơn) để sử dụng bộ đếm thời gian với thời gian như sau:

final Handler handler = new Handler();

TimerTask timertask = new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            public void run() {
               <some task>
            }
        });
    }
};
timer = new Timer();
timer.schedule(timertask, 0, 15000);
}

hoặc chỉ là một trình xử lý với thời gian trễ

final Handler handler = new Handler(); 
final Runnable r = new Runnable()
{
    public void run() 
    {
        <some task>
    }
};
handler.postDelayed(r, 15000);

Ngoài ra, tôi sẽ rất biết ơn nếu bạn có thể giải thích khi nào nên sử dụng cách tiếp cận nào và tại sao một trong số chúng hiệu quả hơn cách tiếp cận khác (nếu nó thực sự là như vậy).


2
Tôi đã đọc nhiều bài đăng về hành vi bất thường của TimerTasks. Lời khuyên của tôi sẽ rõ ràng hơn về chúng và sử dụng phương pháp xử lý / postDelayed.
âm thanh

1
Tôi muốn phương pháp Handler-postDelay - bạn có quyền kiểm soát nhiều hơn và bạn sắp xếp nó từ bên trong
Mihail

1
Đây là một nguồn tuyệt vời cho hẹn giờ so với Handler
CodyF

TimerTask là một nhiệm vụ nền, vì vậy bạn không thể cập nhật giao diện người dùng. Chỉ cần nói ...
Yousha Aleayoub

1
đã làm việc cho tôi..cảm ơn
jyotsna

Câu trả lời:


96

Handlerlà tốt hơn TimerTask.

Cả Java TimerTaskvà Android Handlerđều cho phép bạn lên lịch các tác vụ bị trì hoãn và lặp lại trên các luồng nền. Tuy nhiên, các tài liệu khuyến nghị sử dụng Handlerover TimerTasktrong Android (xem tại đây , đây , đây , đây , đâyđây ).

Một số sự cố được báo cáo với TimerTask bao gồm:

  • Không thể cập nhật chuỗi giao diện người dùng
  • Rò rỉ bộ nhớ
  • Không đáng tin cậy (không phải lúc nào cũng hoạt động)
  • Các nhiệm vụ đang chạy dài có thể ảnh hưởng đến sự kiện đã lên lịch tiếp theo

Thí dụ

Nguồn tốt nhất cho tất cả các loại ví dụ Android mà tôi đã thấy là tại Codepath . Đây là một Handlerví dụ từ đó cho một nhiệm vụ lặp lại.

// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
      // Do something here on the main thread
      Log.d("Handlers", "Called on main thread");
      // Repeat this the same runnable code block again another 2 seconds
      handler.postDelayed(runnableCode, 2000);
    }
};
// Start the initial runnable task by posting through the handler
handler.post(runnableCode);

Có liên quan


6
@Reek Không, GC nên giải quyết vấn đề đó. Nhưng bạn cần quan tâm đến việc đăng có thể chạy được để thực thi bị trì hoãn. Trong ví dụ trên, runnable được sử dụng là một cá thể lớp bên trong để chứa một tham chiếu ngầm định đến lớp chứa (có thể là một hoạt động). Runnable sẽ ở trong hàng đợi thông báo của trình lặp liên kết của trình xử lý cho đến thời gian thực thi tiếp theo của nó, có thể là sau khi ngữ cảnh không hợp lệ và có thể làm rò rỉ cá thể lớp chứa. Bạn có thể xóa các tham chiếu đó bằng cách sử dụng mHandler.removeCallbacks(runnableCode)vào thời điểm thích hợp (ví dụ: onStop()cho một hoạt động).
bitbybit

7
Cách trình bày tài liệu tham khảo tốt nhất từ ​​trước đến nay !!! (xem đây, đây, đây, đây, đây, và đây).
iRavi iVooda

và nếu tôi muốn sử dụng nó bên trong ViewModel thì sao? không chống lại lý tưởng không có những thứ Android ở đó?
desgraci

@desgraci, tôi chưa sử dụng ViewModel, nhưng từ tài liệu, tôi chỉ thấy rằng nó cho biết ViewModel không nên truy cập phân cấp chế độ xem hoặc chứa tham chiếu đến Activity hoặc Fragment. Tôi không thấy bất cứ điều gì cấm có "những thứ Android" nói chung.
Suragch

Cho đến ngày nay, những tài liệu tham khảo đó đối với tôi là lỗi thời và không đủ thông tin để được xem xét. 4 nhược điểm được liệt kê đó chỉ thực sự nếu bạn lập trình mã của mình không tốt. TimerTasks vẫn là một lựa chọn rất tốt nếu bạn muốn chạy định kỳ thứ gì đó trong nền và cuối cùng chạy thứ gì đó trên UIThread nếu một số điều kiện áp dụng.
David

18

Có một số nhược điểm của việc sử dụng Bộ hẹn giờ

Nó chỉ tạo một luồng duy nhất để thực thi các tác vụ và nếu một tác vụ mất quá nhiều thời gian để chạy, các tác vụ khác sẽ bị ảnh hưởng. Nó không xử lý các ngoại lệ do các tác vụ ném ra và luồng chỉ kết thúc, điều này ảnh hưởng đến các tác vụ đã lên lịch khác và chúng không bao giờ được chạy

Được sao chép từ:

TimerTask vs Thread.sleep vs Handler postDelayed - chính xác nhất để gọi hàm mỗi N mili giây?


6
vậy đối với nhiệm vụ one-shot thì sao? Có vẻ như Timer tốt hơn cho điều đó vì bạn không có chi phí của hàng đợi tin nhắn?
Michael

2
Tôi đoán chúng ta sẽ không bao giờ biết
Denny

6

Phiên bản Kotlin của câu trả lời được chấp nhận:

val handler = Handler()

val runnableCode = object : Runnable {
    override fun run() {
       Log.d("Handlers", "Called on main thread")
       handler.postDelayed(this, 2000)
    }
}

handler.post(runnableCode)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.