Bài 37: Xử lý đa tiến trình bằng AsyncTask

Các bài tập 34, 35,36 Tui đã trình bày về xử lý đa tiến trình dùng Handler class. Trong bài tập này Tui muốn trình bày một kỹ thuật mới đó là cách xử lý bằng AsyncTask. Nó hơi hơi phức tạp 1 xí, nhưng cũng không có khó khăn gì … vấn đề là bạn hãy làm đi làm lại thật nhiều lần để hiểu thấu đáo về kỹ thuật này. Khi đã hiểu rồi thì bạn không cần dùng Handler class nữa mà nên dùng luôn AsyncTask. Đặc biệt khi xử lý đa tiến trình mà lại muốn kiểm tra kết quả trả về của tiến trình thì ta phải dùng AsyncTask.

Tui sẽ trình bày sơ qua về lý thuyết của AsyncTask trước khi vào những ví dụ cụ thể:

Bạn xem hình chụp 1 sau (bạn nhìn vào các đường mũi tên trỏ các parameter):

mul9

và hình số 2 sau như (nhìn vào các đường chỉ parameter):

mul10

– Tui sẽ giải thích kỹ về vấn đề này:

Trong AsyncTask<Params, Progress, Result>  có 3 đối số là các Generic Type:

Params: Là giá trị ((biến) được truyền vào khi gọi thực thi tiến trình và nó sẽ  được truyền vào doInBackground

Progress: Là  giá trị (biến) dùng để update giao diện diện lúc tiến trình thực thi, biến này sẽ được truyền vào hàm onProgressUpdate.

Result: Là biến dùng để lưu trữ kết quả trả về sau khi tiến trình thực hiện xong.

Những đối số nào không sử dụng trong quá trình thực thi tiến trình thì ta thay bằng Void.

Thông thường trong 1 AsyncTask sẽ chứa 4 hàm, đó là :

onPreExecute() : Tự động được gọi đầu tiên khi tiến trình được kích hoạt.

doInBackground(): Được thực thi trong quá trình tiến trình chạy nền, thông qua hàm này để ta gọi hàm onProgressUpdate để cập nhật giao diện (gọi lệnh publishProgress). Ta không thể cập nhật giao diện trong hàm doInBackground().

onProgressUpdate (): Dùng để cập nhật giao diện lúc runtime

onPostExecute(): Sau khi tiến trình kết thúc thì hàm này sẽ tự động sảy ra. Ta có thể lấy được kết quả trả về sau khi thực hiện tiến trình kết thúc ở đây.

Trong 4 hàm trên thì hàm doInBackground() bắt buộc phải tồn tại, còn các hàm khác có thể khuyết, nhưng theo Tui các bạn nên sử dụng đầy đủ 4 hàm đã nêu.

Đối với AsyncTask thì ta cần tạo một lớp kế thừa từ AsyncTask, sau đó từ MainActivity ta gọi hàm execute() của tiến trình này là OK.

Sau đây Tui sẽ làm một ví dụ cập nhật ProgressBar bằng AsyncTask (tui đã làm bằng Handler class trong bài 34):

async1

– Bài ví dụ trên chỉ đơn giản là cập nhật Progressbar (không quản lý kết quả trả về), nên đối số 1 và đối số 3 ta để Void, đối số 2 ta để Integer.

– Bạn tạo một Project như hình chụp dưới đây (với MyAsyncTask kết thừa từ AsyncTask):

async2

– Layout XML tương tự như bài 34:












– Bạn xem Tui giải thích source code MyAsyncTask dưới này:


package tranduythanh.com;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MyAsyncTask
extends AsyncTask {
 //khai báo Activity để lưu trữ địa chỉ của MainActivity
 Activity contextCha;
 //constructor này được truyền vào là MainActivity
 public MyAsyncTask(Activity ctx)
 {
 contextCha=ctx;
 }
 //hàm này sẽ được thực hiện đầu tiên
 @Override
 protected void onPreExecute() {
 // TODO Auto-generated method stub
 super.onPreExecute();
 Toast.makeText(contextCha, "onPreExecute!",
 Toast.LENGTH_LONG).show();
 }
 //sau đó tới hàm doInBackground
 //tuyệt đối không được cập nhật giao diện trong hàm này
 @Override
 protected Void doInBackground(Void... arg0) {
 for(int i=0;i<=100;i++)
 {
 //nghỉ 100 milisecond thì tiến hành update UI
 SystemClock.sleep(100);
 //khi gọi hàm này thì onProgressUpdate sẽ thực thi
 publishProgress(i);
 }
 return null;
 }
 /**
 * ta cập nhập giao diện trong hàm này
 */
 @Override
 protected void onProgressUpdate(Integer... values) {
 // TODO Auto-generated method stub
 super.onProgressUpdate(values);
 //thông qua contextCha để lấy được control trong MainActivity
 ProgressBar paCha=(ProgressBar) contextCha
 .findViewById(R.id.progressBar1);
 //vì publishProgress chỉ truyền 1 đối số
 //nên mảng values chỉ có 1 phần tử
 int giatri=values[0];
 //tăng giá trị của Progressbar lên
 paCha.setProgress(giatri);
 //đồng thời hiện thị giá trị là % lên TextView
 TextView txtmsg=(TextView)
 contextCha.findViewById(R.id.textView1);
 txtmsg.setText(giatri+"%");
 }
 /**
 * sau khi tiến trình thực hiện xong thì hàm này sảy ra
 */
 @Override
 protected void onPostExecute(Void result) {
 // TODO Auto-generated method stub
 super.onPostExecute(result);
 Toast.makeText(contextCha, "Update xong roi do!",
 Toast.LENGTH_LONG).show();
 }
 /**
 * tui làm 2 hàm ví dụ này về params trong Android
 */
 public void goividu()
 {
 viduParamschoham();
 viduParamschoham(5);
 viduParamschoham(5,6);
 viduParamschoham(5,6,5,6,7,8,9,0,0);
 }
 /**
 * dấu ... dùng khai báo param
 * tức là ta truyền bao nhiêu đối số cũng được
 * ds trở thành mảng 1 chiều
 * @param ds
 */
 public void viduParamschoham(int ... ds)
 {
 //test chơi...
 int pt0=ds[0];//có lỗi nếu như không truyền đối số nào
 for(int n:ds)
 {
 System.out.println(n);
 }
 //hoặc
 for(int i=0;i<ds.length;i++)
 {
 System.out.println(ds[i]);
 }
 }
}

– Ở đoạn code trên có 2 hàm cuối cùng là Tui viết thêm vào để giải thích cho việc sử dụng params trong Java, bạn cố gắng đọc để hiểu.

– Tiến trình MyASyncTask sẽ được thực thi khi bên MainActivity ta gọi phương thức: .execute()

source code MainActivity:


package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

Button btnStart;
 //khai báo MyAsyncTask
 MyAsyncTask mytt;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 btnStart=(Button) findViewById(R.id.button1);
 btnStart.setOnClickListener(new OnClickListener() {

 @Override
 public void onClick(View arg0) {
 // TODO Auto-generated method stub
 doStart();
 }
 });

 }
 private void doStart()
 {
 //truyền this (chính là MainActivity hiện tại) qua Child Thread
 mytt =new MyAsyncTask(this);
 //Kích hoạt Tiến trình
 //khi gọi hàm này thì onPreExecute của mytt sẽ thực thi trước
 mytt.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.activity_main, menu);
 return true;
 }

}

– Vô cùng đơn giản….. mọi thứ đẩy về cho Child Thread.

– Bạn có thể tải coding mẫu ở đây: http://www.mediafire.com/download/9or85fvafatp14o/LearnMultiThreading_ProgressBar_AsyncTask.rar

– Trong bài kế tiếp Tui sẽ làm 1 ví dụ AsyncTask nhưng có quản lý kết quả trả về, bài này tương đối phức tạp, các bạn chú ý theo dõi

– Chúc các bạn thành công!

Advertisement

Chia sẻ lên:

Like this:

Like

Loading…