post-promotion-placement#checkSidebarAdDisplayCondition” data-controller=”scroll-position sticky-ad post-promotion-placement “>
scroll-to-target-tracking#onClick” data-label=”Scroll to top” data-target-selector=”#page-body”> Scroll to top

*

Paul Trebilcox-Ruiz Jul 22, 2016

Ngoài những cái cơ bản nhất của các ứng dụng Android, tất cả những gì bạn xây dựng sẽ đòi hỏi ít nhất một số tiến trình nền để thực hiện một tác vụ. Điều này là bởi vì Android có một thứ được biết đến như là một timeout ANR (Application Not Responsive), xảy ra khi một tác vụ mất 5 giây hoặc lâu hơn trên tiến trình UI, ngăn chặn người dùng nhập vào và gây cho ứng dụng bị treo.

Để tránh điều này, bạn phải di chuyển tác vụ chạy lâu, chẳng hạn như các yêu cầu mạng hoặc truy vấn cơ sở dữ liệu chậm, vào một tiến trình khác để không ngăn cản người dùng tiếp tục sử dụng ứng dụng của bạn. Mặc dù khái quát toàn diện tiến trình là một chủ đề lớn và phức tạp trong khoa học máy tính, nhưng hướng dẫn này sẽ giới thiệu cho bạn những khái niệm cốt lõi của tiến trình trong Android, và một số công cụ có sẵn để giúp bạn xây dựng các ứng dụng hoạt động tốt hơn bằng cách sử dụng các tiến trình nền.

Đang xem: đa tiến trình trong android

Bạn có thấy dễ dàng hơn khi tìm hiểu bằng video không? Tại sao không kiểm tra khóa học của chúng tôi:

Tìm hiểu về tiến trình

Khi một ứng dụng được khởi động, một tiến trình Linux mới với một luồng tiến trình chính đơn nhất được bắt đầu. Đây là tiến trình truy cập vào Android UI toolkit, lắng nghe đầu vào từ người dùng, và xử lý việc vẽ lên màn hình thiết bị Android. Vì vậy, nó cũng thường được gọi là tiến trình UI.

Tất cả các thành phần của một ứng dụng chạy trong cùng một tiến trình và xử lý theo mặc định, tuy vậy các tiến trình bổ sung có thể được tạo ra để di chuyển các công việc ra khỏi tiến trình UI và ngăn chặn một ANR. Khi nói đến tiến trình trong Android, có hai quy tắc đơn giản cần phải nhớ để giữ cho ứng dụng của bạn hoạt động như mong đợi:

Không chặn tiến trình UI. Đừng cố gắng truy cập các thành phần giao diện người dùng Android từ bên ngoài các tiến trình UI.

Trong khi bạn có thể thực hiện theo các quy tắc đầu tiên chỉ đơn giản bằng cách tạo ra một Thread và Runnable mới, thì việc xử lý quy tắc thứ hai hơi khó hơn một chút. Hãy xem xét đoạn ustone.com.vn sau đây:

new Thread(new Runnable() { public void run() { try { Thread.sleep(6000); } catch( InterruptedException e ) { } mTextView.setText(“test”); }}).start();Mặc dù đoạn ustone.com.vn này sẽ không ảnh hưởng đến tiến trình UI trong khi tiến trình ngủ qua thời gian chờ ANR, thì việc cố gắng thiết lập văn bản cho TextView sẽ làm cho ứng dụng sinh ra lỗi sau:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.May mắn thay, có một vài cách đơn giản để khắc phục điều này. Bạn có thể sử dụng phương thức runOnUiThread(Runnable) của Android để thực thi ustone.com.vn trở lại tiến trình chính của ứng dụng.

mTextView = (TextView) findViewById(R.id.text);new Thread(new Runnable() { public void run() { try { Thread.sleep(6000); } catch( InterruptedException e ) { } runOnUiThread(new Runnable() {
Override public void run() { mTextView.setText(“test”); } }); }}).start();Hoặc bạn có thể lấy một đối tượng View tiêu chuẩn và post một Runnable vào nó.

new Thread(new Runnable() { public void run() { try { Thread.sleep(6000); } catch( InterruptedException e ) { } mTextView.post(new Runnable() {
Override public void run() { mTextView.setText(“test”); } }); }}).start();Mặc dù cả hai thủ thuật này sẽ giúp làm cho tiến trình hoạt động của bạn được an toàn, nhưng khi ứng dụng của bạn trở nên phức tạp hơn thì điều này sẽ trở nên khó khăn để duy trì.

AsyncTask

Một trong những công cụ được cung cấp bởi Android để giúp quản lý các tiến trình nền phức tạp là AsyncTask. AsyncTask cung cấp một tiến trình công việc cho các hoạt động ngăn chặn, và sau đó post kết quả về tiến trình UI cùng với một phương thức callback tạo sẵn, cho phép bạn hoàn thành các tác vụ của bạn dễ dàng mà không cần phải mò mẫm với Thread và Handler.

Vòng đời AsyncTask

Trước khi bạn bắt đầu sử dụng lớp AsyncTask, bạn sẽ cần phải hiểu vòng đời so với chạy một tác vụ trên tiến trình chính.

*
*
*

Phương thức đầu tiên được gọi bởi một AsyncTask là onPreExecute(). Phương thức này chạy trên tiến trình UI và là phương tiện để thiết lập bất kỳ thành phần giao diện cần để cho người dùng biết rằng một cái gì đó đang xảy ra.

Sau khi kết thúc onPreExecute(), doInBackground(T) được gọi. Tham số chung ở đây là bất kỳ thông tin nào mà bạn cần truyền vào với phương thức để cho nó để thực hiện nhiệm vụ của mình. Ví dụ, nếu bạn đang viết một tác vụ truy vấn JSON từ một URL, bạn sẽ truyền URL vào phương thức này như là một String. Tiếp theo là hoạt động tiến hành bên trong doInBackground(), bạn có thể gọi onProgressUpdate(T) để cập nhật UI của bạn (chẳng hạn như một thanh tiến trình trên màn hình). Ở đây là một giá trị biểu diễn cho tiến độ, chẳng hạn như một Integer.

Một khi phương thức doInBackground() đã thực hiện xong, nó có thể trả về một đối tượng được truyền vào trong onPostExecute(T), chẳng hạn như một JSONObject đã được tải về từ URL ban đầu của chúng ta. onPostExecute(T) chạy trên tiến trình UI.

Xem thêm:

Khi bạn tạo ra một lớp AsyncTask, bạn phải override những phương thức này trong cả định nghĩa lớp và các phương thức ở trên. Một ví dụ về AsyncTask cập nhật một ProgressBar mỗi giây có thể được thấy ở đây:

protected class DemoAsyncTask extends AsyncTask {
Override protected void onPreExecute() { super.onPreExecute(); mProgress.setProgress(0); mProgress.setVisibility(View.Visible); }
Override protected void onProgressUpdate(Integer… values) { super.onProgressUpdate(values); mProgress.setProgress(values<0>); }
Override protected Void doInBackground(Void… params) { for( int i = 0; i Bạn có thể thấy rằng onPostExecute(T) kiểm tra lại isCancelled(). Điều này là bởi vì có một vấn đề lớn với các AsyncTask: chúng duy trì một tham chiếu đến một Context ngay cả sau khi Context đó đã bị phá hủy.

Điều này dễ nhìn thấy nhất khi bắt đầu một AsyncTask và sau đó xoay màn hình. Nếu bạn cố gắng tham chiếu đến một phần tử Context (chẳng hạn như View hoặc Activity) sau khi Context ban đầu đã bị phá hủy, một Exception sẽ xảy ra. Cách dễ nhất để giải quyết điều này là gọi cancel(true) trên AsyncTask của bạn trong phương thức onDestroy() của Activity hoặc Fragment, và sau đó xác nhận rằng công việc đã không bị hủy bỏ trong onPostExecute(T).

Cũng như với bất cứ điều gì trong lập trình, câu trả lời khi nào bạn nên sử dụng một AsyncTask là: tuỳ. Mặc dù AsyncTask được sử dụng đơn giản, nhưng chúng không phải là một giải pháp cho tất cả và cuối cùng cho tiến trình, và tốt nhất là được sử dụng cho các hoạt động ngắn kéo dài tối đa một vài giây. Nếu bạn có một hoạt động có thể kéo dài, tôi khuyên bạn nghiên cứu sử dụng ThreadPoolExecutor, Service, hoặc GcmNetworkManager (một phiên bản tương thích ngược của JobScheduler).

Service

Khi bạn cần phải thực hiện một tác vụ dài chạy trong nền, chẳng hạn như chơi nhạc, thực hiện các giao dịch mạng hoặc tương tác với một nhà cung cấp nội dung, thì bạn có thể cần xem xét sử dụng một Service. Một Service cơ bản có thể tồn tại ở hai trạng thái: đã bắt đầu và bị ràng buộc.

Một Service đã bắt đầu được khởi động bởi một thành phần trong ứng dụng của bạn và vẫn còn hoạt động trong nền của thiết bị, thậm chí nếu các thành phần ban đầu đã bị hủy. Khi tác vụ là một Service đã bắt đầu đang thực thi đã hoàn thành, thì Service sẽ ngừng chính nó. Một Service đã bắt đầu tiêu chuẩn thường được sử dụng cho các tác vụ dài chạy trong nền mà không cần phải giao tiếp với phần còn lại của ứng dụng.

Một Service bị ràng buộc tương tự như một Service đã bắt đầu, và nó cũng cung cấp các callback cho các thành phần khác nhau của ứng dụng mà có thể liên kết với nó. Khi tất cả các thành phần bị ràng buộc đã ngừng ràng buộc chính nó khỏi Service, thì nó sẽ dừng chính nó. Điều quan trọng cần lưu ý là hai cách để chạy một Service không loại trừ lẫn nhau—bạn có thể bắt đầu một Service mà sẽ chạy vô thời hạn và có thể có các thành phần liên kết với nó.

IntentService

Một trong những vấn đề lớn nhất đối với một Service tiêu chuẩn đó là nó không thể xử lý yêu nhiều cầu tại cùng một thời điểm, điều này sẽ là một cơn ác mộng đa luồng. Một cách để giải quyết vấn đề này là thừa kế một IntentService, cái mà thừa kế một Service tiêu chuẩn. IntentService tạo ra một tiến trình công việc mặc định để thực hiện tất cả các intent nhận được trong onStartCommand(), do đó, tất cả các hoạt động có thể xảy ra nằm bên ngoài tiến trình chính. Sau đó nó tạo ra một hàng đợi công việc để gửi mỗi intent cho onHandleIntent() tại một thời điểm do đó bạn không cần phải lo lắng về vấn đề đa luồng.

Ngoài việc xử lý phân luồng, IntentService cũng ngừng chính nó một cách tự động sau khi tất cả các yêu cầu đã được xử lý. Bởi vì tất cả các chi tiết cài đặt được xử lý trong IntentService, nên nó làm việc đối với bạn khá đơn giản.

Xem thêm: Cách Nấu Chè Hạt Sen Khô Mau Mềm, Không Bị Sượng? Cách Nấu Chè Hạt Sen Khô Ngon Tại Nhà

public class ExampleIntentService extends IntentService { //required constructor with a name for the service public ExampleIntentService() { super(“ExampleIntentService”); }
Override protected void onHandleIntent(Intent intent) { //Perform your tasks here try { Thread.sleep(5000); } catch (InterruptedException e) {} }}

Tổng kết

Trong hướng dẫn này, bạn đã học được rất nhiều về tiến trình và các giải pháp đa tiến trình trong Android. Toàn bộ các cuốn sách đã được viết về tiến trình trong Android, nhưng bây giờ bạn đã có một nền tảng đối với các tác vụ tổng quát và hiểu thêm tài liệu hướng dẫn chuyên sâu đối với các ứng dụng Android phức tạp hơn.

Leave a Reply

Your email address will not be published. Required fields are marked *