(Part 1) Android background processing với Handlers, AsyncTask và Loaders

Android Threads, Handlers AsyncTask. Bài viết này mô tả cách sử dụng của tiến trình bất đồng bộ trong ứng dụng android (asynchronous ). Bao gồm làm thế nào để xử lý vòng đời ứng dụng với Threads. Được dựa trên Android Studio.

1. Background processing in Android

1.1. Why using concurrency?

Theo mặc định, code được chạy trong main thread. Do đó mỗi câu lệnh được thực hiện theo trình tự. Nếu bạn thực hiện một hoạt động với thời gian lâu, ứng dụng sẽ bị khóa cho đến khi hoạt động đó đã kết thúc.

Để cung cấp trải nghiệm người dùng tốt, tất cả các hoạt động chạy chậm và tốn thời gian trong ứng dụng Android sẽ chạy bất đồng bộ. Các hoạt có thể ví dụ như truy cập mạng, tải tập tin và cơ sở dữ liệu và tính toán phức tạp.

1.2. Main thread

Android thay đổi giao diện người dùng và xử lý các dữ liệu đầu vào từ một single thread, được gọi là main thread. Android thu thập tất cả sự kiện trong Thread đưa lên hàng đợi và xử lý hàng đợi này qua lớp Looper.

1.3. Threading in Android

Android hỗ trợ việc sử dụng lớp Thread để thực hiện quá trình không đồng bộ. Android cũng cung cấp gói java.util.concurrent để thực hiện một hoạt động trong background. Ví dụ, bằng cách sử dụng các lớp ThreadPoolsExecutor.

Nếu bạn cần phải cập nhật giao diện người dùng từ một new Thread, bạn cần đồng bộ với main thread. Do những hạn chế này, nhà phát triển Android thường sử dụng một cấu trúc riêng của Android.

Android cung cấp các cấu trúc bổ sung để xử lý đồng thời so với Java chuẩn.

Bạn có thể sử dụng lớp android.os.Handler hoặc các lớp AsyncTasks. Cách tiếp cận hay hơn dựa trên lớp Loader, giữ lại các fragment và service.

1.4. Providing feedback to a long running operation

Nếu bạn đang thực hiện một hoạt động trong thời gian dài, nó là cách tốt để cung cấp thông tin phản hồi cho người sử dụng.

Bạn có thể cung cấp phản hồi về tiến trình thông qua action bar, ví dụ như thông qua action view. Ngoài ra, bạn có thể sử dụng một ProgressBar trong bộ layout của bạn thiết lập để hiển thị và cập nhật nó cho người dùng.

2. Handler

2.1. Purpose of the Handler class

Một đối tượng Handler đăng ký chính nó với main thread nó được tạo ra. Nó cung cấp một kênh để gửi dữ liệu cho thread này. Ví dụ: nếu bạn tạo new Handler instance  trong phương thức onCreate () của activity , nó có thể được dùng để đẩy dữ liệu lên main thread. Dữ liệu có thể được đẩy qua lớp Handler có thể là một instance của lớp Message hoặc Runnable. Handler rất hữu ích nếu bạn muốn đẩy nhiều lần dữ liệu vào mainThread.

2.2. Creating and reusing instances of Handlers

Để triển khai một lớp handler subclass  và ghi đè lên handleMessage () để xử lý các message. Bạn có thể gửi message đến nó thông qua sendMessage (Message) hoặc thông qua phương thức sendEmptyMessage (). Sử dụng phương thức post () để gửi một Runnable đến nó.

Để tránh việc tạo đối tượng, bạn cũng có thể sử dụng lại đối tượng Handler hiện có trong actiity hiện tại.

// Reuse existing handler if you don't
// have to override the message processing
handler = getWindow().getDecorView().getHandler();

Class View cho phép bạn gửi các đối tượng kiểu Runnable thông qua phương thức post ().

2.3. Example

Đoạn code sau cho thấy việc sử dụng một handle từ một view.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="10"
        android:padding="4dip" >
    </ProgressBar>

     <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="" >
      </TextView>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startProgress"
        android:text="Start Progress" >
    </Button>

</LinearLayout>

Với đoạn code sau, ProgressBar được cập nhật khi người dùng nhấn button.

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class ProgressTestActivity extends Activity {
    private ProgressBar progress;
    private TextView text;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        text = (TextView) findViewById(R.id.textView1);

    }

    public void startProgress(View view) {
        // do something long
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    final int value = i;
                     doFakeWork();
                    progress.post(new Runnable() {
                        @Override
                        public void run() {
                            text.setText("Updating");
                            progress.setProgress(value);
                        }
                    });
                }
            }
        };
        new Thread(runnable).start();
    }

    // Simulating something timeconsuming
    private void doFakeWork() {
        SystemClock.sleep(5000);e.printStackTrace();
    }

}

3. AsyncTask

3.1. Purpose of the AsyncTask class

Lớp AsyncTask cho phép bạn chạy trong nền và đồng bộ lại với main thread. Nó cũng báo cáo tiến độ của các nhiệm vụ đang chạy. AsyncTasks nên được sử dụng cho hoạt động nền ngắn cần cập nhật giao diện người dùng.

3.2. Using the AsyncTask class

Để sử dụng AsyncTask bạn phải phân lớp nó. AsyncTask sử dụng generics và varargs. Các tham số là AsyncTask <TypeOfVarArgParams, ProgressValue, ResultValue>.

Một AsyncTask được bắt đầu thông qua phương thức execute (). Phương thức execute () này gọi phương thức doInBackground ()onPostExecute ().

TypeOfVarArgParams được đưa vào phương thức doInBackground () làm input.

ProgressValue được sử dụng cho thông tin tiến trình và ResultValue phải được trả lại từ phương thức doInBackground (). Tham số này được chuyển tới onPostExecute () dưới dạng một tham số.

Phương pháp doInBackground () nên được thực hiện trong background thread. Phương pháp này chạy tự động trong một Thread riêng biệt.

Phương thức onPostExecute () synchronizes với giao diện người dùng cho phép cập nhật giao diện. Được gọi tới khi phương thức doInBackground () kết thúc.

3.3. Example: AsyncTask

Ví dụ minh họa cách sử dụng lớp AsyncTask để tải nội dung của một trang web.

Thêmandroid.permission.INTERNET vào trong AndroidManifest.xml file.

Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/readWebpage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Load Webpage" >
    </Button>

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Placeholder" >
    </TextView>

</LinearLayout>

Thay đổi code Activity như sau:

public class ReadWebpageAsyncTask extends Activity {
    private TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textView = (TextView) findViewById(R.id.TextView01);
    }

    private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
            // we use the OkHttp library from https://github.com/square/okhttp
            OkHttpClient client = new OkHttpClient();
            Request request =
                    new Request.Builder()
                    .url(urls[0])
                    .build();
                 Response response = client.newCall(request).execute();
                 if (response.isSuccessful()) {
                     return response.body().string();
                 }
            }
            return "Download failed";
        }

        @Override
        protected void onPostExecute(String result) {
            textView.setText(result);
        }
    }

    public void onClick(View view) {
        DownloadWebPageTask task = new DownloadWebPageTask();
        task.execute(new String[] { "http://www.androidcoban.com/" });

    }
}

Tiến hành Chạy ứng dụng. Trang web được xác định được đọc dưới nền. Sau khi hoàn thành textview được cập nhật.

Xem thêm ví dụ khác về Asyctask return multple value… tại đây.

Còn tiếp……
LINK GỐC:  XEM TẠI ĐÂY

Nguyễn Linh

Chia sẻ để cùng tiến bộ...

Bình luận đã bị khoá.