Android: ฉันควรใช้ Handler () เมื่อใดและควรใช้ Thread เมื่อใด


129

เมื่อฉันต้องการบางสิ่งบางอย่างเพื่อให้ทำงานแบบอะซิงโครนัสเช่นงานที่ทำงานเป็นเวลานานหรือตรรกะที่ใช้เครือข่ายหรือไม่ว่าด้วยเหตุผลใดก็ตามการเริ่มเธรดใหม่และเรียกใช้งานจะทำงานได้ดี การสร้างHandlerและเรียกใช้งานได้เช่นกัน อะไรคือความแตกต่าง? ฉันควรใช้แต่ละตัวเมื่อใด ข้อดี / เหตุผลในการใช้ a Handlerและ not a Threadคืออะไร?

PS - AsyncTaskเพื่อประโยชน์ของคำถามนี้ขอไม่สนใจ - Handler().postDelayedกรณีการใช้งานเป็นเรื่องที่ชัดเจนสำหรับฉันสำหรับคำถามนี้สมมติว่าฉันต้องการให้งานเริ่มทันที


ในสถานการณ์ของคุณเพียงแค่ดำเนินการไปข้างหน้าและใช้ Thread ใหม่คำแนะนำต่อไปของฉันคือ AsyncTask แต่นั่นไม่ใช่สิ่งที่คุณต้องการอย่างชัดเจน ตัวจัดการส่วนใหญ่จะใช้ในกรณีที่คุณต้องการเพิ่มการหน่วงเวลาหรือการปรับแต่งประเภทอื่นให้กับ runnable
kabuto178

1
@ kabuto178 ยังมีประโยชน์อื่น ๆ ของตัวจัดการที่ควรค่าแก่การกล่าวถึงที่คุณข้ามไป เช่นสามารถโต้ตอบกับเธรด UI จากเธรดที่แยกต่างหาก ..
tony9099

คำตอบ:


168

หากสิ่งที่คุณทำคือ "หนัก" คุณควรทำในเธรด หากคุณไม่ได้เริ่มอย่างชัดเจนในเธรดของตัวเองเธรดนั้นจะทำงานบนเธรดหลัก (UI) ซึ่งอาจสังเกตได้ว่าผู้ใช้ของคุณกระวนกระวายใจหรือตอบสนองช้า

สิ่งที่น่าสนใจเมื่อคุณใช้เธรดการใช้ Handler เป็นวิธีการสื่อสารระหว่างเธรดงานที่คุณกำลังเริ่มต้นและเธรดหลักมักจะมีประโยชน์

การโต้ตอบของ Thread / Handler โดยทั่วไปอาจมีลักษณะดังนี้:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

โดยทั่วไปแล้วสิ่งที่นำกลับบ้านคือคุณควรใช้เธรดทุกครั้งที่คุณทำงานบางอย่างที่อาจใช้งานได้นานหรือเร่งรัดมาก (เช่นเครือข่ายอะไรก็ได้ไฟล์ IO เลขคณิตหนัก ฯลฯ )


ขอบคุณสำหรับการตอบกลับอย่างรวดเร็วและระยะเวลาที่ลงทุน (และความเร็วในการตอบกลับของคุณ !!)! ให้ฉันดูว่าฉันได้รับสิ่งนี้หรือไม่: Handler ได้รับการออกแบบมาเพื่ออำนวยความสะดวกในการสื่อสารแบบไม่ปิดกั้นระหว่างเธรดของผู้ปฏิบัติงานและเธรด UI
JRun

3
@JRun นั่นคือหนึ่งในการใช้งานใช่ ตรวจสอบคำอธิบายตัวจัดการในเอกสาร javaสำหรับข้อมูลที่ดีเกี่ยวกับเรื่องนี้ รวมถึงการใช้งานอื่น ๆ (เพื่อกำหนดเวลาข้อความและ runnables ที่จะดำเนินการเป็นบางประเด็นในอนาคต)
FoamyGuy

อธิบายอย่างดี @FoamyGuy!
tony9099

สวัสดีรับประกันว่าupdateUI()จะทำงานหลังจากonCreateView(หลังจากโหลดมุมมองใหม่แล้ว)?
Zyoo

1
เป็นเพราะmessage.what()อะไร? มันจะไม่ใช่if(msg == 0){เหรอ? ขอบคุณมาก! :)
Ruchir Baronia

64

Handler และ Thread เป็น 2 สิ่งที่แตกต่างกันจริงๆ

ต้องสร้างเธรดเพื่อรันงานที่รันเป็นเวลานาน

Handler เป็นออบเจ็กต์ที่สะดวกมากในการสื่อสารระหว่าง 2 เธรด (ตัวอย่างเช่นเธรดพื้นหลังจำเป็นต้องอัปเดต UI คุณสามารถใช้ Handler เพื่อโพสต์ Runnable จากเธรดพื้นหลังของคุณไปยังเธรด UI)

คุณจึงไม่มีทางเลือกระหว่าง Handler หรือ Thread ใช้ด้ายยยยยงานหนัก! (คุณสามารถใช้ Handler ได้หากเธรดพื้นหลังของคุณจะทริกเกอร์งานบางอย่างที่ต้องทำในเธรดอื่นซึ่งส่วนใหญ่เป็นเธรด UI)


ขอบคุณสำหรับการตอบกลับอย่างรวดเร็วและระยะเวลาที่ลงทุน (และความเร็วในการตอบกลับของคุณ !!)!
JRun

28

HandlerและThreadเป็นสองสิ่งที่แตกต่างกัน แต่ไม่ขัดแย้งกัน คุณสามารถมีHandlerและ a Threadในเวลาเดียวกันและจริงๆแล้วแต่ละรายการHandlerจะต้องทำงานในไฟล์Thread.

สำหรับรายละเอียดเพิ่มเติมที่คุณอาจต้องการตรวจสอบบทความนี้

ป้อนคำอธิบายภาพที่นี่


19

Handlerวิ่งบนเดียวกันThreadที่Threadวิ่งในหัวข้อที่แตกต่างกัน

ใช้ Handler หากคุณต้องการเรียกใช้บางสิ่งในเธรดเดียวกันโดยปกติจะเป็นองค์ประกอบ GUI หรืออะไรทำนองนั้น

ใช้ด้ายถ้าคุณต้องการที่จะให้ฟรีหัวข้อหลักที่จะทำสิ่งอื่นใช้สิ่งนี้สำหรับสิ่งที่ต้องใช้เวลามาก


6
เหตุใดฉันจึงควรใช้ตัวจัดการหากฉันต้องการเรียกใช้บางสิ่งในเธรดเดียวกัน จุดประสงค์ของวิธี mHandler.post (... ) คืออะไร?
Elias

1
ในกรณีนี้ Elias คุณอาจใช้ตัวจัดการถ้าคุณต้องการให้งานบางอย่างทำงานหลังจากผ่านไประยะหนึ่งหรือทำซ้ำงานทุกๆ X ระยะเวลา หากคุณไม่ต้องการใช้สิ่งเหล่านี้คุณมีสิทธิ์ ไม่สมควรใช้ตัวจัดการ คุณสามารถทำสิ่งต่างๆของ GUI ได้ที่นั่นจากนั้น bcoz คุณอยู่ในเธรด UI อย่างไรก็ตามตัวจัดการทำงานบนเธรดที่สร้างขึ้น
tony9099

14

ตัวจัดการเป็นวิธีที่ดีที่สุดในการสื่อสารระหว่างพื้นหลังและเธรด UI โดยทั่วไปตัวจัดการจะเชื่อมโยงกับคิวข้อความของเธรดและใช้เพื่อส่งข้อความและรันไปยังข้อความได้

ใช้:

เธรด:ในการทำงานในเธรด saperate (พื้นหลัง) มากกว่าเธรด UI (ช่วยปลดบล็อกเธรด UI)

Handlerใช้เพื่อสื่อสารระหว่าง UI และเธรดพื้นหลัง

ลองดูบทความนี้


4

หากคุณต้องการอัพเดตอินเทอร์เฟซผู้ใช้จากเธรดใหม่คุณต้องซิงโครไนซ์กับเธรดอินเทอร์เฟซผู้ใช้

คุณสามารถใช้คลาส android.os.Handler หรือคลาส AsyncTasks สำหรับสิ่งนี้

คลาส Handler สามารถอัพเดตอินเทอร์เฟซผู้ใช้ Handler จัดเตรียมวิธีการรับอินสแตนซ์ของคลาส Message หรือ Runnable

เธรดคุณสามารถโพสต์ข้อความผ่านเมธอด sendMessage (Message msg) หรือผ่านเมธอด sendEmptyMessage ()

... ดูข้อมูลเพิ่มเติมเกี่ยวกับเธรด ฯลฯที่นี่ (รวมถึงการสร้างคำอธิบายสำหรับกลไกเธรดและการซิงค์ที่แตกต่างกันและเมื่อใดควรใช้อะไร)


ขอขอบคุณที่สละเวลาตอบคำถามของฉัน ฉันชอบบล็อกของ Lars Vogel เป็นข้อมูลเชิงลึกและง่ายต่อการติดตาม ขอบคุณ!
JRun

2

ข้อดี / เหตุผลในการใช้ Handler ไม่ใช่ Thread คืออะไร?

Handlerช่วยให้คุณส่งข้อความและกระบวนการและวัตถุที่เกี่ยวข้องกับของด้ายRunnable MessageQueueแต่ละHandlerอินสแตนซ์เชื่อมโยงกับเธรดเดียวและคิวข้อความของเธรดนั้น

เมื่อคุณสร้างใหม่Handlerจะถูกผูกไว้กับเธรด / คิวข้อความของเธรดที่กำลังสร้างเธรด - จากจุดนั้นเป็นต้นไปมันจะส่งข้อความและ runnables ไปยังคิวข้อความนั้นและดำเนินการตามที่ออกมาจากคิวข้อความ .

การใช้งานหลัก ๆ สองประการสำหรับ Handler:

  1. เพื่อกำหนดเวลาข้อความและRunnablesที่จะดำเนินการเป็นบางประเด็นในอนาคต
  2. เพื่อจัดคิวการดำเนินการกับเธรดอื่นที่ไม่ใช่ของคุณเอง

หากคุณใช้เธรด java คุณต้องจัดการบางอย่างด้วยตัวคุณเองเช่นการซิงโครไนซ์กับเธรดหลักการยกเลิกเธรดเป็นต้น

เธรดเดี่ยวนี้ไม่ได้สร้างเธรดพูลเว้นแต่คุณจะใช้ThreadPoolExecutorหรือExecutorServiceAPI

(นำคำถามนี้มาจากความคิดเห็นของคุณเกี่ยวกับคำตอบของ Blackbelt)

ทำไมไม่ใช้ Executor? และแม้ว่าฉันต้องการใช้ Handler เพื่อทำสิ่งนั้นอย่างไร

อ้างอิง: บทความประสิทธิภาพของเธรด

มีงานบางประเภทที่สามารถลดลงเป็นงานแบบกระจายขนานกันได้มาก ด้วยจำนวนแพ็คเก็ตงานที่แท้จริงสิ่งนี้จะสร้างขึ้นAsyncTaskและHandlerThreadไม่ใช่คลาสที่เหมาะสม ลักษณะเธรดเดียวAsyncTaskจะเปลี่ยนงานที่ทำเกลียวทั้งหมดให้เป็นระบบเชิงเส้น ในทางกลับกันการใช้HandlerThreadคลาสจะต้องให้โปรแกรมเมอร์จัดการโหลดบาลานซ์ระหว่างกลุ่มเธรดด้วยตนเอง

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

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

คุณสามารถดูบทความคู่มือสำหรับนักพัฒนาเกี่ยวกับcreate-threadpoolสำหรับรายละเอียดเพิ่มเติม

ดูโพสต์นี้สำหรับการใช้งานHandlerเพื่อเรียกใช้อินสแตนซ์ Runnable หลายรายการ ในกรณีนี้Runnableงานทั้งหมดจะทำงานในเธรดเดียว

Android: ปิ้งในกระทู้


1

Handlerสามารถใช้ร่วมกับThreadเพื่อสร้างกลไกที่อยู่ในคิวได้ คุณสามารถใช้handlerเพื่อโพสต์บางสิ่งในไฟล์Thread Looper


ขอขอบคุณที่สละเวลาตอบคำถามของฉัน ทำไมไม่ใช้ Executor? และแม้ว่าฉันต้องการใช้ Handler เพื่อทำสิ่งนั้นอย่างไร
JRun

ตัวดำเนินการแตกต่างกันเล็กน้อย ในการใช้งานคุณต้องขยายเธรดและในการรันเรียกการจัดเตรียม static.metohd ของคลาส Looper หลังจากที่คุณเรียกใช้เมธอดแบบคงที่คิวจะถูกสร้างขึ้นและคุณสามารถใช้คำสั่ง handlerbin เพื่อส่งต่อคำขอและรับผลลัพธ์กลับ
Blackbelt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.