Bài 2: Xử lý sự kiện trong chương trình Android


Trong bài này tôi sẽ trình bày cách xử lý các sự kiện trong chương trình Android để tạo cho chương trình nét linh động và thực hiện các xử lý phức tạp hơn. Để minh hoạ, tôi sẽ xây dựng một ứng dụng mẫu có tên là Sức khoẻ của bạn.

Bài báo sẽ bao gồm 5 phần chính như sau: phần 1 mô tả cấu trúc một chương trình Android; phần 2 trình bày vòng đời của Activity trong Android; phần 3 mô tả ý tưởng thiết kế chương trình Sức khoẻ của bạn; phần 4 trình bày cách hiện thực chương trình Sức khoẻ của bạn, phần 5 tổng kết và đưa ra các gợi ý nâng cấp chương trình với những yêu cầu phức tạp hơn.

1. Cấu trúc 1 project Android:
Trong bài 1, các bạn đã làm quen với môi trường Eclipse trong việc phát triển ứng dụng, trong bài này, ta sẽ lần lượt khám phá các chi tiết trong đó để làm cho chương trình thông minh hơn. Việc giải thích về một chương trình Android như thế nào và các thành phần bao gồm ra sao đã được rất nhiều sách giải thích cặn kẽ về nó. Các bạn có thể tìm đọc thêm tại đây: http://www.vogella.com/articles/Android/article.html. Vogella là một tác giả rất năng động và đóng góp nhiều cho cộng đồng mã nguồn mở Android.

Trong khuôn khổ chuỗi hướng dẫn lập trình Android thông qua ví dụ, tôi đã làm sẵn các chương trình và để tiện theo dõi, các bạn hãy download toàn bộ source code của project MyHealth và import vào workspace của các bạn [5].

Trước tiên, hãy xem trong cửa sổ số 1: Package Explorer. Ta sẽ quan tâm các thư mục sau: src/, res/layout, và res/values/.
Thư mục src chứa tất cả các file mã nguồn của chương trình. Trong bài này chỉ có 1 file duy nhất đó là MainActivity.java.
Thư mục res chứa các file tài nguyên (hình ảnh, giá trị, thiết kế giao diện,…) của 1 project Android.

2. Một chút lý thuyết về Activity trong Android:
Có thể nói, HĐH Android tuy dành cho những chiếc điện thoại di động nhỏ bé nhưng chứa đựng đằng sau nó một kho tàng tri thức mà kể cả những lập trình viên lâu năm cũng còn phải liên tục học hỏi. Do đó, với cách tiếp cận từ ví dụ, tôi hy vọng là sẽ giúp các bạn có thể từ từ khám phá để làm chủ nó.

Trước tiên là từ khoá Activity. HĐH Android gọi hoạt động của một chương trình là Activity. Một chương trình có thể có một Activity hoặt nhiều Activities. Tập tin MainActivity.java chính là của ngõ đầu tiên bước vào chương trình. Nó được ví như hàm main() trong ngôn ngữ C vậy.

Một activity có những trạng thái của nó như đang chạy – Running, đang dừng – Pause, dừng hẳn – Stopped, và bị huỷ - destroyed (Hình 1). Bạn có thể tìm hiểu thêm chi tiết về nó tại [6]. Nhưng trong khuôn khổ bài này, chúng ta chỉ làm việc với trạng thái đang chạy.

Hình 1. Vòng đời của Activity.


Đoạn mã sau là toàn bộ nội dung tập tin MainActivity.java
 public class MainActivity extends Activity  {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Tiếp theo, tập tin res/layout/activity_main.xml chính là tập tin thiết kế giao diện chương trình. Tại đây, nó khai báo tất cả những đối tượng chính nằm trên màn hình của ứng dụng.
Các đối tượng được bố trí trên màn hình theo các dạng layout khác nhau: linear layout, grid layout, table layout, và một số layout khác. Để tìm hiểu kỹ thêm về các layout, các bạn có thể tìm đọc trong tham khảo [7]. Trong bài này, tôi sử dụng Tablet layout, có nghĩa là các đối tượng được bố trí theo hàng và cột.

Cuối cùng đó là tập tin res/strings.xml, đây là tập tin lưu các giá trị của các dòng thông báo trong project. Android khuyến khích các lập trình viên khai báo các biến trong đây để dễ dàng thay đổi một cách thống nhất khi chương trình có sự thay đổi lớn.

Chúng ta vừa khảo sát qua các tập tin chính trong project MyHealth. Bao gồm các tập tin quan trọng. Trong phần tiếp theo, chúng ta sẽ định nghĩa bài toán và tìm phương án giải quyết để có được chương trình mong muốn.

3. Ý tưởng thiết kế chương trình Sức khoẻ của bạn
Ngày nay, khi kinh tế phát triển thì con người ta có nhiều lựa chọn trong việc ăn uống hơn. Do đó, việc tăng cân không mong muốn và dẫn đến thừa cân, béo phì đang làm ảnh hưởng rất lớn đến sức khoẻ. Nhất là việc ảnh hưởng này diễn ra một cách âm thầm và êm ái qua việc ăn uống của chúng ta. Do đó, việc theo dõi sức khoẻ qua chỉ số Body Mass Index (BMI) – Tạm dịch là Chỉ số trọng lượng cơ thể, sẽ là một cách quản lý việc ăn uống của mình tốt hơn.

Chỉ số BMI đơn giản là một công thức tỷ lệ giữa trọng lượng chia cho bình phương chiều cao cơ thể (Công thức 1). Căn cứ vào chỉ số BMI này, các nhà khoa học đã tìm ra một bảng tra cứu chỉ số BMI để cho biết là chỉ số này nằm trong khoảng nào là bình thường, nằm trong khoảng nào là bất thường (Bảng 1).

Công thức tính BMI 


Công thức 1: cách tính BMI, trong đó: Mass=trọng lượng cơ thể tính bằng kg, và Height: chiều cao cơ thể tính bằng mét.
Chỉ số BMI trung bình trong bài này tôi tính dựa theo chỉ số khuyến nghị của tổ chức y tế thế giới [3]. Trong khi đó, các chỉ số có thể rất khác nhau cho các quốc gia, chủng tộc khác nhau (ví dụ trong [4]).

Bảng 1. Chỉ số BMI và các nguy cơ

Nhận thấy, chỉ số BMI được tính bằng công thức đơn giản như trên chỉ với 2 thông số đầu vào: trọng lượng cơ thể và chiều cao cơ thể. Bài toán của chúng ta đặt ra đó là ta cần lấy 2 thông số đầu vào do người dùng nhập vào, sau đó tính theo công thức số 1 rồi xuất ra màn hình. Ta có thể làm một chương trình nho nhỏ ngay trên chiếc điện thoại Android của ta để phục vụ nhu cầu theo dõi và chăm sóc sức khoẻ chủ động.

4. Cách hiện thực chương trình Sức khoẻ của bạn
Để làm được chương trình, tôi tạm thiết kế sử dụng 3 thành phần cơ bản trong Android (widgets) như sau: TextView, EditText, và Button. Đồng thời để lắng nghe sự kiện Click, hay Chạm vào Button, tôi phải hiện thực thêm một phương thức nữa đó là OnClickListener.

Trước tiên là giao diện được thiết kế theo hình 2.

Hình 2. Thiết kế giao diện.


Trong đó, file thiết kế được hiện thực như sau:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/TableLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TableRow >
        <TextView
            android:id="@+id/WeightInput"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/Weight_input"  />
  
    <EditText
        android:id="@+id/WeightInputEdt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="7"
        android:inputType="numberDecimal" >
        <requestFocus />
    </EditText>
     </TableRow>

    <TableRow>
      <TextView
        android:id="@+id/HeightInput"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/Height_input"  />

     <EditText
        android:id="@+id/HeightInputEdt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="7"
        android:inputType="numberDecimal" />
     </TableRow>
    
     <Button
             android:id="@+id/CalculateBMI"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/CalculateBMI" />
            
<TableRow>
    <TextView
        android:id="@+id/BMI"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/BMI"   />

    <EditText
        android:id="@+id/BMIEdt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="7"
        android:enabled="false"
        android:inputType="numberDecimal" />
</TableRow>
    
</TableLayout>



Lưu ý là các tag android:text="@string/*"   tôi đều sử dụng biến được khai báo trong tập tin strings.xml. Về lý thuyết, các bạn hoàn toàn có thể thay đổi nội dung text trong các trường này. Nhưng nếu làm như vậy chương trình sẽ khó thay đổi về sau.

Phần quan trọng tiếp theo là phần xử lý sự kiện cho nút Calculate BMI. Như đã đề cập trong phần đầu, tôi hiện thực phương thức lắng nghe sự kiện Click chuột hoặc touch vào màn hình sử dụng OnClickListener.
 touch vào màn hình sử dụng OnClickListener.

public class MainActivity extends Activity implements OnClickListener { …

Khi thực thi hàm này, Eclipse sẽ gợi ý ta thêm method OnClick()

   @Override
  public void onClick(View v) {

  }
Đây chính là điểm mà ta sẽ xử lý thông tin tính BMI.
Toàn bộ code của chương trình nằm trong file MainActivity.java như sau:

package vn.edu.uit.uitubicom.myhealth;

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;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button CalculateBMI_Btn = (Button) findViewById(R.id.CalculateBMI);        /* Hàm này dùng để tìm đến đúng đối tượng nút CalculateBMI. */

        CalculateBMI_Btn.setOnClickListener(this); /* Sau khi tìm thấy nó, ta lắng nghe sự kiện click vào nó */

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        /* Hàm này để thiết kế menu, ta chưa cần quan tâm trong bài này */
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


     @Override
     public void onClick(View v) {
          try{
          EditText edtWeight = (EditText) findViewById(R.id.WeightInputEdt);
          EditText edtHeight = (EditText) findViewById(R.id.HeightInputEdt);

/* Vì các đối tượng nằm trong giao diện là thuộc đối tượng EditText, nên ta phải lấy quyền điều khiển nó bằng hàm findViewById */

  String sWeight = edtWeight.getText().toString();
        String sHeight = edtHeight.getText().toString();
         
/*  Sau khi lấy được quyền điều khiển, ta sẽ lấy nội dung text input và gán nó vào 2 biến tạm sWeight, sHeight */


          float fWeight = Float.valueOf(sWeight);
          float fHeight = Float.valueOf(sHeight);
/* Một thủ thuật nhỏ để chuyển đổi kiểu dữ liệu từ text sang số thập phân để tính toán. */
         
          float fBMI = fWeight / (fHeight*fHeight);
/* Đây chính là lúc ta áp dụng công thức 1 vào để tính BMI */

         
          EditText edtBMIEdt = (EditText) findViewById(R.id.BMIEdt);
          edtBMIEdt.setText(String.valueOf(fBMI));
/*  Sau khi đã tính được BMI, ta bắt đầu gán ngược lại giá trị cho khung ghi kết quả */
         
          }catch(Exception e ){
            Toast.makeText(v.getContext(), "Error during calculating BMI"+e.toString(), 1000);  
          }
     }   

}
Chương trình khi chạy sẽ có giao diện như sau:
Hình 3.Giao diện chương trình khi hoàn tất


Bây giờ những việc các bạn có thể làm là download source code để thử trải nghiệm những nét thú vị của Android bằng chương trình thứ 2, một chút phức tạp hơn, một chút trải nghiệm nhiều hơn sự tuyệt vời của Android.

5. Tổng kết và hướng phát triển

Tóm lại, bài này tôi đã trình bày với các bạn về Activity và cách thức lắng nghe sự kiện click/chạm vào một đối tượng trên Android. Đồng thời, các bạn cũng được làm quen với cách thiết kế giao diện đơn giản với nhiều đối tượng sẵn có của Android. Thông qua ví dụ hữu ích đó là tính ra chỉ số BMI đã cho các bạn phần nào một góc nhìn hẹp và cụ thể để xử lý sự kiện và áp dụng vào thực tế lập trình. Công việc của các bạn lúc này là hãy download source code (tại link [5]) để tiến hành thực tập ngay những gì đã được mô tả bên trên để tự mình khám phá.

Các bạn có thể mở rộng thêm độ phức tạp của chương trình bằng cách thêm các đánh giá, gợi ý khi có kết quả BMI trả về theo bảng số 1. Ví dụ khi nhận được BMI > 25 thì chương trình cảnh báo, bạn sẽ gặp phải những nguy cơ gì. Chúc các bạn có được những chương trình sáng tạo hữu ích.


Tài liệu tham khảo
[1] Meier, R., Professional Android 4 Application Development Wiley, 2012
[2] Vogella, Android Development Tutorial, 8/2013, http://www.vogella.com/articles/Android/article.html, Last visited: 29/9/2013.
[3] BMI classification, http://apps.who.int/bmi/index.jsp?introPage=intro_3.html, Last visited: 29/9/2013.

[4] WHO Expert Consultation. Appropriate body-mass index for Asian populations and its implications for policy and intervention strategies. Lancet. 2004;363(9403):157-163
[5] Project mẫu tính BMI, http://www.mediafire.com/?2l2q4rrexklupxp
[6] Android Lifecycle, http://developer.android.com/training/basics/activity-lifecycle/index.html
[7] Android Layout, http://developer.android.com/guide/topics/ui/declaring-layout.html

Nhận xét

Đăng nhận xét