Bài tập 34: đa tiến trình trong Android (Multi-Threading)


– 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.


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


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 :


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 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


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.

33 responses

  1. Xin cam on nhung bai huong dan rat hay cua Thay

    1. xin thầy hướng dẫn làm cách nào để chạy được bài tập mẫu mà thầy gửi lên. em làm nhiều lỗi quá mà không biết sai ở đâu.

      1. Bùi Quang Vinh

        Dễ lắm bạn.
        1) Down về
        2) BỎ vào cái chỗ cài Eclipse cho tiện nhé / hay chỗ mấy file .apk build ra
        3) Vào IDE
        4) Bật File -> Import -> General -> Existing Projects into Workspace -> Next
        5) Chỗ Select Root Directory -> Browse -> tìm đến thư mục chứa project ( folder được extract ra chứ ko fai file .zip nhé )
        6) Next hay OK gì đó là xong
        7) Có thể lúc load vào thì thấy Project có dấu x màu đỏ thì bấm chuột phải vào Project đó , chọn Properties -> chọn Android -> trong Project build target -> tick vào cái hàng đầu tiên -> Apply -> xong ^^
        Chúc bạn thành công !

  2. Chân thành cảm ơn thầy Thanh.

  3. cám ơn thầy rất nhiều … em đang chờ bài Broadcast Receiver và Telephony của thầy :)… hihi

  4. Cám ơn thầy nhiều ạ, khi nào có thể thầy làm bài lấy rss, json cho bọn e nha thầy, cám ơn thầy rất nhiều ạ

  5. hu hu hu thầy ơi. Sao mãi mà không có bài viết mới vậy ạ. Bọn em đang chờ đón những kiến thức hay từ thầy ạ

  6. cám ơn thầy rất nhiều

  7. Em cảm ơn thầy rất nhiều, cảm ơn thấy đã tiếp thêm ánh sáng tri thức cho chúng em!

  8. học xong cảm thấy tự tin hản thầy ạ . mong thầy tiếp tục hướng dẫn thêm nhiều bài nữa

  9. cảm ơn thầy rất nhiều. nhờ thầy mà em học thêm được rất nhiều kiến thức bổ ích.
    em mong được học những bài tiếp theo của thầy

  10. Đang nóng lòng đợi bài mới 😀

  11. Rất mong thầy sớm có những bài viết tiếp theo! cảm ơn thầy vì những bài viết bổ ích!

  12. Đang chờ bài viết về Handler class và AsyncTask class mà lâu quá thầy ạ, các bài viết của thầy thật sự hay và hữu ích lắm. Cảm ơn thầy

  13. em cảm ơn thầy.
    những bài viết thật tuyệt vời
    chúc thầy mạnh khỏe để bồi dưỡng thế hệ trẻ việt nam

  14. thật sự thì tôi chỉ mất có ~2h để xem các kiến thức của anh đã truyền đạt, nó mang nhiều ý nghĩa vì những ví dụ gần gũi và trực quan. Thật ra nếu anh làm clip Youtube và upload mã nguồn như ở đây thì sẽ rất tuyệt vì anh có thể giải thích được nhiều hơn.

  15. cảm ơn thầy vè những bài viết tuyệt vời, em mong đợi các bài giảng tiếp theo của thầy ạ.

  16. thầy ơi, thầy viết tiếp đi ạ, chúng em rât mong ạ

  17. Thầy ơi, bao giờ thì bài này “ra lò” thế ạh ?!, Emd đang vướng mắc chỗ này, rất mong được thầy hướng dẫn !

  18. Em cảm ơn! Thầy ơi! đầu tư làm cuốn sách lập trình android luôn thầy.

  19. […] Bài tập 34: đa tiến trình trong Android (Multi-Threading)In “6. Xử lý đa tiến trình trong Android” […]

  20. Bùi Quang Vinh | Reply

    cho mình hỏi là tại sao cần biến bool đó làm gì vậy ? bỏ đi có vấn đề gì ko? Xin cám ơn

  21. Biến isRunning dùng để tránh trường hợp khi tiến trình đang cập nhật trạng thái progressBar, người dùng bấm btnStart lần nữa thì sẽ có thêm tiến trình khác cập nhất progressBar. Vì vậy trong phương thức OnClick() cần kiểm tra trạng thái isRunning if(isRunning.compareAndSet(false, true)){
    doStart();
    }
    và khi i = 100 phải set lại isRunning.set(false);

    Cảm ơn thầy!

  22. hàm isrunning là của đối tượng nào, vào để làm gì, sao nó báo lỗi nhỉ

  23. ý nghĩa “isrunning.get()” trong vòng lặp for (int i = 1; i <= 100 && isrunning.get(); i++) là gi vậy mọi người. thanks ạ!

  24. Sao no ko chay vay ta @@

  25. thưa thầy, thầy có thế giải thích rõ hơn ý nghĩa của “isrunning.get()” for (int i = 1; i <= 100 && isrunning.get(); i++) được không. và khi e ấn nút start lần 2 khi progressbar đang chạy thì nó dựt dựt giống như có progressbar khác đang chạy theo.em cảm ơn!

  26. […] Bài tập 34: đa tiến trình trong Android (Multi-Threading) […]

  27. thầy ơi cho em hỏi:
    em có 1 cái AsyncTast và 1 method
    method và AsyncTast đều được gọi ra trong onCreate của Activity_Main
    cái method của em cần dữ liệu từ AsyncTast nên khi chạy chương trình bị lỗi
    em nghĩ là lỗi này là do ta tạo ra 1 cái AsyncTast thì nó sẽ chạy song song với method nên method chưa lấy được dữ liệu.
    thầy có cách nào để chạy xong cái AsyncTast thì mới chạy cái method ko ạ?
    (method ko bỏ vào onPostExcute của AsyncTast được)

  28. Здравствуйте уважаемые!
    Предлагаем Вам
    Дробилка для ПЭТ , Мы изготавливаем шредеры под заказ
    Новости Гамма-Инструмент здесь

  29. 🙂

  30. Ấn nút Start liên tiếp nhiều lần mới thấy tác dụng của đa tiến trình là thế nào 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: