– Chúc mừng các bạn đã vượt qua được 33 cửa ải bài tập Android.

-Tôi thật sự vui mừng xúc động khi các bạn đã bền bỉ theo dõi từng bài, để tới được đây thì Tôi cam đoan rằng các bạn đã phải tốn rất nhiều công sức và thời gian, các bạn phải thức ngày đêm để làm được những bài tập trước đó.

– Để đáp lại những cố gắng của các bạn, trong bài tập này Tôi sẽ cung cấp cho các bạn một kiến thức hay, kiến thức mới và cực kỳ khó để các bạn quen với nỗi khổ đau để về sau có bị khổ nữa thì cũng quen rồi sẽ không còn thấy khổ (Tôi viết theo phạm trù triết học, chỉ có lập trình quá khổ mới hiểu).

– Như Tôi đã từng nói Intent là linh hồn của Android, trong mọi ngõ nghách hẻm hay mặt tiền của Android thì Intent vẫn tồn tại như chưa từng được tồn tại.

– Còn đa tiến trình (Multi – Threading)? nó cũng vậy, nó cũng giống như kỹ thuật truyền huyết mạch của từng ứng dụng Android, đặc biệt là những ứng dụng Vô Đối. Ví dụ như bạn cần cập nhật giao diện lúc thời gian thực, bạn cần kết nối internet hay làm những giao tác nào đó mà phải phân ra nhiểu tiểu trình để chạy. Để xử lý được đa tiến trình thì bạn phải có một tư duy lập trình logic thật tốt, nếu không tốt thì phải (Lấy Cần Cù Bù Thông Minh).

– Kỹ thuật đa tiến trình rất khó mà không khó (nếu bạn hiểu).

– Trong bài này Tôi sẽ hướng dẫn các bạn xử lý đa tiến trình với Handler class và AsyncTask class.

Bài ví dụ cập nhật ProgressBar lúc runtime: Progressbar sẽ cập nhật từ 0% tới 100% như hình bên dưới.

mul1– Trước tiên Tôi muốn nói về cách tạo đa tiến trình trong Java trước để các bạn dễ dàng áp dụng vào trong Android (vì Android dùng Java để coding).

– Trong java có 2 cách tạo đa tiến trình:

Cách 1: Ta implements interface Runnable

Sau đó ta Override phương thức run() này, khi tiến trình được Start thì hàm run sẽ được thực thi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyRunable implements Runnable {
@Override
 public void run() {
 System.out.println
 (Thread.currentThread().getName()+" ...start!");
 }
 public static void main(String[] args) {
 for(int i=0;i<5;i++)
 {
 Thread t1=new Thread(new MyRunable());
 t1.start();
 }
 }
}

Ở trên Tôi dùng hàm main để Test tiến trình, Tôi tạo ra 5 tiến trình bằng cách dùng vòng lặp for.

Thread.currentThread().getName() là trả về tên của tiến trình hiện tại đang thực thi

Thread t1=new Thread(new MyRunable()); để tạo 1 tiến trình

gọi phương thức start để kích hoạt tiến trình.
t1.start(); Khi gọi hàm này thì phương thức run của MyRunnable sẽ được thực thi.

Chú ý rằng tiến trình rất khó kiểm soát, mỗi lần chạy sẽ mỗi khác nhau nên rất khó Debug, nó lệ thuộc vào hệ điều hành.

Ví dụ lần 1 bạn start thì có kết quả có thể là như sau:

mul2

– ở lần chạy tiếp theo thì chưa chắc bạn thấy được kết quả như trên nữa.

Cách 2: Kế thừa trực tiếp từ lớp Thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyThread extends Thread {
 @Override
 public void run() {
 super.run();
 System.out.println(getName()+" ... Start");
 }
 public static void main(String[] args) {
 for(int i=0;i<5;i++)
 {
 MyThread t=new MyThread();
 t.start();
 }
 }
}

– Ta thấy cách 2 dùng trực tiếp Thread, nên ta tạo 1 Thread từ MyThread và gọi start là tiến trình này sẽ được thực thi.

– Thường thì người ta hay sử dụng cách 1, do cách 1 có thể chia sẻ được các đối tượng qua lại giữa các tiến trình.

Giờ ta quay trở lại ví dụ cập nhật ProgressBar trong Android.

Trong bài ví dụ này Tôi dùng Handler class để xử lý. Chú ý rằng Handler class lại có 2 cách dùng.

Ở đây Tôi dùng sendMessage của Handler class để xử lý đa tiến trình, trong ví dụ kế tiếp Tôi sẽ dùng using Post  để xử lý.

Mô hình của Handler MessageQueue:

mul3

cách viết coding cho Handler class dùng Message:

mul4

– Chi tiết bài ví dụ:

– XML Layout :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >
<TextView
 android:id="@+id/textView1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#FFFFFF"
 android:gravity="center"
 android:text="0%"
 android:textColor="#008000"
 android:textSize="25sp" />
<ProgressBar
 android:id="@+id/progressBar1"
 style="?android:attr/progressBarStyleHorizontal"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:max="100"
 android:minHeight="50dp" />
 <Button
 android:id="@+id/btnstart"
 android:layout_width="105dp"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:text="Start" />
</LinearLayout>

– Tới đây thì việc thiết kế layout là vô cùng đơn giản đối với các bạn rồi, nên Tôi không nói nhiều về nó nữa.

– Ta chuyển qua coding của MainActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package tranduythanh.com;
import java.util.concurrent.atomic.AtomicBoolean;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity {
 ProgressBar bar;
 //khai báo handler class để xử lý đa tiến trình
 Handler handler;
 //dùng AtomicBoolean để thay thế cho boolean
 AtomicBoolean isrunning=new AtomicBoolean(false);
 //boolean
 Button btnstart;
 TextView lblmsg;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 bar=(ProgressBar) findViewById(R.id.progressBar1);
 btnstart=(Button) findViewById(R.id.btnstart);
 btnstart.setOnClickListener(new View.OnClickListener() {
 public void onClick(View arg0) {
 doStart();
 }
 });
 //viết lệnh cho handler class để nhận thông điệp
 //gửi về từ tiến trình con
 //mọi thông điệp sẽ được xử lý trong handleMessage
 //từ tiến trình con ta gửi Message về cho main thread
 handler=new Handler(){
 public void handleMessage(Message msg) {
 super.handleMessage(msg);
 //msg.arg1 là giá trị được trả về trong message
 //của tiến trình con
 bar.setProgress(msg.arg1);
 lblmsg.setText(msg.arg1+"%");
 }
 };
 lblmsg=(TextView) findViewById(R.id.textView1);
 }
 public void doStart()
 {
 bar.setProgress(0);
 isrunning.set(false);
 //tạo 1 tiến trình CON
 Thread th=new Thread(new Runnable() {
 @Override
 public void run() {
 //vòng lặp chạy 100 lần
 for(int i=1;i<=100 && isrunning.get();i++)
 {
 //cho tiến trình tạm ngừng 100 mili second
 SystemClock.sleep(100);
 //lấy message từ Main thread
 Message msg=handler.obtainMessage();
 //gán giá trị vào cho arg1 để gửi về Main thread
 msg.arg1=i;
 //gửi lại Message này về cho Main Thread
 handler.sendMessage(msg);
 }
 }
 });
 isrunning.set(true);
 //kích hoạt tiến trình
 th.start();
 }
 @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;
}

Bây giờ bạn tiến hành chạy ứng dụng và có kết quả như mong muốn. Chú ý rằng ta phải dùng đa tiến trình, nếu như chỉ dùng vòng lặp thông thường thì ứng dụng có vẻ như bị TREO, nó chỉ hiển thị kết quả ra khi đã thực hiện xong vòng lặp, còn ở đây ta dùng tiến trình thì nó sẽ thực hiện theo thời gian thực. Ta chỉ có thể cập nhật giao diện lúc Runtime ở Main Thread.

Bạn có thể tải coding mẫu ở đây:

http://www.mediafire.com/download/ogqfj1lfziy9d2s/LearnMultiThreading_usingMessage.rar

Bài kế tiếp Tôi sẽ làm tiếp một ví dụ về Using Message của Handler class, trong ví dụ này Tôi sẽ cho vẽ các Button lúc runtime, các bạn chú ý theo dõi để hiểu thêm về cách sử dụng Handler class trong việc xử lý đa tiến trình.

chúc các bạn thành công.

Nguồn: http://duythanhcse.wordpress.com/category/l%E1%BA%ADp-trinh-android/