portaldacalheta.pt
  • หลัก
  • การจัดการโครงการ
  • การเพิ่มขึ้นของระยะไกล
  • การบริหารโครงการ
  • เครื่องมือและบทช่วยสอน
มือถือ

Android Threading: สิ่งที่คุณต้องรู้



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

เมื่อเปิดแอปพลิเคชันใน Android แอปพลิเคชันจะสร้างเธรดการดำเนินการชุดแรกซึ่งเรียกว่าเธรด“ หลัก” เธรดหลักมีหน้าที่จัดส่งเหตุการณ์ไปยังวิดเจ็ตอินเทอร์เฟซผู้ใช้ที่เหมาะสมตลอดจนสื่อสารกับส่วนประกอบจากชุดเครื่องมือ Android UI



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



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



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

วิธีทำโทเค็น ethereum

ในบทความนี้คุณจะได้เรียนรู้เกี่ยวกับสถานการณ์ทั่วไปใน การพัฒนา Android ที่เธรดกลายเป็นสิ่งสำคัญและวิธีแก้ปัญหาง่ายๆที่สามารถนำไปใช้กับสถานการณ์เหล่านั้นและอื่น ๆ



เธรดใน Android

ใน Android คุณสามารถจัดหมวดหมู่ส่วนประกอบเธรดทั้งหมดออกเป็นสองประเภทพื้นฐาน:

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

คอมโพเนนต์เธรดที่แนบกับกิจกรรม / ส่วนย่อย

AsyncTask

AsyncTask เป็นส่วนประกอบพื้นฐานของ Android สำหรับเธรด ใช้งานง่ายและใช้ได้ดีกับสถานการณ์พื้นฐาน



ตัวอย่างการใช้งาน:

public class ExampleActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new MyTask().execute(url); } private class MyTask extends AsyncTask { @Override protected String doInBackground(String... params) { String url = params[0]; return doSomeWork(url); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); // do something with result } } }

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



รถตัก

รถตักเป็นทางออกสำหรับปัญหาดังกล่าวข้างต้น รถตักสามารถหยุดได้โดยอัตโนมัติเมื่อกิจกรรมถูกทำลายและยังสามารถรีสตาร์ทเองได้หลังจากสร้างกิจกรรมใหม่

ส่วนใหญ่มีรถตักสองประเภท: AsyncTaskLoader และ CursorLoader. คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับ CursorLoader ต่อไปในบทความนี้



AsyncTaskLoader คล้ายกับ AsyncTask แต่ซับซ้อนกว่าเล็กน้อย

ตัวอย่างการใช้งาน:



public class ExampleActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getLoaderManager().initLoader(1, null, new MyLoaderCallbacks()); } private class MyLoaderCallbacks implements LoaderManager.LoaderCallbacks { @Override public Loader onCreateLoader(int id, Bundle args) { return new MyLoader(ExampleActivity.this); } @Override public void onLoadFinished(Loader loader, Object data) { } @Override public void onLoaderReset(Loader loader) { } } private class MyLoader extends AsyncTaskLoader { public MyLoader(Context context) { super(context); } @Override public Object loadInBackground() { return someWorkToDo(); } } }

ส่วนประกอบของเธรดที่ไม่แนบกับกิจกรรม / ส่วนย่อย

บริการ

Service เป็นส่วนประกอบที่มีประโยชน์สำหรับการดำเนินการที่ยาวนาน (หรืออาจยาวนาน) โดยไม่มี UI ใด ๆ

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

ตัวอย่างการใช้งาน:

public class ExampleService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { doSomeLongProccesingWork(); stopSelf(); return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }

ด้วย Service มันคือ ของคุณ ความรับผิดชอบในการหยุดงานเมื่องานเสร็จสมบูรณ์โดยเรียก stopSelf() หรือ stopService() วิธี.

IntentService

ชอบ Service, IntentService ทำงานบนเธรดแยกต่างหากและหยุดตัวเองโดยอัตโนมัติหลังจากทำงานเสร็จสิ้น

IntentService โดยปกติจะใช้สำหรับงานสั้น ๆ ที่ไม่จำเป็นต้องเชื่อมต่อกับ UI ใด ๆ

ตัวอย่างการใช้งาน:

public class ExampleService extends IntentService { public ExampleService() { super('ExampleService'); } @Override protected void onHandleIntent(Intent intent) { doSomeShortWork(); } }

เจ็ดรูปแบบเธรดใน Android

ใช้กรณีที่ 1: การร้องขอผ่านเครือข่ายโดยไม่ต้องการการตอบกลับจากเซิร์ฟเวอร์

บางครั้งคุณอาจต้องการส่งคำขอ API ไปยังเซิร์ฟเวอร์โดยไม่ต้องกังวลกับการตอบสนอง ตัวอย่างเช่นคุณอาจส่งโทเค็นการลงทะเบียนแบบพุชไปยังส่วนหลังของแอปพลิเคชันของคุณ

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

ตัวเลือกที่ 1: AsyncTask หรือรถตัก

คุณสามารถใช้ AsyncTask หรือรถตักสำหรับการโทรและมันจะทำงาน

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

ทางเลือกที่ 2: บริการ

Service อาจเหมาะกว่าสำหรับกรณีการใช้งานนี้เนื่องจากไม่ได้เชื่อมต่อกับกิจกรรมใด ๆ ดังนั้นจึงจะสามารถดำเนินการโทรเครือข่ายต่อไปได้แม้ว่ากิจกรรมจะถูกทำลายไปแล้วก็ตาม นอกจากนี้เนื่องจากไม่จำเป็นต้องมีการตอบสนองจากเซิร์ฟเวอร์บริการจึงไม่ จำกัด ที่นี่เช่นกัน

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

สิ่งนี้จะต้องใช้ความพยายามมากกว่าที่ควรจะเป็นสำหรับการกระทำง่ายๆเช่นนี้

อะไรคือความแตกต่างระหว่าง s corp และ c corp

ตัวเลือกที่ 3: IntentService

ในความคิดของฉันนี่น่าจะเป็นตัวเลือกที่ดีที่สุด

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

ใช้กรณีที่ 2: การโทรผ่านเครือข่ายและรับการตอบกลับจากเซิร์ฟเวอร์

กรณีการใช้งานนี้อาจพบได้บ่อยกว่าเล็กน้อย ตัวอย่างเช่นคุณอาจต้องการเรียกใช้ API ในส่วนหลังและใช้การตอบกลับเพื่อเติมข้อมูลในฟิลด์บนหน้าจอ

ทางเลือกที่ 1: บริการหรือ IntentService

แม้ว่า a Service หรือ IntentService เหมาะสำหรับกรณีการใช้งานก่อนหน้านี้การใช้ที่นี่คงไม่ใช่ความคิดที่ดี พยายามดึงข้อมูลจาก Service หรือ IntentService ในเธรด UI หลักจะทำให้สิ่งต่างๆซับซ้อนมาก

ทางเลือกที่ 2: AsyncTask หรือรถตัก

ตอนแรกอาย AsyncTask หรือรถตักดูเหมือนจะเป็นทางออกที่ชัดเจนที่นี่ ใช้งานง่าย - เรียบง่ายและตรงไปตรงมา

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

นั่นเป็นงานที่ต้องทำมากมายสำหรับทุกการโทร โชคดีที่ตอนนี้มีวิธีแก้ปัญหาที่ดีและง่ายกว่ามาก: RxJava

ตัวเลือกที่ 3: RxJava

คุณอาจเคยได้ยินเกี่ยวกับ RxJava ห้องสมุดที่พัฒนาโดย Netflix เกือบจะเป็นเวทมนตร์ใน Java

RxAndroid ช่วยให้คุณใช้ RxJava ใน Android และจัดการกับงานแบบอะซิงโครนัสได้อย่างง่ายดาย คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ RxJava บน Android ที่นี่ .

RxJava มีสององค์ประกอบ: Observer และ Subscriber.

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

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

ด้วย RxJava คุณต้องสร้างสิ่งที่สังเกตได้ก่อน:

Observable.create((ObservableOnSubscribe) e -> { Data data = mRestApi.getData(); e.onNext(data); })

เมื่อสร้างสิ่งที่สังเกตได้แล้วคุณสามารถสมัครสมาชิกได้

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

คุณเชื่อมโยงกับสิ่งที่สังเกตได้ด้วยฟังก์ชันทั้งสองนี้:

.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()

ตัวกำหนดตารางเวลาเป็นส่วนประกอบที่ดำเนินการดำเนินการในเธรดหนึ่ง ๆ AndroidSchedulers.mainThread() เป็นตัวกำหนดตารางเวลาที่เกี่ยวข้องกับเธรดหลัก

ระบุว่าการเรียก API ของเราคือ mRestApi.getData() และส่งกลับ Data วัตถุการเรียกพื้นฐานอาจมีลักษณะดังนี้:

cfo คืออะไร?
Observable.create((ObservableOnSubscribe) e -> { try { Data data = mRestApi.getData(); e.onNext(data); } catch (Exception ex) { e.onError(ex); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(match -> Log.i(“rest api, 'success'), throwable -> Log.e(“rest api, 'error: %s' + throwable.getMessage()));

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

ใช้กรณีที่ 3: การเชื่อมโยงการโทรในเครือข่าย

สำหรับการโทรผ่านเครือข่ายที่ต้องดำเนินการตามลำดับ (กล่าวคือโดยแต่ละการดำเนินการขึ้นอยู่กับการตอบสนอง / ผลลัพธ์ของการดำเนินการก่อนหน้านี้) คุณต้องระมัดระวังเป็นพิเศษในการสร้างรหัสสปาเก็ตตี้

ตัวอย่างเช่นคุณอาจต้องทำการเรียก API ด้วยโทเค็นที่คุณต้องดึงข้อมูลก่อนผ่านการเรียก API อื่น

ตัวเลือกที่ 1: AsyncTask หรือรถตัก

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

ตัวเลือกที่ 2: RxJava โดยใช้ flatMap

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

ขั้นตอนที่ 1. สร้างสิ่งที่สังเกตได้ที่ดึงโทเค็น:

public Observable getTokenObservable() { return Observable.create(subscriber -> { try { String token = mRestApi.getToken(); subscriber.onNext(token); } catch (IOException e) { subscriber.onError(e); } }); }

ขั้นตอนที่ 2. สร้างสิ่งที่สังเกตได้ซึ่งรับข้อมูลโดยใช้โทเค็น:

public Observable getDataObservable(String token) { return Observable.create(subscriber -> { try { Data data = mRestApi.getData(token); subscriber.onNext(data); } catch (IOException e) { subscriber.onError(e); } }); }

ขั้นตอนที่ 3. เชื่อมโยงสิ่งที่สังเกตได้ทั้งสองเข้าด้วยกันและสมัครสมาชิก:

getTokenObservable() .flatMap(new Function() { @Override public Observable apply(String token) throws Exception { return getDataObservable(token); } }) .subscribe(data -> { doSomethingWithData(data) }, error -> handleError(e));

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

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

ใช้กรณีที่ 4: สื่อสารกับเธรด UI จากเธรดอื่น

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

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

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

ตัวเลือกที่ 1: RxJava ภายในบริการ

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

ในทางกลับกันด้วย Service คุณจะต้องหยุดบริการด้วยตนเองซึ่งต้องทำงานมากขึ้น

ตัวเลือกที่ 2: BroadcastReceiver

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

ในการดำเนินการนี้คุณต้องสร้างคลาสแบบกำหนดเองที่ขยาย BroadcastReceiver ลงทะเบียนในไฟล์ Manifest และใช้ Intent และ IntentFilter เพื่อสร้างเหตุการณ์ที่กำหนดเอง ในการทริกเกอร์เหตุการณ์คุณจะต้องมี sendBroadcast วิธี.

ประจักษ์:

public class UploadReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getBoolean(“success”, false) { Activity activity = (Activity)context; activity.updateUI(); } }

ผู้รับ:

Intent intent = new Intent(); intent.setAction('com.example.upload'); sendBroadcast(intent);

ผู้ส่ง:

Handler

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

ตัวเลือกที่ 3: การใช้ Handler

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

เมื่อ a Looper ถูกสร้างขึ้นมันจะได้รับ Looper.getMainLooper() อ็อบเจ็กต์ในตัวสร้างซึ่งระบุว่าเธรดใดที่ตัวจัดการแนบอยู่ หากคุณต้องการใช้ตัวจัดการที่เชื่อมต่อกับเธรดหลักคุณต้องใช้ looper ที่เชื่อมโยงกับเธรดหลักโดยเรียก Runnable

ในกรณีนี้หากต้องการอัปเดต UI จากเธรดพื้นหลังคุณสามารถสร้างตัวจัดการที่แนบมากับเธรด UI จากนั้นโพสต์การดำเนินการเป็น Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // update the ui from here } }); :

EventBus

วิธีนี้ดีกว่าวิธีแรกมาก แต่มีวิธีที่ง่ายกว่านี้อีก ...

ตัวเลือกที่ 3: การใช้ EventBus

UIEvent ซึ่งเป็นไลบรารียอดนิยมของ GreenRobot ช่วยให้ส่วนประกอบต่างๆสามารถสื่อสารระหว่างกันได้อย่างปลอดภัย เนื่องจากกรณีการใช้งานของเราเป็นกรณีที่เราต้องการอัปเดต UI เท่านั้นจึงเป็นทางเลือกที่ง่ายและปลอดภัยที่สุด

ขั้นตอนที่ 1. สร้างคลาสกิจกรรม เช่น @Subscribe(threadMode = ThreadMode.MAIN) public void onUIEvent(UIEvent event) {/* Do something */}; register and unregister eventbus : @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } .

ขั้นตอนที่ 2. สมัครเข้าร่วมกิจกรรม

EventBus.getDefault().post(new UIEvent());

ขั้นตอนที่ 3. โพสต์เหตุการณ์: ThreadMode

ด้วย UIEvent ในคำอธิบายประกอบคุณกำลังระบุเธรดที่คุณต้องการสมัครรับข้อมูลสำหรับเหตุการณ์นี้ ในตัวอย่างของเราที่นี่เรากำลังเลือกเธรดหลักเนื่องจากเราต้องการให้ผู้รับของเหตุการณ์สามารถอัปเดต UI ได้

คุณสามารถจัดโครงสร้าง class UploadFileService extends IntentService { // … Boolean success = uploadFile(File file); EventBus.getDefault().post(new UIEvent(success)); // ... } ของคุณได้ คลาสเพื่อให้มีข้อมูลเพิ่มเติมตามความจำเป็น

ในบริการ:

@Subscribe(threadMode = ThreadMode.MAIN) public void onUIEvent(UIEvent event) {//show message according to the action success};

ในกิจกรรม / ส่วน:

EventBus library

การใช้ EventBus การสื่อสารระหว่างเธรดจะง่ายขึ้นมาก

ใช้กรณีที่ 5: การสื่อสารสองทางระหว่างเธรดตามการกระทำของผู้ใช้

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

ตัวอย่างโปรแกรมเล่นสื่อแบบเต็มอยู่นอกเหนือขอบเขตของบทความนี้ อย่างไรก็ตามคุณสามารถค้นหาบทเรียนที่ดีได้ ที่นี่ และ ที่นี่ .

cfo หมายถึงอะไรในธุรกิจ

ตัวเลือกที่ 1: การใช้ EventBus

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

ตัวเลือกที่ 2: การใช้ BoundService

ก Service คือ Binder ที่ผูกไว้กับกิจกรรม / ส่วน ซึ่งหมายความว่ากิจกรรม / ส่วนย่อยจะรู้อยู่เสมอว่าบริการกำลังทำงานอยู่หรือไม่และนอกจากนี้ยังสามารถเข้าถึงวิธีการสาธารณะของบริการได้อีกด้วย

ในการใช้งานคุณต้องสร้าง public class MediaService extends Service { private final IBinder mBinder = new MediaBinder(); public class MediaBinder extends Binder { MediaService getService() { // Return this instance of LocalService so clients can call public methods return MediaService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } } ที่กำหนดเอง ภายในบริการและสร้างวิธีที่ส่งคืนบริการ

ServiceConnection

ในการเชื่อมโยงกิจกรรมกับบริการคุณต้องใช้ bindService ซึ่งเป็นคลาสที่ตรวจสอบสถานะบริการและใช้เมธอด // in the activity MediaService mService; // flag indicates the bound status boolean mBound; @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, MediaService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { MediaBinder binder = (MediaBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; เพื่อทำการผูก:

BroadcastReceiver

คุณสามารถดูตัวอย่างการใช้งานแบบเต็มได้ ที่นี่ .

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

เมื่อมีกิจกรรมสื่อและคุณต้องการสื่อสารสิ่งนั้นกลับไปที่กิจกรรม / ส่วนย่อยคุณสามารถใช้หนึ่งในเทคนิคก่อนหน้านี้ (เช่น Handler, EventBus หรือ merge())

ใช้กรณีที่ 6: ดำเนินการควบคู่กันไปและรับผลลัพธ์

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

เว็บไซต์บูตสแตรปคืออะไร

ในการทำให้กระบวนการขนานกันการเรียก API แต่ละรายการต้องเกิดขึ้นในเธรดที่แตกต่างกัน

ตัวเลือกที่ 1: การใช้ RxJava

ใน RxJava คุณสามารถรวมสิ่งที่สังเกตได้หลายรายการเข้าด้วยกันโดยใช้ concat() หรือ ExecutorService ตัวดำเนินการ จากนั้นคุณสามารถสมัครรับข้อมูล 'ผสาน' ที่สังเกตได้และรอผลลัพธ์ทั้งหมด

อย่างไรก็ตามแนวทางนี้ไม่ได้ผลตามที่คาดไว้ หากการเรียก API หนึ่งครั้งล้มเหลวสิ่งที่สังเกตได้ที่ผสานจะรายงานความล้มเหลวโดยรวม

ตัวเลือกที่ 2: การใช้คอมโพเนนต์ดั้งเดิมของ Java

Future ใน Java จะสร้างจำนวนเธรดที่คงที่ (กำหนดค่าได้) และรันงานบนเธรดพร้อมกัน บริการส่งคืน a invokeAll() อ็อบเจ็กต์ที่ส่งกลับผลลัพธ์ทั้งหมดในที่สุดผ่านทาง ExecutorService วิธี.

แต่ละงานที่คุณส่งไปที่ Callable ควรมีอยู่ใน invokeAll() อินเทอร์เฟซซึ่งเป็นอินเทอร์เฟซสำหรับการสร้างงานที่สามารถทำให้เกิดข้อยกเว้นได้

เมื่อคุณได้ผลลัพธ์จาก ExecutorService pool = Executors.newFixedThreadPool(3); List tasks = new ArrayList(); tasks.add(new Callable() { @Override public Integer call() throws Exception { return mRest.getAttractionType1(); } }); // ... try { List results = pool.invokeAll(tasks); for (Future result : results) { try { Object response = result.get(); if (response instance of AttractionType1... {} if (response instance of AttractionType2... {} ... } catch (ExecutionException e) { e.printStackTrace(); } } } catch (InterruptedException e) { e.printStackTrace(); } คุณสามารถตรวจสอบทุกผลลัพธ์และดำเนินการตามนั้น

ตัวอย่างเช่นสมมติว่าคุณมีแหล่งท่องเที่ยวสามประเภทที่มาจากจุดสิ้นสุดที่ต่างกันสามจุดและคุณต้องการโทรขนานกันสามสาย:

Cursor

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

วิธีนี้ง่ายกว่าการใช้ RxJava ง่ายกว่าสั้นกว่าและไม่ล้มเหลวทุกการกระทำเพราะข้อยกเว้นเดียว

ใช้กรณีที่ 7: การสืบค้นฐานข้อมูล SQLite ภายในเครื่อง

เมื่อจัดการกับฐานข้อมูล SQLite ในเครื่องขอแนะนำให้ใช้ฐานข้อมูลจากเธรดพื้นหลังเนื่องจากการเรียกฐานข้อมูล (โดยเฉพาะกับฐานข้อมูลขนาดใหญ่หรือการสืบค้นที่ซับซ้อน) อาจใช้เวลานานส่งผลให้ UI ค้าง

เมื่อค้นหาข้อมูล SQLite คุณจะได้รับ Cursor cursor = getData(); String name = cursor.getString(); จากนั้นสามารถใช้เพื่อดึงข้อมูลจริง

public Observable getLocalDataObservable() { return Observable.create(subscriber -> { Cursor cursor = mDbHandler.getData(); subscriber.onNext(cursor); }); }

ตัวเลือกที่ 1: การใช้ RxJava

คุณสามารถใช้ RxJava และรับข้อมูลจากฐานข้อมูลได้เช่นเดียวกับที่เรารับข้อมูลจากส่วนหลังของเรา:

getLocalDataObservable()

คุณสามารถใช้สิ่งที่สังเกตได้ที่ส่งคืนโดย getLocalDataObservable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(cursor -> String name = cursor.getString(0), throwable -> Log.e(“db, 'error: %s' + throwable.getMessage())); ดังต่อไปนี้:

CursorLoader

แม้ว่านี่จะเป็นแนวทางที่ดี แต่ก็มีวิธีหนึ่งที่ดีกว่านั้นเนื่องจากมีส่วนประกอบที่สร้างขึ้นเพื่อสถานการณ์นี้โดยเฉพาะ

ตัวเลือกที่ 2: การใช้ CursorLoader + ContentProvider

Android มี Loader ซึ่งเป็นส่วนประกอบดั้งเดิมสำหรับการโหลดข้อมูล SQLite และจัดการเธรดที่เกี่ยวข้อง มันคือ Cursor ที่ส่งคืน getString() ซึ่งเราสามารถใช้เพื่อรับข้อมูลโดยเรียกวิธีง่ายๆเช่น getLong(), public class SimpleCursorLoader extends FragmentActivity implements LoaderManager.LoaderCallbacks { public static final String TAG = SimpleCursorLoader.class.getSimpleName(); private static final int LOADER_ID = 0x01; private TextView textView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_cursor_loader); textView = (TextView) findViewById(R.id.text_view); getSupportLoaderManager().initLoader(LOADER_ID, null, this); } public Loader onCreateLoader(int i, Bundle bundle) { return new CursorLoader(this, Uri.parse('content://com.github.browep.cursorloader.data') , new String[]{'col1'}, null, null, null); } public void onLoadFinished(Loader cursorLoader, Cursor cursor) { if (cursor != null && cursor.moveToFirst()) { String text = textView.getText().toString(); while (cursor.moveToNext()) { text += '
' + cursor.getString(1); cursor.moveToNext(); } textView.setText(Html.fromHtml(text) ); } } public void onLoaderReset(Loader cursorLoader) { } }
เป็นต้น

CursorLoader

ContentProvider ใช้ได้กับ

|_+_|
ส่วนประกอบ. ส่วนประกอบนี้มีคุณลักษณะฐานข้อมูลแบบเรียลไทม์มากมายเหลือเฟือ (เช่นการแจ้งเตือนการเปลี่ยนแปลงทริกเกอร์ ฯลฯ ) ที่ช่วยให้นักพัฒนาสามารถใช้ประสบการณ์ผู้ใช้ที่ดีขึ้นได้ง่ายขึ้น

ไม่มีโซลูชัน Silver Bullet สำหรับ Threading ใน Android

Android มีหลายวิธีในการจัดการและจัดการเธรด แต่ไม่มีเลยที่จะเป็นกระสุนเงิน

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

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

การสร้างแอปข้ามแพลตฟอร์มด้วย Xamarin: มุมมองของนักพัฒนา Android

มือถือ

การสร้างแอปข้ามแพลตฟอร์มด้วย Xamarin: มุมมองของนักพัฒนา Android
ผู้จัดการฝ่ายจัดส่ง

ผู้จัดการฝ่ายจัดส่ง

อื่น ๆ

โพสต์ยอดนิยม
ตลาด Crowdfunding Equity ของสหรัฐมีการเติบโตขึ้นตามความคาดหวังหรือไม่?
ตลาด Crowdfunding Equity ของสหรัฐมีการเติบโตขึ้นตามความคาดหวังหรือไม่?
คู่มือสำคัญสำหรับ Qmake
คู่มือสำคัญสำหรับ Qmake
หลักการออกแบบ Mobile UX
หลักการออกแบบ Mobile UX
MIDI Tutorial: การสร้างแอปพลิเคชั่นเสียงบนเบราว์เซอร์ที่ควบคุมโดยฮาร์ดแวร์ MIDI
MIDI Tutorial: การสร้างแอปพลิเคชั่นเสียงบนเบราว์เซอร์ที่ควบคุมโดยฮาร์ดแวร์ MIDI
Init.js: คำแนะนำเกี่ยวกับสาเหตุและวิธีการใช้ JavaScript แบบ Full-Stack
Init.js: คำแนะนำเกี่ยวกับสาเหตุและวิธีการใช้ JavaScript แบบ Full-Stack
 
Splash of EarlGrey - UI การทดสอบแอพ ApeeScape Talent
Splash of EarlGrey - UI การทดสอบแอพ ApeeScape Talent
จาก Node.js ไปจนถึงการจ่ายภาษีอิสระของคุณ: บทสัมภาษณ์กับ Developer ที่ประสบความสำเร็จ
จาก Node.js ไปจนถึงการจ่ายภาษีอิสระของคุณ: บทสัมภาษณ์กับ Developer ที่ประสบความสำเร็จ
ขายธุรกิจของคุณ? หยุดทิ้งเงินไว้บนโต๊ะ
ขายธุรกิจของคุณ? หยุดทิ้งเงินไว้บนโต๊ะ
บทช่วยสอนเกี่ยวกับส่วนขยายแอป iOS 8
บทช่วยสอนเกี่ยวกับส่วนขยายแอป iOS 8
ผู้จัดการการเติบโต
ผู้จัดการการเติบโต
โพสต์ยอดนิยม
  • หน้าวัตถุรุ่นซีลีเนียม java
  • ความแตกต่างระหว่าง s corp c corp และ llc
  • เรียนภาษา c หรือ c++ ก่อน
  • ember js กวดวิชาทีละขั้นตอน
  • เรียนยาก
  • เทคนิคการเพิ่มประสิทธิภาพแบบสอบถามเซิร์ฟเวอร์ sql
หมวดหมู่
  • การจัดการโครงการ
  • การเพิ่มขึ้นของระยะไกล
  • การบริหารโครงการ
  • เครื่องมือและบทช่วยสอน
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt