ตัวจัดการ vs AsyncTask กับเธรด [ปิด]


382

ผมสับสนเล็กน้อยเกี่ยวกับความแตกต่างระหว่างHandlers, AsyncTaskและThreadsใน Android ฉันอ่านบล็อกและคำถามไม่กี่ที่นี่ใน StackOverflow

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

AsyncTaskที่จริงแล้วมันคล้ายกันHandlerแต่ใช้ไม่ได้ในเธรด UI ดังนั้นจึงเป็นการดีสำหรับการดึงข้อมูลเช่นดึงข้อมูลบริการเว็บ หลังจากนั้นคุณสามารถโต้ตอบกับ UI

Threadแต่ไม่สามารถโต้ตอบกับ UI ได้ แต่ให้เธรดขั้นพื้นฐาน "มากขึ้นและคุณจะพลาดภาพนามธรรมAsyncTaskทั้งหมด

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

ในขณะเดียวกันเอกสารได้รับการปรับปรุงอย่างมาก



9
"ตัวจัดการเป็นเธรดพื้นหลัง" - คำตอบที่ได้รับคะแนนสูงสุดบางคำดูเหมือนจะไปในทิศทางนั้นเช่นกัน แต่นั่นเป็นความเข้าใจผิด A Handlerไม่ใช่เธรดและไม่ดำเนินการใด ๆ เป็นเพียงวิธีการส่งต่อข้อความจากเธรดหนึ่งไปยังคิวข้อความของเธรดอื่นอย่างปลอดภัย ดังนั้นโดยปกติ (อย่างน้อย) สองเธรดต้องยังคงถูกสร้างซึ่งสามารถใช้ตัวจัดการได้ แต่ตัวจัดการไม่สามารถดำเนินการอะไรได้เอง
JimmyB

คำตอบ:


57

ในขณะที่การสอนการประมวลผลพื้นหลัง Android กับ Handlers, AsyncTask และ Loadersในเว็บไซต์ Vogella ทำให้:

Handlerระดับสามารถใช้ในการลงทะเบียนเพื่อด้ายและให้ช่องทางที่ง่ายในการส่งข้อมูลไปยังหัวข้อนี้

AsyncTaskระดับความสุนทรีย์ของการสร้างกระบวนการพื้นหลังและการประสานกับหัวข้อหลัก นอกจากนี้ยังรองรับการรายงานความคืบหน้าของงานที่กำลังรันอยู่

และThreadโดยพื้นฐานแล้วองค์ประกอบหลักของมัลติเธรดซึ่งนักพัฒนาซอฟต์แวร์สามารถใช้ได้โดยมีข้อเสียดังต่อไปนี้:

หากคุณใช้ Java threads คุณต้องจัดการข้อกำหนดต่อไปนี้ในรหัสของคุณเอง:

  • การซิงโครไนซ์กับเธรดหลักหากคุณโพสต์ผลลัพธ์กลับไปยังส่วนติดต่อผู้ใช้
  • ไม่มีค่าเริ่มต้นสำหรับการยกเลิกเธรด
  • ไม่มีการรวมเธรดเริ่มต้น
  • ไม่มีค่าเริ่มต้นสำหรับการจัดการการเปลี่ยนแปลงการกำหนดค่าใน Android

และเกี่ยวกับการAsyncTaskเป็นนักพัฒนาซอฟต์แวร์ Android อ้างอิงทำให้มัน:

AsyncTaskช่วยให้สามารถใช้เธรด UI ได้อย่างเหมาะสมและง่ายดาย คลาสนี้อนุญาตให้ดำเนินการพื้นหลังและเผยแพร่ผลลัพธ์บนเธรด UI โดยไม่ต้องจัดการกับเธรดและ / หรือตัวจัดการ

AsyncTaskถูกออกแบบมาให้เป็นคลาสผู้ช่วยรอบ ๆThreadและHandler และไม่ได้เป็นกรอบเธรดทั่วไป AsyncTasks ควรใช้อย่างเหมาะสมสำหรับการดำเนินการสั้น ๆ (ไม่เกินสองสามวินาที) หากคุณต้องการให้เธรดทำงานต่อเนื่องเป็นเวลานานขอแนะนำอย่างยิ่งให้คุณใช้ API ต่างๆที่จัดทำโดยแพ็คเกจ java.util.concurrent เช่น ผู้บริหาร, ThreadPoolExecutor และ FutureTask

อัปเดตพฤษภาคม 2558:ฉันพบชุดการบรรยายที่ยอดเยี่ยมครอบคลุมหัวข้อนี้

นี่คือการค้นหาโดย Google: ดักลาสชามิดท์บรรยายหุ่นยนต์พร้อมกันและการประสาน

นี่คือวิดีโอของการบรรยายครั้งแรกบน YouTube

ทั้งหมดนี้เป็นส่วนหนึ่งของCS 282 (2013): ระบบการเขียนโปรแกรมสำหรับ Androidจากมหาวิทยาลัย Vanderbilt นี่คือเพลย์ลิสต์ของ YouTube

ดูเหมือนว่า Douglas Schmidt จะเป็นอาจารย์ที่ยอดเยี่ยม

สำคัญ:หากคุณอยู่ในจุดที่คุณกำลังพิจารณาที่จะใช้AsyncTaskเพื่อแก้ไขปัญหาเธรดของคุณคุณควรตรวจสอบReactiveX/RxAndroidรูปแบบการเขียนโปรแกรมที่เหมาะสมกว่านี้ก่อน ทรัพยากรที่ดีมากสำหรับการรับภาพรวมคือการเรียนรู้ RxJava 2 สำหรับ Android โดยยกตัวอย่างเช่น


4
ในชุดการบรรยายนั้นลิงก์นี้จะนำคุณไปสู่ตัวอย่างหัวข้อ: youtu.be/4Vue_KuXfCk?t=19m24s
Aggressor

353

หากเราดูซอร์สโค้ดเราจะเห็นAsyncTaskและHandlerเขียนเป็นภาษาจาวาอย่างแท้จริง (มีข้อยกเว้นอยู่บ้าง แต่นั่นไม่ใช่ประเด็นสำคัญ)

ดังนั้นจึงมีความมหัศจรรย์ในไม่มีหรือAsyncTask Handlerคลาสเหล่านี้ทำให้ชีวิตของเราง่ายขึ้นในฐานะนักพัฒนา

ตัวอย่างเช่น: หากโปรแกรม A วิธีการโทร A () วิธี A () สามารถทำงานในเธรดอื่นด้วยโปรแกรม A เราสามารถตรวจสอบได้อย่างง่ายดายด้วยรหัสต่อไปนี้:

Thread t = Thread.currentThread();    
int id = t.getId();

ทำไมเราควรใช้เธรดใหม่สำหรับงานบางอย่าง? คุณสามารถ google มัน ด้วยเหตุผลหลายประการเช่นยกงานหนักทำงานยาว

ดังนั้นสิ่งที่เป็นความแตกต่างระหว่างThread, AsyncTaskและHandler?

AsyncTaskและHandlerเขียนเป็นภาษาจาวา (ใช้ภายในThread) ดังนั้นทุกสิ่งที่เราสามารถทำได้ด้วยHandlerหรือAsyncTaskเราก็สามารถใช้งานได้Threadเช่นกัน

สิ่งที่สามารถHandlerและAsyncTaskจริงๆช่วย?

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

นั่นคือเหตุผลที่เราควรใช้และHandler AsyncTaskคลาสเหล่านี้ทำงานส่วนใหญ่ให้กับเราเราจำเป็นต้องรู้วิธีการที่จะแทนที่

ความแตกต่างระหว่างHandlerและAsyncTaskเป็น: ใช้AsyncTaskเมื่อด้าย Callerเป็นหัวข้อ UI นี่คือเอกสาร Android ที่บอกว่า:

AsyncTask ช่วยให้สามารถใช้เธรด UI ที่เหมาะสมและง่ายดาย คลาสนี้อนุญาตให้ดำเนินการพื้นหลังและเผยแพร่ผลลัพธ์บนเธรด UI โดยไม่ต้องจัดการกับเธรดและ / หรือตัวจัดการ

ฉันต้องการเน้นสองจุด:

1) การใช้เธรด UI อย่างง่ายดาย (ดังนั้นใช้เมื่อเธรดผู้โทรคือเธรด UI)

2) ไม่จำเป็นต้องจัดการกับตัวจัดการ (หมายถึง: คุณสามารถใช้ตัวจัดการแทน AsyncTask แต่ AsyncTask เป็นตัวเลือกที่ง่ายกว่า)

มีหลายสิ่งในโพสต์นี้ที่ฉันยังไม่ได้พูดเช่น: UI Thread คืออะไรหรือทำไมง่ายกว่า คุณต้องรู้วิธีการบางอย่างหลังแต่ละชั้นเรียนและใช้มันคุณจะเข้าใจเหตุผลอย่างสมบูรณ์

@: เมื่อคุณอ่านเอกสาร Android คุณจะเห็น:

ตัวจัดการช่วยให้คุณสามารถส่งและประมวลผลข้อความและวัตถุที่เรียกใช้ที่เชื่อมโยงกับ MessageQueue ของเธรด

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

ซับซ้อน? เพียงจำไว้ว่าHandlerสามารถสื่อสารกับผู้โทรเข้าเธรดได้อย่างปลอดภัย


4
อันที่จริง asynctask ขึ้นอยู่กับการจัดการและอนาคตแท็กดู
สุมิท

AsyncTask เป็นชั้นผู้ช่วยที่สร้างขึ้นบนตัวจัดการและด้าย developer.android.com/reference/android/os/AsyncTask.html ดูเอกสาร "AsyncTask ได้รับการออกแบบให้เป็นคลาสผู้ช่วยรอบ ๆ เธรดและตัวจัดการ" AsyncTask เปิดตัวใน API3 ขณะที่ Handler มีอยู่ตั้งแต่ API1
hjchin

52

หลังจากมองในเชิงลึกแล้วมันจะตรงไปข้างหน้า

AsyncTask:

มันเป็นวิธีที่ง่ายต่อการใช้ด้ายโดยไม่ต้องรู้อะไรเกี่ยวกับรูปแบบด้ายจาวา AsyncTaskให้การเรียกกลับต่าง ๆ ตามเธรดของผู้ปฏิบัติงานและเธรดหลัก

ใช้สำหรับการรอคอยขนาดเล็กดังต่อไปนี้:

  1. ดึงข้อมูลบางอย่างจากบริการบนเว็บและแสดงผ่านโครงร่าง
  2. แบบสอบถามฐานข้อมูล
  3. เมื่อคุณตระหนักว่าการดำเนินการรันจะไม่เกิดขึ้นซ้ำซ้อน

Handler:

เมื่อเราติดตั้งแอปพลิเคชั่นใน Android แล้วมันจะสร้างเธรดสำหรับแอปพลิเคชั่นนั้นเรียกว่า MAIN UI Thread กิจกรรมทั้งหมดทำงานภายในเธรดนั้น โดยกฎโมเดลเธรดเดี่ยวของ Android เราไม่สามารถเข้าถึงองค์ประกอบ UI (บิตแมปมุมมองข้อความ ฯลฯ ) โดยตรงสำหรับเธรดอื่นที่กำหนดไว้ภายในกิจกรรมนั้น

ตัวจัดการช่วยให้คุณสามารถสื่อสารกับเธรด UI จากเธรดพื้นหลังอื่น ๆ สิ่งนี้มีประโยชน์ใน android เนื่องจาก android ไม่อนุญาตให้เธรดอื่นสื่อสารโดยตรงกับ UI ของเธรดได้ ตัวจัดการสามารถส่งและประมวลผลข้อความและวัตถุที่เรียกใช้ได้ที่เกี่ยวข้องกับ MessageQueue ของเธรด แต่ละอินสแตนซ์ของตัวจัดการเกี่ยวข้องกับเธรดเดี่ยวและคิวข้อความของเธรดนั้น เมื่อตัวจัดการใหม่ถูกสร้างขึ้นจะถูกผูกไว้กับคิวเธรด / ข้อความของเธรดที่สร้างขึ้น

มันเหมาะที่สุดสำหรับ:

  1. จะช่วยให้คุณทำการจัดคิวข้อความ
  2. การจัดตารางข้อความ

Thread:

ตอนนี้ได้เวลาพูดคุยเกี่ยวกับเธรด

กระทู้คือพ่อแม่ของทั้งสองและAsyncTask Handlerพวกเขาทั้งภายในใช้ด้ายซึ่งหมายความว่าคุณยังสามารถสร้างรูปแบบของคุณเองด้ายเหมือนAsyncTaskและHandlerแต่ที่ต้องใช้ความรู้ที่ดีของของ Java Multi-Threading การดำเนินงาน


1
AsyncTask API จริง ๆ แล้วเขียนด้วย Futures, Handlers และ Executors ดูซอร์สโค้ด: grepcode.com/file_/repository.grepcode.com/java/ext/…
IgorGanapolsky

22

AsyncTaskจะใช้ในการทำคำนวณพื้นฐานบางอย่างและเผยแพร่ผลให้หัวข้อ UI (มีการอัปเดตความคืบหน้าตัวเลือก) เนื่องจากคุณไม่ได้กังวลกับ UI ดังนั้นจึงเป็น a HandlerหรือThreadดูเหมือนว่าเหมาะสมมากขึ้น

คุณสามารถวางไข่พื้นหลังThreadและส่งข้อความกลับไปที่หัวข้อหลักของคุณโดยใช้ Handler's postวิธี


9

เกลียว

รองรับ Android มาตรฐาน Java กระทู้ คุณสามารถใช้เธรดมาตรฐานและเครื่องมือจากแพ็คเกจ“ java.util.concurrent” เพื่อใส่การกระทำลงในพื้นหลัง ข้อ จำกัด เพียงอย่างเดียวคือคุณไม่สามารถอัปเดต UI โดยตรงจากกระบวนการพื้นหลัง

หากคุณต้องการอัปเดต UI จากงานพื้นหลังคุณต้องใช้คลาสเฉพาะของ Android คุณสามารถใช้คลาส“ android.os.Handler” สำหรับสิ่งนี้หรือคลาส“AsyncTask

ผู้ดำเนินการ

คลาส“ Handler” สามารถอัปเดต UI หมายเลขอ้างอิงให้วิธีการรับข้อความและสำหรับ runnables ในการใช้ตัวจัดการคุณต้อง subclass มันและแทนที่handleMessage()การประมวลผลข้อความ ในการประมวลผลRunableคุณสามารถใช้วิธีที่post();คุณต้องการเพียงหนึ่งอินสแตนซ์ของตัวจัดการในกิจกรรมของคุณ

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

AsyncTask

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

สำหรับข้อมูลเพิ่มเติมคุณสามารถดูลิงค์เหล่านี้

http://mobisys.in/blog/2012/01/android-threads-handlers-and-asynctask-tutorial/

http://www.slideshare.net/HoangNgoBuu/android-thread-handler-and-asynctask


6

Thread:

คุณสามารถใช้งานใหม่Threadสำหรับงานพื้นหลังที่ใช้เวลานานโดยไม่กระทบกับ UI Thread จาก Java Thread คุณไม่สามารถอัปเดต UI Thread ได้

เนื่องจากเธรดทั่วไปไม่มีประโยชน์สำหรับสถาปัตยกรรม Android จึงมีการแนะนำคลาสตัวช่วยสำหรับเธรด

คุณสามารถค้นหาคำตอบสำหรับคำถามของคุณได้ในประสิทธิภาพของเธรดหน้าเอกสารประกอบ

ตัวจัดการ :

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

มีสองวิธีหลักสำหรับHandler:

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

  2. เพื่อจัดคิวการกระทำที่จะดำเนินการในเธรดอื่นนอกเหนือจากของคุณเอง

AsyncTask :

AsyncTaskช่วยให้สามารถใช้เธรด UI ได้อย่างเหมาะสมและง่ายดาย คลาสนี้ช่วยให้คุณสามารถดำเนินการพื้นหลังและเผยแพร่ผลลัพธ์บนเธรด UI โดยไม่ต้องจัดการกับเธรดและ / หรือตัวจัดการ

ข้อเสีย:

  1. ตามค่าเริ่มต้นแอปจะส่งAsyncTaskวัตถุทั้งหมดที่สร้างไปในเธรดเดียว ดังนั้นพวกเขาจึงดำเนินการตามลำดับอนุกรมและ - เช่นเดียวกับเธรดหลัก - แพ็คเก็ตการทำงานที่ยาวเป็นพิเศษสามารถบล็อกคิว เนื่องจากเหตุผลนี้ใช้ AsyncTask กับรายการจับการทำงานที่สั้นกว่า5ms ในระยะเวลา

  2. AsyncTaskวัตถุยังเป็นผู้กระทำผิดที่พบบ่อยที่สุดสำหรับปัญหาการอ้างอิงโดยนัย AsyncTaskวัตถุนำเสนอความเสี่ยงที่เกี่ยวข้องกับการอ้างอิงที่ชัดเจนเช่นกัน

HandlerThread :

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

ThreadPoolExecutor :

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

หากปริมาณงานมีมากขึ้นและโสดHandlerThreadไม่พอคุณก็สามารถทำได้ThreadPoolExecutor

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

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

 HandlerThread handlerThread = new HandlerThread("SocketOperation");
 handlerThread.start();
 Handler requestHandler = new Handler(handlerThread.getLooper());
 requestHandler.post(myRunnable); // where myRunnable is your Runnable object. 

หากคุณต้องการสื่อสารกลับไปยังเธรด UI คุณสามารถใช้ตัวจัดการเพิ่มเติมอีกหนึ่งตัวเพื่อประมวลผลการตอบสนอง

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Foreground task is completed:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

ในของRunnableคุณคุณสามารถเพิ่ม

responseHandler.sendMessage(msg);

รายละเอียดเพิ่มเติมเกี่ยวกับการใช้งานสามารถดูได้ที่นี่:

Android: ขนมปังปิ้งในหัวข้อ


5

ในความคิดเห็นของฉันกระทู้ไม่ได้เป็นวิธีที่มีประสิทธิภาพที่สุดในการทำการเชื่อมต่อซ็อกเก็ต แต่พวกเขาจะให้การทำงานมากที่สุดในแง่ของการใช้งานหัวข้อ ฉันบอกว่าเพราะจากประสบการณ์การใช้งานเธรดเป็นเวลานานทำให้อุปกรณ์มีความร้อนแรงและทรัพยากรเข้มข้น แม้แต่ความเรียบง่ายwhile(true)จะทำให้โทรศัพท์ร้อนขึ้นในเวลาไม่กี่นาที ถ้าคุณบอกว่าการโต้ตอบ UI นั้นไม่สำคัญบางทีอาจAsyncTaskเป็นสิ่งที่ดีเพราะถูกออกแบบมาสำหรับกระบวนการระยะยาว นี่เป็นเพียงความเห็นของฉันเกี่ยวกับมัน

UPDATE

โปรดไม่สนใจคำตอบข้างต้นของฉัน! ฉันตอบคำถามนี้ย้อนกลับไปในปี 2011 เมื่อฉันมีประสบการณ์น้อยใน Android มากกว่าตอนนี้ คำตอบของฉันด้านบนทำให้เข้าใจผิดและถือว่าผิด ฉันออกจากที่นั่นเพราะหลายคนแสดงความคิดเห็นไว้ด้านล่างเพื่อแก้ไขและฉันเรียนรู้บทเรียนของฉัน

มีคำตอบอื่น ๆ ที่ดีกว่าในหัวข้อนี้ แต่อย่างน้อยฉันจะให้คำตอบที่เหมาะสมยิ่งขึ้น ไม่มีอะไรผิดปกติกับการใช้ Java ปกติThread; อย่างไรก็ตามคุณควรระมัดระวังเกี่ยวกับวิธีการใช้งานของคุณเพราะการทำผิดอาจทำให้ตัวประมวลผลมีความเข้มข้นมาก (อาการที่น่าสังเกตมากที่สุดคือ AsyncTaskเหมาะอย่างยิ่งสำหรับงานส่วนใหญ่ที่คุณต้องการรันในพื้นหลัง (ตัวอย่างทั่วไปคือดิสก์ I / O, การโทรเครือข่ายและการโทรฐานข้อมูล) อย่างไรก็ตามAsyncTaskไม่ควรใช้ s สำหรับกระบวนการที่มีความยาวเป็นพิเศษซึ่งอาจต้องดำเนินการต่อหลังจากผู้ใช้ปิดแอปของคุณหรือทำให้อุปกรณ์อยู่ในโหมดสแตนด์บาย ผมจะบอกว่าสำหรับกรณีส่วนใหญ่สิ่งที่ไม่ได้อยู่ในหัวข้อ UI AsyncTaskที่สามารถได้รับการดูแลใน


ขอบคุณมีเหตุผลที่ฉันควรใช้เธรดแทน AsyncTasks หรือไม่ หรือจะแนะนำให้ใช้มันมากกว่านี้อีก?
Alx

9
@AeroDroid ในตัวอย่างของคุณ: "ง่าย ๆ (จริง)" คุณจะตรึง CPU ที่นี่เว้นแต่คุณจะเพิ่มสถานะสลีปในลูป นี่เป็นความจริงของวงวนไม่รู้จบ ถ้าคุณต้องการลดการใช้งาน CPU เนื่องจากโอเวอร์เฮดนี้ให้นอนด้ายเป็นเวลาสองสามมิลลิวินาทีในตอนท้ายของลูป
ข้อผิดพลาด 454

1
@Error 454 - น่าสนใจ! หากคุณต้องเลือกหมายเลขที่เหมาะสมสำหรับเวลานอนหลับมันจะอยู่ระหว่าง 40-80 มิลลิวินาทีหรือไม่
อภิสิทธิ์

6
@Abhijit จากสิ่งที่เกมที่ฉันทำใน SDL เพียงแค่เพิ่ม 10 ms sleep เพื่อลูปก็เพียงพอที่จะลดลงจาก 99% cpu ถึง ~ 0 ในช่วงเวลาที่ไม่ได้ใช้งาน
ข้อผิดพลาด 454

15
ที่จริงdeveloper.android.com/reference/android/os/AsyncTask.htmlกล่าวว่า "AsyncTasks ควรนึกคิดนำมาใช้สำหรับการดำเนินงานระยะสั้น" คุณควรใช้อย่างระมัดระวังเนื่องจากระบบสามารถยกเลิกได้โดยไม่ต้องดำเนินการ!
type-a1pha

5

AsyncTaskถูกออกแบบมาเพื่อดำเนินการไม่เกินสองสามวินาทีในการดำเนินการในพื้นหลัง (ไม่แนะนำสำหรับเมกะไบต์ของการดาวน์โหลดไฟล์จากเซิร์ฟเวอร์หรือคำนวณซีพียูอย่างเข้มข้นเช่นการดำเนินงาน IO ไฟล์) หากคุณต้องการดำเนินการการทำงานที่ยาวนานคุณได้รับคำแนะนำอย่างยิ่งให้ใช้เธรดเนทีฟ java Java ให้คลาสที่เกี่ยวข้องกับเธรดต่างๆเพื่อทำสิ่งที่คุณต้องการ ใช้Handlerเพื่ออัปเดต UI เธรด


2
public class RequestHandler {

    public String sendPostRequest(String requestURL,
                                  HashMap<String, String> postDataParams) {

        URL url;

        StringBuilder sb = new StringBuilder();
        try {
            url = new URL(requestURL);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);


            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(os, "UTF-8"));
            writer.write(getPostDataString(postDataParams));

            writer.flush();
            writer.close();
            os.close();
            int responseCode = conn.getResponseCode();

            if (responseCode == HttpsURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                sb = new StringBuilder();
                String response;
                while ((response = br.readLine()) != null){
                    sb.append(response);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");

            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }

        return result.toString();
    }

}

1

ให้ฉันลองตอบคำถามที่นี่ด้วยตัวอย่าง :) - MyImageSearch [โปรดดูรูปภาพที่นี่ของหน้าจอกิจกรรมหลัก - ที่มีข้อความแก้ไข / ปุ่มค้นหา / มุมมองกริด]

MyImageSearch

คำอธิบายของ MyImageSearch - เมื่อผู้ใช้ป้อนรายละเอียดในฟิลด์แก้ไขข้อความและคลิกที่ปุ่มค้นหาเราจะค้นหารูปภาพบนอินเทอร์เน็ตผ่านเว็บเซอร์วิสที่มีให้โดย flickr (คุณจะต้องลงทะเบียนที่นั่นเพื่อรับกุญแจ / โทเค็นลับ) - สำหรับการค้นหาเราจะส่งคำขอ HTTP และรับข้อมูล JSON กลับมาเพื่อตอบสนองด้วย URL ของภาพแต่ละภาพซึ่งเราจะใช้ในการโหลดมุมมองกริด

การใช้งานของฉัน - ในกิจกรรมหลักฉันจะกำหนดคลาสภายในซึ่งขยาย AsyncTask เพื่อส่งคำขอ HTTP ในวิธี doInBackGround และดึงการตอบสนอง JSON และอัปเดต ArrayList ท้องถิ่นของฉันของ FlickrItems ซึ่งฉันจะใช้เพื่ออัปเดต GridView ของฉันผ่าน FlickrAdapter (ขยาย BaseAdapter) และเรียกใช้ adapter.notifyDataSetChanged () ใน onPostExecute () ของ AsyncTask เพื่อโหลดมุมมองกริดใหม่ โปรดทราบว่าที่นี่คำขอ HTTP คือการบล็อกการโทรเนื่องจากฉันได้ทำผ่าน AsyncTask และฉันสามารถแคชรายการในอะแดปเตอร์เพื่อเพิ่มประสิทธิภาพหรือเก็บไว้ใน SDCard ตารางที่ฉันจะขยายใน FlickrAdapter มีในการใช้งานของฉันแถบความคืบหน้าและมุมมองภาพ ด้านล่างคุณสามารถค้นหารหัสสำหรับ mainActivity ที่ฉันใช้

ตอบคำถามทันที - เมื่อเรามีข้อมูล JSON สำหรับดึงภาพแต่ละภาพเราสามารถใช้ตรรกะในการรับภาพในพื้นหลังผ่านทาง Handlers หรือ Threads หรือ AsyncTask เราควรทราบไว้ที่นี่ว่าเนื่องจากรูปภาพของฉันเมื่อดาวน์โหลดจะต้องแสดงบน UI / เธรดหลักเราไม่สามารถใช้เธรดได้เนื่องจากเป็นเพราะพวกเขาไม่สามารถเข้าถึงบริบทได้ ใน FlickrAdapter ตัวเลือกที่ฉันคิดได้:

  • ตัวเลือกที่ 1: สร้าง LooperThread [ขยายเธรด] - และทำการดาวน์โหลดรูปภาพตามลำดับในหนึ่งเธรดโดยเปิดเธรดนี้ไว้ [looper.loop ()]
  • ตัวเลือกที่ 2: ใช้ประโยชน์จากเธรดพูลและโพสต์ runnable ผ่าน myHandler ซึ่งมีการอ้างอิงถึง ImageView ของฉัน แต่เนื่องจากมุมมองในมุมมองกริดถูกนำกลับมาใช้อีกครั้งปัญหาอาจเกิดขึ้นเมื่อรูปภาพที่ดัชนี 4 แสดงที่ดัชนี 9 [ดาวน์โหลดอาจ ใช้เวลามากขึ้น]
  • ตัวเลือก 3 [ฉันใช้สิ่งนี้]: ใช้ประโยชน์จากกลุ่มเธรดและส่งข้อความไปยัง myHandler ซึ่งมีข้อมูลที่เกี่ยวข้องกับดัชนีของ ImageView และ ImageView เองดังนั้นในขณะที่ทำ handleMessage () เราจะอัปเดต ImageView เฉพาะเมื่อ currentIndex ตรงกับดัชนีของ ภาพที่เราพยายามดาวน์โหลด
  • ตัวเลือกที่ 4: ใช้ประโยชน์จาก AsyncTask เพื่อดาวน์โหลดภาพในพื้นหลัง แต่ที่นี่ฉันจะไม่สามารถเข้าถึงจำนวนเธรดที่ฉันต้องการในกลุ่มเธรดและมันจะแตกต่างกันไปตามรุ่น Android ที่แตกต่างกัน แต่ในตัวเลือก 3 ฉันสามารถตัดสินใจได้อย่างมีสติ ของขนาดเธรดพูลขึ้นอยู่กับการกำหนดค่าอุปกรณ์ที่ใช้

ที่นี่รหัสแหล่งที่มา:

public class MainActivity extends ActionBarActivity {

    GridView imageGridView;
    ArrayList<FlickrItem> items = new ArrayList<FlickrItem>();
    FlickrAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageGridView = (GridView) findViewById(R.id.gridView1);
        adapter = new FlickrAdapter(this, items);
        imageGridView.setAdapter(adapter);
    }

    // To avoid a memory leak on configuration change making it a inner class
    class FlickrDownloader extends AsyncTask<Void, Void, Void> {



        @Override
        protected Void doInBackground(Void... params) {
            FlickrGetter getter = new FlickrGetter();

            ArrayList<FlickrItem> newItems = getter.fetchItems();

            // clear the existing array
            items.clear();

            // add the new items to the array
            items.addAll(newItems);

            // is this correct ? - Wrong rebuilding the list view and should not be done in background
            //adapter.notifyDataSetChanged();

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            adapter.notifyDataSetChanged();
        }

    }

    public void search(View view) {
        // get the flickr data
        FlickrDownloader downloader = new FlickrDownloader();
        downloader.execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

ฉันหวังว่าคำตอบของฉันจะช่วยทำความเข้าใจรายละเอียดปลีกย่อย


ฉันขอทราบเหตุผลที่คำอธิบายของฉันบนพื้นฐานของตัวอย่างเพื่อประโยชน์ในการเปรียบเทียบได้รับการลงคะแนนเพื่อที่ฉันจะได้เรียนรู้จากมันด้วย
akshaymani

2
ก่อนอื่นขอขอบคุณสำหรับการตอบกลับของคุณถึงแม้ว่าหัวข้อนี้จะค่อนข้างเก่า แต่แนวคิดหลักยังคงเป็นปัจจุบันอยู่เสมอ คำถามแรกของฉันไม่ได้รับการตอบคุณกำลังยกตัวอย่างและอธิบายวิธีการทำงาน แต่คำถามนั้นถามถึงความแตกต่างระหว่างตัวจัดการ asynctask และเธรด
Alx

@ 80 ลีฟโอเคฉันเข้าใจแล้วตอนนี้ฉันพยายามอธิบายว่าฉันมาถึงข้อสรุปของการเลือกทางอื่น อย่างไรก็ตามชอบที่จะได้ยินมุมมองของคุณ / คนอื่น ๆ ว่าสิ่งที่ฉันเขียนนั้นถูกต้องหรือไม่หรือสามารถปรับปรุงได้อีก
akshaymani

1

มันขึ้นอยู่กับว่าใครจะเลือกขึ้นอยู่กับความต้องการ

ตัวจัดการส่วนใหญ่จะใช้ในการสลับจากเธรดอื่นไปเป็นเธรดหลักตัวจัดการติดกับ looper ซึ่งโพสต์ภารกิจที่รันได้ในคิว ดังนั้นหากคุณอยู่ในเธรดอื่นแล้วเปลี่ยนไปใช้เธรดหลักคุณต้องจัดการแทนงาน async หรือเธรดอื่น

หากตัวจัดการที่สร้างขึ้นนอกเหนือไปจากเธรดหลักซึ่งไม่ใช่ looper จะไม่ให้ข้อผิดพลาดเนื่องจากหมายเลขอ้างอิงถูกสร้างขึ้นเธรดนั้นจำเป็นต้องสร้างเธรดนั้น

AsyncTaskใช้ในการรันโค้ดในเวลาไม่กี่วินาทีซึ่งรันบนเธรดพื้นหลังและให้ผลลัพธ์กับเธรดหลัก ** * ข้อ จำกัด AsyncTask 1. ภารกิจ Async ไม่ได้เชื่อมต่อกับวงจรชีวิตของกิจกรรมและยังคงทำงานแม้ว่ากิจกรรมจะถูกทำลายในขณะที่โหลดไม่ทำงาน ไม่มีข้อ จำกัด นี้ 2. งาน Async ทั้งหมดแชร์เธรดพื้นหลังเดียวกันสำหรับการดำเนินการซึ่งส่งผลต่อประสิทธิภาพของแอป

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


0

เกลียว

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

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

เพื่อป้องกันสิ่งนี้คุณสามารถสร้างเธรดผู้ปฏิบัติงานและรันแบ็คกราวน์หรืองานที่รันนาน

ผู้ดำเนินการ

เนื่องจาก android ใช้โมเดลเธรดเดี่ยวส่วนประกอบ UI จะถูกสร้างขึ้นแบบไม่ปลอดภัยสำหรับเธรดหมายถึงเฉพาะเธรดที่สร้างขึ้นควรเข้าถึงพวกเขานั่นหมายความว่าคอมโพเนนต์ UI ควรได้รับการอัปเดตบนเธรดหลักเท่านั้น เนื่องจากองค์ประกอบ UI ทำงานบนเธรดหลักงานที่รันบนเธรดผู้ปฏิบัติงานจึงไม่สามารถแก้ไขคอมโพเนนต์ UI ได้ นี่คือที่มาของ Handler ตัวจัดการด้วยความช่วยเหลือของ Looper สามารถเชื่อมต่อกับเธรดใหม่หรือเธรดที่มีอยู่และรันโค้ดที่มีอยู่ในเธรดที่เชื่อมต่อ

Handler ทำให้การสื่อสารระหว่างเธรดเป็นไปได้ การใช้ตัวจัดการเธรดพื้นหลังสามารถส่งผลลัพธ์ไปได้และตัวจัดการที่เชื่อมต่อกับเธรดหลักสามารถอัพเดตคอมโพเนนต์ UI บนเธรดหลักได้

AsyncTask

AsyncTask ที่จัดทำโดย Android ใช้ทั้งเธรดและตัวจัดการเพื่อทำให้การรันงานง่าย ๆ ในพื้นหลังและการปรับปรุงผลลัพธ์จากเธรดพื้นหลังเป็นเธรดหลักได้อย่างง่ายดาย

โปรดดูด้ายจัดการ, asynctask และด้ายสระว่ายน้ำหุ่นยนต์สำหรับตัวอย่าง


-1

Handler- เป็นสื่อการสื่อสารระหว่างเธรด ใน android ส่วนใหญ่จะใช้ในการสื่อสารกับเธรดหลักโดยการสร้างและส่งข้อความผ่านตัวจัดการ

AsyncTask- ใช้เพื่อดำเนินการแอปพลิเคชันที่รันเป็นเวลานานในเธรดพื้นหลัง ด้วย n AsyncTaskคุณสามารถทำการดำเนินการในเธรดพื้นหลังและรับผลลัพธ์ในเธรดหลักของแอปพลิเคชัน

Thread- เป็นกระบวนการที่มีน้ำหนักเบาเพื่อให้เกิดการใช้งานพร้อมกันและการใช้งาน cpu สูงสุด ใน android คุณสามารถใช้เธรดเพื่อทำกิจกรรมที่ไม่ได้สัมผัส UI ของแอพ

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