Bài 6: Làm quen với một số kiểu lập trình sự kiện trong android

     Ở bài tập trước, các bạn đã học được cách sử dụng một vài loại layout cơ bản giúp các bạn thiết kế giao diện chương trình. Trong bài tập này, chúng ta cùng tìm hiểu một vài kiểu lập trình sự kiện trong android với Button. Button(nút) là một trong những control quan trọng nhất trong android, vì vậy mình mong rằng các bạn cần phải thật sự hiểu và nắm chắc về nó.


1.Kiểu sự kiện Inline anonymous listener với Button.


-Ví dụ sau đây sẽ là một ví dụ đơn giản nhất: "Tính tổng 2 số". Phân tích một chút về đề bài, chúng ta phải có 2 ô Editext giúp các bạn nhập dữ liệu của 2 số, 1 nút Button để tính tổng, và một TextView giúp chúng ta hiển thị kết quả. Các bạn xem qua về giao diện mình tranh thủ thiết kế
-Giao diện rất đơn giản mình mong rằng các bạn nhìn vào đây, áp dụng kiến thức về layout trước và cố gắng thiết kế giao diện. Các bạn cũng có thể tham khảo outline của mình dưới đây
Và sau đây là code của chương trình này. Các bạn cần nghiên cữu kỹ về code và các chú thích kèm theo của mình nhé
+File giao diện activity_main.xml:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stretchColumns="*">
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span = "3"
            android:textColor="#FFFFFF"
            android:background="#0000A0"
            android:textSize="20sp"
            android:gravity="center"
            android:text="Chương trình tính tổng 2 số"/>
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/edtSoA" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="1" 
            android:inputType="number"      />
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="+"/>
        <EditText
            android:id="@+id/edtSoB" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="1"          
            android:inputType="number"   />
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btnTong"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span="3"
            android:text="Tính tổng" />
            
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:id="@+id/txtKetQua"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span = "3"
            android:textColor="#FFFFFF"
            android:background="#0000A0"
            android:textSize="20sp"
            android:gravity="center"      />
    </TableRow>
   
</TableLayout> 
+File MainActivity.java:

package com.example.hellowolrd;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

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

        //Tạo một đối tượng Button gọi tới Button btnTong trong
        //activity_main.xml. Đối tượng Button này xử lý các sự kiện
        //của button trong activity.
        Button btnTong = (Button)findViewById(R.id.btnTong);
        //gọi bộ lắng nghe sự kiện của nút khi Onclick. 
        //Các bạn chú ý khi code thì sử dụng thêm tổ hợp Ctrl+space nhé
        //nhớ phải import đầy đủ các gói View nhé
        btnTong.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                
                //Tương tự Button, tạo 2 object EditText thôi
                EditText soA = (EditText)findViewById(R.id.edtSoA);
                EditText soB = (EditText)findViewById(R.id.edtSoB);
                //Lấy giá trị của số nhập vào, ép kiểu sang float
                float a = Float.parseFloat(soA.getText().toString());
                float b = Float.parseFloat(soB.getText().toString());
                //Tương tự Button
                TextView kq = (TextView)findViewById(R.id.txtKetQua);
                //Hiển thị kết quả
                kq.setText(""+(a+b));
            }
        });
    }
}
Các bạn đọc code và chú thích, tự mình code lại để nhớ sâu nhé. Quan trọng nhất là setOnclickListener và đoạn tạo đối tượng Button, EditText và TextView nhé. Và đó cũng là Kiểu sự kiện Inline anonymous listener

2. Activity is listener:

- Với cách lập trình sự kiện này, Activity sẽ implements interface (Có nghĩa là kế thừa từ nhiều loại interface có sẵn). Mình sẽ ví dụ về trường hợp của Button cho các bạn có thể nắm vững.

- Đề bài: Tính chỉ số khối của cơ thể con người - chỉ số BMI. Chỉ số này sẽ đánh giá mức độ gầy hay béo của con người, giúp chúng ta xác định một người gầy hay là bếu phì.
     +Công thức tính: BMI = W/(H*H)

-Phân loại đánh giá béo - gầy:
  • BMI < 18: người gầy
  • BMI = 18 – 24,9: người bình thường
  • BMI = 25 – 29,9: người béo phì độ I
  • BMI = 30 – 34,9: người béo phì độ II
  • BMI > 35: người béo phì độ III
Theo đề bài, mình tạm thời thiết kế một giao diện chương trình như sau:
Source code activity_main.xml:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stretchColumns="*">
  
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span = "2"
            android:textColor="#FFFFFF"
            android:background="#0000A0"
            android:textSize="20sp"
            android:gravity="center"
            android:text="Chương trình tính chỉ số BMI"/>
    </TableRow>
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Chiều cao"/>
        <EditText 
            android:id="@+id/edtChieuCao"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:ems="10"/>
    </TableRow>
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cân nặng"/>
        <EditText 
            android:id="@+id/edtCanNang"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:inputType="numberSigned"
            android:ems="10"/>
    </TableRow>
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button android:id="@+id/btnTinh"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span = "2"
            android:text="Tính chỉ số BMI"/>
    </TableRow>
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5sp">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Chỉ số BMI:"/>
        <TextView 
            android:id="@+id/txtChiSo"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </TableRow>
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5sp">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Đánh giá: "/>
        <TextView 
            android:id="@+id/txtDanhGia"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </TableRow>
   
</TableLayout>

Các bạn chú ý là tại EditText, mình có thiết lập một thuộc tính inputType với giá trị là number. Có nghĩa là khi bạn nhập chỉ được phép nhập số. Bàn phím trong android cũng chỉ hiển thị và cho phép nhập số. Các bạn có thể thử trong emulator của mình

+MainActivity.java

package com.example.hellowolrd;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
//Chú ý dòng này, có thêm implements OnclickListener
//Nhiều người quên mất đoạn này thành ra chạy sẽ lỗi
public class MainActivity extends ActionBarActivity implements OnClickListener {



    Button btnTinhBMI;
    EditText edtChieuCao, edtCanNang;
    TextView txtChiSo, txtDanhGia;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Gọi hàm lấy các control cho View
        getControlView();
        btnTinhBMI.setOnClickListener(this);
    }
    
    //Viết lại sự kiện onClick của nút
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
       
        //Chú ý hàm try-catch bắt lỗi khi bạn chưa nhập dữ liệu
        try {
            //Lấy giá trị nhập vào và ép kiểu về Float
            float chieuCao = Float.parseFloat(edtChieuCao.getText().toString());
            float canNang = Float.parseFloat(edtCanNang.getText().toString());
            float BMI = canNang/(chieuCao*chieuCao);
            txtChiSo.setText(BMI+"");
            if(BMI<18){
                txtDanhGia.setText("Bạn hơi gầy");
            }else if(18<=BMI && BMI<25){
                txtDanhGia.setText("Bạn bình thường");
            }else if(25<=BMI && BMI<30){
                txtDanhGia.setText("Bạn béo phì độ 1");
            }else if(30<=BMI && BMI<35){
                txtDanhGia.setText("Bạn béo phì độ 2");
            }else if(35<=BMI){
                txtDanhGia.setText("Bạn béo phì độ 3");
            }
        } catch (Exception e) {
            //Câu lệnh thông báo một dòng chữ nhỏ ở dưới ra màn hình
            Toast.makeText(getBaseContext(), 
                    "Bạn chưa nhập dữ liệu. Làm lại nào", Toast.LENGTH_SHORT).show();
        }
       
    }


    private void getControlView() {
        // TODO Auto-generated method stub
        btnTinhBMI = (Button)findViewById(R.id.btnTinh);
        edtChieuCao = (EditText)findViewById(R.id.edtChieuCao);
        edtCanNang = (EditText)findViewById(R.id.edtCanNang);
        txtChiSo = (TextView)findViewById(R.id.txtChiSo);
        txtDanhGia = (TextView)findViewById(R.id.txtDanhGia);
    }
    
}

Trong MainActivity các bạn cần chú ý 1 vài điểm sau:
+Phải implement OnclickListener chỗ khai báo class MainActivity. Đây là cách để viết sự kiện Activity Listeners.
+Câu lệnh Toast.makeText... đưa ra thông báo một dòng chữ nhỏ ở gần dưới cùng màn hình. Ở đây thông báo khi bạn không nhập dữ liệu cho 2 ô cân nặng và chiều cao. Trong câu lệnh này có 3 đối số:
      -Đối số thứ 1: getBaseContext() : Lấy Context đang làm việc. Tìm hiêu sâu hơn về vấn đề Context trong các bài sau này
      -Đối số thứ 2: dạng String dùng để hiển thị dòng thông báo
      -Đối số thứ 3: Thời gian hiển thị thông báo. Toast có 2 hằng số là Toast.LENGTH_SHORT (2.0 giây) và Toast.LENGTH_LONG (3.5 giây)

3.Listeners in variable

-Với trường hợp này, listeners được lưu trữ trong một biến do chúng ta tạo ra. Và vì vậy, chúng ta có thể chia sẻ chung một biến sự kiện cho nhiều trường hợp control khác nhau
-Mình sẽ đi vào một ví dụ để các bạn có thể  hiểu dễ hơn. Chúng ta cùng làm một ví dụ chương trình chuyển đổi mét sang dặm. Công thức: "1 mile =1 609.344 meters"
-Sau đây là giao diện của chương trình
Listeners in variable
Các bạn hãy tự mình thiết kế giao diện cho chương trình nhé. Tốt nhất là khi nào gặp vấn đề khó không giải quyết được thì tham khảo code của mình. Làm 1,2 lần là nhớ như in ngay.
Khi tạo một project mới thì nhớ xử lý cái fragment đi.
>>>Giải quyết vấn đề với Fragment Layout

+activity_main.xml:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stretchColumns="*">
   
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_span = "3"
            android:textColor="#FFFFFF"
            android:background="#0000A0"
            android:textSize="20sp"
            android:gravity="center"
            android:text="Chuyển đổi miles, metters"/>
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10sp">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Metters"
            android:textStyle="bold"
            android:textSize="17sp"
            android:textColor="#008000"/>
        <TextView />
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Miles"
            android:textStyle="bold"
            android:textSize="17sp"
            android:textColor="#008000"/>
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10sp">
        <EditText 
            android:id="@+id/edtMetters"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="5"
            android:inputType="number"/>
        
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="="/>
        
        <EditText
            android:id="@+id/edtMiles"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="5"
            android:inputType="number"/>
    </TableRow>
    
    <TableRow android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10sp">
        <Button 
            android:id="@+id/btnConvert2Mile"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/convert_2_miles"/>
        
        <TextView 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>
        
        <Button
            android:id="@+id/btnConvert2Metter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/convert_2_metters"/>
    </TableRow>
    
    
    
</TableLayout>

+strings.xml (nằm trong res/values)

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">HelloWolrd</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>

    <string name="convert_2_miles">Convert to \n miles</string>
    <string name="convert_2_metters">Convert to \n metters</string>
</resources>

+Cuối cùng là MainActivity.java

package com.example.hellowolrd;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
//Chú ý dòng này, có thêm implements OnclickListener
//Nhiều người quên mất đoạn này thành ra chạy sẽ lỗi
public class MainActivity extends ActionBarActivity  {

    Button btnConvert2Miles, btnConvert2Metters;
    EditText edtMiles, edtMetters;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Gọi hàm lấy các control cho View
        getControlView();
        //đặt bộ listerner là một biến myNewListeners
        btnConvert2Metters.setOnClickListener(myNewListeners);
        btnConvert2Miles.setOnClickListener(myNewListeners);
    }
    //Khai báo biến myNewListeners và viết lại hàm onClick
    private OnClickListener myNewListeners = new OnClickListener() {
        
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //Nếu biến myNewListeners được đặt cho btn2Metters
            if(v == btnConvert2Metters){
                try {
                    //Lấy dữ liệu từ ô Miles. Nếu chưa nhập hoặc lỗi chuyển đổi
                    //sẽ nhẩy vào thực hiện ở vòng catch
                    float fMiles = Float.parseFloat(edtMiles.getText().toString());
                    //Tính toán và show giá trị
                    edtMetters.setText(""+fMiles/1609.344f);
                } catch (Exception e) {
                    // TODO: handle exception
                    Toast.makeText(getBaseContext(), 
                            "Bạn chưa nhập dữ liệu ô Miles", Toast.LENGTH_SHORT).show();
                }
            }//Nếu biến myNewListeners được đặt cho btn2Miles
            else if(v == btnConvert2Miles){
                try {
                    float fMetters = Float.parseFloat(edtMetters.getText().toString());
                    //Tính toán và show giá trị
                    edtMiles.setText(""+fMetters*1609.344f);
                } catch (Exception e) {
                    // TODO: handle exception
                    Toast.makeText(getBaseContext(), 
                            "Bạn chưa nhập dữ liệu ô Metters", Toast.LENGTH_SHORT).show();
                }
            }
        }
    };

    private void getControlView() {
        // TODO Auto-generated method stub
        btnConvert2Miles = (Button)findViewById(R.id.btnConvert2Mile);
        btnConvert2Metters = (Button)findViewById(R.id.btnConvert2Metter);
        edtMetters = (EditText)findViewById(R.id.edtMetters);
        edtMiles = (EditText)findViewById(R.id.edtMiles);
    }
}
Các bạn chú ý code phần tạo biến listener mới và cách viết hàm của nó để áp dụng vào thực tế. Code đã được chú thích đầy đủ, nếu có gì không hiểu thì comment lại đừng ngại nhé.

Vậy là qua bài tập này, các bạn đã nắm chắc được một vài kiểu lập trình sự kiện thường được sử dụng trong android và cách thiết kế giao diện kết hợp, cùng với sử dụng một vài control trong android như Button, EditText, TextView... Mình hy vọng sẽ giúp ích được các bạn trong quá trình học tập môn lập trình android này. Hẹn gặp lại các bạn trong các bài sau.

>>>Bài 7: Toast và Alert Dialog.  

No comments:

Post a Comment