Timertask หรือ Handler


104

สมมติว่าฉันต้องการดำเนินการบางอย่างทุกๆ 10 วินาทีและไม่จำเป็นต้องอัปเดตมุมมอง

คำถามคือจะดีกว่าไหม (ฉันหมายถึงมีประสิทธิภาพและประสิทธิผลมากกว่า) ในการใช้ตัวจับเวลากับ timertask ดังนี้:

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);
}

หรือเป็นเพียงตัวจัดการที่มีการล่าช้าภายหลัง

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

นอกจากนี้ฉันจะขอบคุณหากคุณสามารถอธิบายได้ว่าเมื่อใดควรใช้วิธีใดและทำไมหนึ่งในนั้นจึงมีประสิทธิภาพมากกว่าอีกวิธีหนึ่ง (ถ้าเป็นจริง)


2
ฉันได้อ่านโพสต์มากมายเกี่ยวกับพฤติกรรมที่ผิดปกติของ TimerTasks คำแนะนำของฉันจะหลีกเลี่ยงพวกเขาและใช้วิธีการจัดการ / postDelayed
Sound Conception

1
ฉันต้องการวิธี Handler-postDelay - คุณสามารถควบคุมได้มากกว่าและกำหนดเวลาจากภายใน
mihail

1
นี่คือแหล่งข้อมูลที่ยอดเยี่ยมสำหรับTimer vs. Handler
CodyF

TimerTask เป็นงานเบื้องหลังดังนั้นคุณจึงไม่สามารถอัปเดต UI ได้ แค่บอกว่า ...
Yousha Aleayoub

1
ทำงานให้ฉัน.. ขอบคุณ
jyotsna

คำตอบ:


97

Handlerดีกว่าTimerTask.

ทั้ง Java TimerTaskและ Android Handlerช่วยให้คุณสามารถกำหนดเวลางานล่าช้าและซ้ำ ๆ กับเธรดพื้นหลังได้ อย่างไรก็ตามวรรณกรรมโด่งแนะนำให้ใช้Handlerมากกว่าTimerTaskใน Android (ดูที่นี่ , ที่นี่ , ที่นี่ , ที่นี่ , ที่นี่และที่นี่ )

ปัญหาบางอย่างที่รายงานเกี่ยวกับ TimerTask ได้แก่ :

  • ไม่สามารถอัปเดตเธรด UI
  • หน่วยความจำรั่ว
  • ไม่น่าเชื่อถือ (ไม่ได้ผลเสมอไป)
  • งานที่ดำเนินการเป็นเวลานานอาจรบกวนเหตุการณ์ที่กำหนดไว้ถัดไป

ตัวอย่าง

แหล่งที่ดีที่สุดสำหรับทุกชนิดของตัวอย่าง Android ที่ฉันได้เห็นที่Codepath นี่คือHandlerตัวอย่างจากที่นั่นสำหรับงานที่ทำซ้ำ

// 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);

ที่เกี่ยวข้อง


6
@ รีรอไม่ GC ควรดูแลมัน แต่คุณต้องดูแล runnable ที่โพสต์ไว้สำหรับการดำเนินการที่ล่าช้า ในตัวอย่างด้านบน runnable ที่ใช้เป็นอินสแตนซ์คลาสภายในดังนั้นจึงมีการอ้างอิงโดยนัยไปยังคลาสที่มี (ซึ่งอาจเป็นกิจกรรม) runnable จะอยู่ในคิวข้อความของ looper ที่เกี่ยวข้องของตัวจัดการจนกว่าจะถึงเวลาดำเนินการครั้งต่อไปซึ่งอาจเกิดขึ้นหลังจากบริบทไม่ถูกต้องและอาจรั่วไหลของอินสแตนซ์คลาสที่มี คุณสามารถล้างข้อมูลอ้างอิงดังกล่าวได้โดยใช้mHandler.removeCallbacks(runnableCode)ในเวลาที่เหมาะสม (เช่นonStop()สำหรับกิจกรรม)
bitbybit

7
วิธีการนำเสนอข้อมูลอ้างอิงที่ดีที่สุด !!! (ดูที่นี่ที่นี่ที่นี่ที่นี่ที่นี่และที่นี่)
iRavi iVooda

และถ้าฉันต้องการใช้สิ่งนั้นภายใน ViewModel ล่ะ? ไม่ได้ต่อต้านอุดมคติของการไม่มีสิ่ง Android ที่นั่น?
desgraci

@desgraci ฉันไม่ได้ใช้ ViewModel แต่จากเอกสารฉันเห็นเพียงว่า ViewModel ไม่ควรเข้าถึงลำดับชั้นของมุมมองหรือมีการอ้างอิงถึงกิจกรรมหรือส่วนย่อย ฉันไม่เห็นสิ่งใดที่ห้ามไม่ให้มี "Android Things" โดยทั่วไป
Suragch

ณ วันนี้การอ้างอิงเหล่านั้นเป็นข้อมูลที่ล้าสมัยและไม่มีข้อมูลเพียงพอที่จะนำมาพิจารณา ข้อเสียที่ระบุไว้ 4 ข้อนั้นจะเกิดขึ้นจริงก็ต่อเมื่อคุณตั้งโปรแกรมโค้ดไม่ดี TimerTasks ยังคงเป็นตัวเลือกที่ดีมากหากคุณต้องการเรียกใช้บางสิ่งในพื้นหลังเป็นระยะ ๆ และในที่สุดก็เรียกใช้บางสิ่งบน UIThread หากมีเงื่อนไขบางประการ
เดวิด

18

มีข้อเสียบางประการของการใช้ Timer

สร้างเธรดเดียวเท่านั้นเพื่อดำเนินการกับภารกิจและหากงานใช้เวลารันนานเกินไปงานอื่น ๆ จะต้องทนทุกข์ทรมาน ไม่จัดการข้อยกเว้นที่เกิดจากงานและเธรดเพียงแค่ยุติซึ่งส่งผลกระทบต่องานตามกำหนดเวลาอื่น ๆ และจะไม่รัน

คัดลอกมาจาก:

TimerTask vs Thread.sleep vs Handler postDelayed - ถูกต้องที่สุดในการเรียกใช้ฟังก์ชันทุก ๆ N มิลลิวินาที?


6
แล้วสำหรับงาน one-shot ล่ะ? ดูเหมือนว่า Timer อาจจะดีกว่าสำหรับสิ่งนั้นเพราะคุณไม่มีเหนือศีรษะของคิวข้อความ?
Michael

2
ฉันเดาว่าเราจะไม่มีทางรู้
Denny

6

คำตอบที่ยอมรับเวอร์ชัน Kotlin:

val handler = Handler()

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

handler.post(runnableCode)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.