Tự động tạo các thành phần cho Class bằng Lombok trong Android Studio

bài trước, Tui có hướng dẫn cách sử dụng Lombok trong Eclipse, bài này Tui tiếp tục sử dụng Lombok trong Android Studio để hướng dẫn các bạn cách tự động tạo các thành phần cho Class.

Ta có 3 bước chính để sử dụng được Lombok trong Android Studio.

Bước 1: Cài đặt Plugin Lombok

Bước 2: Chỉnh dependencies

Bước 3: Viết annotation cho Class.

Bây giờ ta đi vào chi tiết từng bước.

Để cài đặt Plug-in Lombok ta có vài chỗ để cài. Một là từ màn hình Welcome/chọn Configure/ chọn Plugins. Hai là từ Project đang mở sẵn ta vào File > Settings > Plugins

từ màn hình Plugins này ta tìm Lombok để cài.

Hình trên là từ màn hình Welcome ta chọn Configure

Sau đó chọn Plugins, màn hình Plugins hiển thị ra như bên dưới:

Mục tìm kiếm ta gõ “lombok”, sau đó nhìn bên góc phải có nút “Install”, ta nhấn Install để cài đặt:

Sau khi cài đặt xong ta thấy nút ‘”Installed” bị mờ đi như dưới đây:

Nhấn OK để hoàn tất quá trình cài Lombok Plugins

Bây giờ ta tạo một Project tên: TestLombokAndroid (xem các bài về Android Studio 2020 tại đây):

Từ Android Studio/ chọn Create New Project:

Mục Templates chọn Phone and Tablet.

Mục chi tiết bên phải chọn Empty Activity

Nhấn Next để tiếp tục:

Đặt tên dự án: TestLombokAndroid

Các package cho phù hợp

ngôn ngữ Java

Minimum SDK 26

Sau đó nhấn Finish để tạo Project.

Sau đó vào build.gradle (Module):

Bổ sung thư viện Lombok vào dependencies:

dependencies {
compileOnly ‘org.projectlombok:lombok:1.18.16’
annotationProcessor ‘org.projectlombok:lombok:1.18.16’
}

chi tiết:

Tùy vào thời điểm chọn version mà bạn nhập cho đúng, sau đó nhấn “Sync Now

Tiếp theo ta tạo model: tranduythanh.com.model, và tạo một lớp SanPham có cấu trúc như dưới đây:

package tranduythanh.com.model;

public class SanPham {
private int ma;
private String ten;
private int soLuong;
private double donGia;
}

Ở trên, ta chỉ cần khai báo các thuộc tính mà thôi. Tiếp theo ta dùng các cú pháp của Lombok để setup cho lớp SanPham:

Mã lệnh:

package tranduythanh.com.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class SanPham {
private int ma;
private String ten;
private int soLuong;
private double donGia;
}

Ở trên ta thấy:

@AllArgsConstructor tự động tạo ra constructor đầy đủ đổi số.

@NoArgsConstructor tự động tạo ra constructor mặc định

@Data tự động tạo mọi getter/setter cho class

Bây giờ trong giao diện của Android, ta tiết kế 4 EditText, 1 Button để thử nghiệm class SanPham:

Code XML của activity_main.xml như sau:

Ta gán sự kiện cho Button “Thực hiện”:

chi tiết lệnh cho thucHienLombok:

package tranduythanh.com.testlombokandroid;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import tranduythanh.com.model.SanPham;

public class MainActivity extends AppCompatActivity {

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

public void thucHienLombok(View view) {
EditText edtMa=findViewById(R.id.edtMa);
EditText edtTen=findViewById(R.id.edtTen);
EditText edtSoLuong=findViewById(R.id.edtSoLuong);
EditText edtDonGia=findViewById(R.id.edtDonGia);

SanPham sp1=new SanPham(
Integer.parseInt(edtMa.getText().toString()),
edtTen.getText().toString(),
Integer.parseInt(edtSoLuong.getText().toString()),
Double.parseDouble(edtDonGia.getText().toString()));

Toast.makeText(this,sp1.toString(),Toast.LENGTH_LONG).show();
}
}

Chạy phần mềm lên ta có:

Ví dụ code ở trên dùng constructor đầy đủ đối số. Ta cũng có thể sử dụng Constructor mặc định và gọi các getter/setter:

SanPham sp1=new SanPham();
sp1.setMa(Integer.parseInt(edtMa.getText().toString()));
sp1.setTen(edtTen.getText().toString());
sp1.setSoLuong(Integer.parseInt(edtSoLuong.getText().toString()));
sp1.setDonGia(Double.parseDouble(edtDonGia.getText().toString()));
String info=”Mã=”+sp1.getMa()+”\n”+
“Tên=”+sp1.getTen()+”\n”+
“Số lượng=”+sp1.getSoLuong()+”\n”+
“Đơn giá=”+sp1.getDonGia();
Toast.makeText(this,info,Toast.LENGTH_LONG).show();

Chạy lên ta cũng có kết quả như mong muốn.

Đây là source code của bài này: https://www.mediafire.com/file/v8oqdvoqa0fmx70/TestLombokAndroid.rar/file

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

Bài 14. TextView, EditText, Button trong Android phần 2

Như vậy ở bài 13 Tui đã hướng dẫn các bạn lý thuyết về bộ 3 nguy hiểm TextView, EditText, Button. Bài này Tui sẽ ứng dụng nó để làm 1 tiện ích nho nhỏ đó là “Đọc số tiền bằng chữ”. Ví dụ khi người dùng nhập vào số tiền “8767543” -> “Tám triệu bảy trăm sáu mươi bảy nghìn năm trăm bốn mươi ba”

Tạo một dự án tên “DocTienBangChu”, thiết kế giao diện như hình dưới đây:

XML Layout code như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
android:background="#fff120"
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập số tiền bằng Số:" />

<EditText
android:id="@+id/editNumberOfMoney"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" />

<Button
android:id="@+id/btnDocTien"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đọc Tiền" />

<TextView
android:id="@+id/txtTextOfMoney"
android:layout_width="match_parent"
android:layout_height="151dp"
android:background="#fff120"
android:text="" />
</LinearLayout>
[/code]

Tiến hành cấu hình ViewBinding cho dự án, bạn nào chưa học bài ViewBinding thì xem lại bài 12.

Tiếp theo bấm chuột phải vào java/chọn new/ chọn package:

Màn hình Choose Destination Directory xuất hiện như dưới đây:

Chọn app\src\main\java

Rồi bấm OK:

Nhập package name là: tranduythanh.com.utils rồi nhấn Enter.

Ta thấy package utils xuất hiện ra như trên. Bây giờ tạo thư viện để đọc Tiền bằng số ra chữ (trên mạng có nhiều, thích tham khảo ở đâu cũng được, miễn là nó chạy đúng, ví dụ có thể tham khảo tại đây, mã nguồn bên dưới Tui cũng tham chiếu từ link đó cho các bạn dễ đọc):

Sau đó tạo một lớp tên là MoneyConverter:

Đặt tên xong thì double click vào Class, ta thấy kết quả như dưới đây:

Bây giờ tiến hành coding để đọc 1 số tiền bằng số ra chữ. Dĩ nhiên ta không phải học kỹ thuật đọc chữ thế nào, mà ta chỉ ứng dụng nó để làm việc với TextView , EditText, Button nên Tui sẽ bỏ qua bước giải thích thuật toán này (chi tiết bạn xem tại link ).

Dưới đây là coding MoneyConverter mà Tui có cấu trúc lại chút đỉnh:

[code language=”java”]
package tranduythanh.com.utils;
import java.util.ArrayList;
import java.util.Arrays;
public class MoneyConverter {
private static final String KHONG = "không";
private static final String MOT = "một";
private static final String HAI = "hai";
private static final String BA = "ba";
private static final String BON = "bốn";
private static final String NAM = "năm";
private static final String SAU = "sáu";
private static final String BAY = "bảy";
private static final String TAM = "tám";
private static final String CHIN = "chín";
private static final String LAM = "lăm";
private static final String LE = "lẻ";
private static final String MUOI = "mươi";
private static final String MUOIF = "mười";
private static final String MOTS = "mốt";
private static final String TRAM = "trăm";
private static final String NGHIN = "nghìn";
private static final String TRIEU = "triệu";
private static final String TY = "tỷ";
private static final String [] number = {KHONG, MOT, HAI, BA,
BON, NAM, SAU, BAY, TAM, CHIN};
public static String TextOfMoney(String numberOfMoney)
{
ArrayList<String> kq = new ArrayList<String>();
//Cắt chuổi string chử số ra thành các chuổi nhỏ 3 chử số
ArrayList<String> List_Num = Split(numberOfMoney, 3);
while (List_Num.size() != 0)
{
//Xét 3 số đầu tiên của chuổi (số đầu tiên của List_Num)
switch (List_Num.size() % 3)
{
//3 số đó thuộc hàng trăm
case 1:
kq.addAll(read_3num(List_Num.get(0)));
break;
// 3 số đó thuộc hàng nghìn
case 2:
ArrayList<String> nghin = read_3num(List_Num.get(0));
if(!nghin.isEmpty()){
kq.addAll(nghin);
kq.add(NGHIN);
}
break;
//3 số đó thuộc hàng triệu
case 0:
ArrayList<String> trieu = read_3num(List_Num.get(0));
if(!trieu.isEmpty()) {
kq.addAll(trieu);
kq.add(TRIEU);
}
break;
}
//Xét nếu 3 số đó thuộc hàng tỷ
if (List_Num.size() == (List_Num.size() / 3) * 3 + 1 && List_Num.size() != 1) kq.add(TY);
//Xóa 3 số đầu tiên để tiếp tục 3 số kế
List_Num.remove(0);
}
String textResult=String.join(" ",kq);
return textResult;
}
//Đọc 3 số
private static ArrayList<String> read_3num(String a)
{
ArrayList<String> kq = new ArrayList<String>();
int num = -1;
try{ num = Integer.parseInt(a); } catch(Exception ex){}
if (num == 0) return kq;

int hang_tram = -1;
try{ hang_tram = Integer.parseInt(a.substring(0, 1)); } catch(Exception ex){}
int hang_chuc = -1;
try{ hang_chuc = Integer.parseInt(a.substring(1, 2)); } catch(Exception ex){}
int hang_dv = -1;
try{ hang_dv = Integer.parseInt(a.substring(2, 3)); } catch(Exception ex){}
//xét hàng trăm
if (hang_tram != -1){
kq.add(number[hang_tram]);
kq.add(TRAM);
}
//xét hàng chục
switch (hang_chuc)
{
case -1:
break;
case 1:
kq.add(MUOIF);
break;
case 0:
if (hang_dv != 0) kq.add(LE);
break;
default:
kq.add(number[hang_chuc]);
kq.add(MUOI);
break;
}
//xét hàng đơn vị
switch (hang_dv)
{
case -1:
break;
case 1:
if ((hang_chuc != 0) && (hang_chuc != 1) && (hang_chuc != -1))
kq.add(MOTS);
else kq.add(number[hang_dv]);
break;
case 5:
if ((hang_chuc != 0) && (hang_chuc != -1))
kq.add(LAM);
else kq.add(number[hang_dv]);
break;
case 0:
if (kq.isEmpty()) kq.add(number[hang_dv]);
break;
default:
kq.add(number[hang_dv]);
break;
}
return kq;
}
private static ArrayList<String> Split(String str, int chunkSize) {
int du = str.length() % chunkSize;
//Nếu độ dài chuổi không phải bội số của chunkSize thì thêm # vào trước cho đủ.
if (du != 0)
for (int i = 0; i < (chunkSize – du); i++) str = "#" + str;
return splitStringEvery(str, chunkSize);
}
//Hàm cắt chuổi ra thành chuổi nhỏ
private static ArrayList<String> splitStringEvery(String s, int interval) {
ArrayList<String> arrList = new ArrayList<String>();
int arrayLength = (int) Math.ceil(((s.length() / (double) interval)));
String[] result = new String[arrayLength];
int j = 0;
int lastIndex = result.length – 1;
for (int i = 0; i < lastIndex; i++) {
result[i] = s.substring(j, j + interval);
j += interval;
}
result[lastIndex] = s.substring(j);
arrList.addAll(Arrays.asList(result));
return arrList;
}
}
[/code]

Bây giờ ta vào MainActivity để xử lý:

[code language=”java”]
package tranduythanh.com.doctienbangchu;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;

import tranduythanh.com.doctienbangchu.databinding.ActivityMainBinding;
import tranduythanh.com.utils.MoneyConverter;

public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding=ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
adEvents();
}
private void adEvents() {
binding.btnDocTien.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String docTien= MoneyConverter.TextOfMoney(binding.editNumberOfMoney.getText().toString());
binding.txtTextOfMoney.setText(docTien);
}
});
}
}
[/code]

Chạy lên ta có kết quả:

 

Như vậy Tui đã hướng dẫn xong bài ứng dụng TextView, EditText, Button để làm tiện ích đọc tiền bằng số ra chữ.

Ở bài này Ta ôn tập lại cách thức sử dụng 3 control cơ bản ở trên, sử dụng lại ViewBinding để truy suất tới các biến control trên giao diện cũng như gán sự kiện cho nó

Bạn có thể tải code mẫu ở đây: https://gitlab.com/duythanhcse/DocTienBangChu/

Bài học sau Tui sẽ hướng dẫn các bạn các kỹ thuật xử lý trên CheckBox, RadioButton

Các bạn chú ý theo dõi nhé

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

Bài 13. TextView, EditText, Button trong Android phần 1

Android cung cấp rất nhiều View/Control để ta có thể tùy chọn thiết kế giao diện tương tác người dùng. TextView dùng để hiển thị dữ liệu, EditText để hiển thị và cho phép thay đổi thông tin, Button để ra lệnh, CheckBox để chọn nhiều lựa chọn, RadioButton để chọn một lựa chọn, ImagView để hiển thị hình ảnh…

Trong bài này Tui sẽ trình bày về 3 View cơ bản nhất, mà bất kỳ một phần mềm cùi bắp nào cũng có đó là: TextView, EditText và Button.

13.1 TextView

TextView là view dùng để chỉ hiển thị dữ liệu không cho phép người sử dụng thay đổi dữ liệu. TextView thuộc nhóm Common và Text trong công cụ Palette:

Ta có thể kéo thả các View vào giao diện thiết kế một cách dễ dàng.

Bảng 13.1. Các thuộc tính/sự kiện quan trọng của TextView

Các thuộc tính/sự kiện Mô tả
android:id Id của TextView
android:layout_width Độ rộng
android:layout_height Độ cao
android:text Chữ hiển thị lên giao diện
android:textColor Màu chữ
android:textSize Cỡ chữ
android:background Màu nền
android:hint Chữ gợi ý khi android:text rỗng

Để truy suất TextView ta cần đặt Id cho nó trong thanh công cụ Properties hoặc trong XML. Hàm findViewById đã được giới thiệu trước đó dùng để truy suất View (Hoặc dùng ViewBinding được trình bày trong bài 12):

TextView txtMessage=findViewById(R.id.txtMessage);

Để thiết lập nội dung hiển thị ta có hai cách:

  • Trong Java code (Activity):

txtMessage.setText(“ Thầy Trần Duy Thanh ”);

  • Trong XML:

android:text=“ Thầy Trần Duy Thanh ”

[code language=”xml”]
<TextView
android:id="@+id/txtMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_red_light"
android:textColor="@android:color/holo_blue_light"
android:text="Khoa Hệ Thống Thông Tin"
android:textSize="30sp"
/>
[/code]

Ngoài id, text thì TextView còn có các thuộc tính quan trọng khác như: layout_width(thiết lập độ rộng), layout_height(thiết lập chiều cao), background(màu nền), textColor(màu chữ), textSize(cỡ chữ). Các thuộc tính cho TextView rất nhiều và được cung cấp sẵn trong công cụ Properties ta có thể vào đây để thao tác.

13.2 EditText

EditText là lớp kế thừa từ TextView, được dùng thay đổi nội dung text, chứa tất cả thuộc tính của TextView nên TextView hoạt động như thế nào thì EditText hoạt động như vậy, nằm trong nhóm Text của Palette. Đặt Id nên bắt đầu là là edt hoặc txt

Android đã tự động phân EditText thành nhiều loại khác nhau: Nhập chuỗi, số, điện thoại, email, mật khẩu … dựa vào thuộc tính inputType. Nhờ thuộc tính inputType mà trải nghiệm người dùng được tốt hơn, điện thoại sẽ hiển thị bàn phím tương ứng với inputType mà ta cấu hình giúp người dùng thao tác một cách dễ dàng và nhanh chóng:

EditText có nhiều thuộc tính quan trọng ta cần quan tâm:

Bảng 13.2. Các thuộc tính/sự kiện quan trọng của EditText

Các thuộc tính/sự kiện Mô tả
android:id Id của EditText
android:layout_width Độ rộng
android:layout_height Độ cao
android:text Chữ hiển thị lên giao diện
android:textColor Màu chữ
android:textSize Cỡ chữ
android:background Màu nền
android:hint Chữ gợi ý khi android:text rỗng
android:inputType Thiết lập loại dữ liệu nhập để có bàn phím phù hợp

Ta thấy trong nhóm Text rất nhiều View (EditText), tùy vào nhu cầu sử dụng mà ta kéo thả các EditText phù hợp ra.

Cấu trúc XML của Edittext:

[code language=”xml”]
<EditText
android:id="@+id/edtPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="1"
android:textColor="@android:color/holo_blue_light"
android:inputType="textPassword"
android:text="hoilamgi"

/>

[/code]

Thuộc tính inPutType= “textPassword” giúp ta khi nhập dữ liệu vào thì phần mềm tự động mã hóa thành các ký tự * để bảo mật. Edittext ngoài ra còn sử dụng Hint để nhắc nhớ người dùng, ta có thể bổ sung android:hint = “nhập mật khẩu ở đây”, người dùng sẽ biết ô này dùng để làm gì.

Để truy suất ta cũng dùng hàm findViewById (Hoặc dùng ViewBinding được trình bày trong bài 12):

EditText edtPassword=findViewById(R.id.edtPassword);

Để thay đổi nội dung hiển thị ta dùng: edtPassword.setText(“obama”)

Để lấy nội dung người dùng nhập liệu: edtPassword.getText().toString()

13.3. Button

Đối tượng Button được xây dựng từ TextView, cho phép thể hiện các nội dung văn bản, hình ảnh – nhận và phản hồi tương tác nhấn từ người dùng. Nên đặt Id cho Button bắt đầu bằng btn

Button thuộc nhóm Buttons hoặc Common trong công cụ Palette:

Các thuộc tính trong Button tương tự như trong TextView và EditText

Bảng 13.3. Các thuộc tính/sự kiện quan trọng của Button

Các thuộc tính/sự kiện Mô tả
android:id Id của EditText
android:layout_width Độ rộng
android:layout_height Độ cao
android:text Chữ hiển thị lên giao diện
android:textColor Màu chữ
android:textSize Cỡ chữ
android:background Màu nền
android:onClick Gán sự kiện cho Button

Cấu trúc XML của Button:

[code language=”xml”]
<Button
android:id="@+id/btnDangNhap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Đăng Nhập"
/>

[/code]

Button thường dùng để cho phép người dùng ra lệnh thực thi một nghiệp vụ nào đó, sự ra lệnh này gọi là các sự kiện (event). Button ngoài hiển thị dữ liệu còn có nhiệm vụ lắng nghe các sự kiện người dùng, hai cách nhanh nhất để lắng nghe sự kiện:

  • Lắng nghe trong XML: android:onClick=“tenPhuongThuc”
  • Lắng nghe trong java code:

btnDangNhap.setOnCLickListener(new OnClickLisntener() {

@Override

public void onClick(View v) {

xuLyDangNhap();

}

});

Chi tiết các kỹ thuật xử lý sự kiện sẽ được trình bày ở các bài sau.

Như vậy Tui đã trình bày xong phần lý thuyết của TextView, EditText và Button. Bài sau Tui sẽ làm một ví dụ cụ thể về ứng dụng của 3 Control này, dĩ nhiên Tui sẽ dùng kỹ thuật mới là ViewBinding để tương tác với các control trên giao diện, còn bạn nào  muốn dùng findViewById thì có thể xem tại đây).

Các bạn chú ý theo dõi nhé

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

Bài 12. ViewBinding trong Android

Như vậy ở bài 11 các bạn đã biết cách dùng findViewById để truy suất tới các control trên giao diện, tuy nhiên nó làm mất khá nhiều thanh xuân của lập trình viên, phải lặp đi lặp lại thao tác findViewById. Đặc biệt nó cũng khó tiếp cận cho những lập trình viên nhảy từ .Net qua.

Android Studio trong các phiên bản mới gần đây đã hỗ trợ ViewBinding để giúp chúng ta dễ dàng truy suất tới các control trên giao diện.

Bây giờ các bạn tạo một dự án tên “HocViewBinding“, sau đó vào file build.gradle (module:HocViewBinding.app):

Ở trên các bạn thấy nhóm android{}, xuống dưới cùng (thực ra chỗ nào cũng được) trong nhóm android{} ngày đằng sau compileOptions{}, bổ sung thêm lệnh:

[code language=”java”]
buildFeatures{
viewBinding=true
}
[/code]

Nếu bạn dùng Android version cũ hơn Tui đang sử dụng thì thay lệnh trên bằng:

[code language=”java”]
viewBinding {
enabled = true
}
[/code]

chi tiết bao gồm cả android {}:

[code language=”java”]
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "tranduythanh.com.hocviewbinding"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(‘proguard-android-optimize.txt’), ‘proguard-rules.pro’
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
buildFeatures{
viewBinding=true
}
}
[/code]

Sau đó nhớ nhấn Sync Now:

Sau khi Sync Now thành công thì tất cả các Layout (layout xml) trong dự án Android Studio sẽ được phát sinh ra một lớp, tương với tên Layout XML + Binding

Ví dụ: Ta vào thư mục “layout“, trong thư mục này có “activity_main.xml” thì nó sẽ tự động phát sinh ra một lớp tên là “ActivityMainBinding“, tương tự như vậy nếu ta có 1 layout khác tên là “activity_login.xml” thì nó cũng sẽ tự phát sinh thêm một lớp tên là “ActivityLoginBinding“:

Từ lớp binding này ta có thể cấu hình để có thể truy suất trực tiếp vào control trên giao diện mà không cần thông qua hàm findViewById.

Android cũng hỗ trợ cho phép ta cấu hình từ chối binding cho các layout, ví dụ có một layout nào đó mà bạn không muốn dùng binding thì thêm thuộc tính sau cho nó:

[code language=”xml”]

<LinearLayout

tools:viewBindingIgnore="true" >

</LinearLayout>

[/code]

Bây giờ ta sẽ vào phần xử lý mã nguồn để khai báo các biến sử dụng ViewBinding:

Đây là màn hình coding gốc ban đầu của MainActivity:

[code language=”java”]
package tranduythanh.com.hocviewbinding;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
[/code]

Ta viết mã lệnh để truy suất trực tiếp các control trên giao diện thông qua binding:

[code language=”java”]
package tranduythanh.com.hocviewbinding;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import tranduythanh.com.hocviewbinding.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
//khai báo biến binding có kiểu tương ứng với lớp được tạo ra từ layout của màn hình
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//gọi hàm inflate
binding=ActivityMainBinding.inflate(getLayoutInflater());
//thay thế đối số truyền vào cho setContentView bằng binding.getRoot()
setContentView(binding.getRoot());
}
}
[/code]

Tới đây, để truy suất tới bất kỳ biến control nào trên giao diện ta sẽ thông qua đối tượng binding. Bất cứ khi nào ta kéo thả control/view vào giao diện, đặt id cho control/view thì chỉ cần lấy {binding}.{id của control}.

Ví dụ giờ ta chỉnh sửa layout ta kéo một Button và 1 TextView vào giao diện (activity_main.xml) như sau:

code XML:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btnClickMe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Me" />
<TextView
android:background="#FF0F1F"
android:id="@+id/txtMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
[/code]

Bạn thấy Button Tui đặt id là “btnClickMe“, TextView Tui đặt là “txtMessage“.

Bây giờ quay lại màn hình mã lệnh, thêm hàm addEvents() để xử lý như sau:

[code language=”java”]
package tranduythanh.com.hocviewbinding;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import tranduythanh.com.hocviewbinding.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
//khai báo biến binding có kiểu tương ứng với lớp được tạo ra từ layout của màn hình
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//gọi hàm inflate
binding=ActivityMainBinding.inflate(getLayoutInflater());
//thay thế đối số truyền vào cho setContentView bằng binding.getRoot()
setContentView(binding.getRoot());
addEvents();
}
private void addEvents() {

}
}
[/code]

bạn không tạo hàm addEvents() cũng được, ở đây Tui tạo ra để cho các bạn làm quen, sau này các Project ở các bài học tiếp theo sẽ làm giống vầy, lý do là khi ta làm Project sẽ có rất nhiều control trên giao diện cũng như nhiều xử lý khác, do đó tốt nhất ta nên tách hàm ra để dễ quản lý, và tìm lỗi.

trong hàm addEvents() này ta sẽ thử tiến hành dùng binding để truy suất tới các control như sau nhé:

[code language=”java”]
private void addEvents() {
//truy suất trực tiếp tới biến btnClickMe để gán sự kiện nhấn vào Button:
binding.btnClickMe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//truy suất trực tiếp vào biến txtMessage để hiển thị chuỗi dữ liệu:
binding.txtMessage.setText("chào Thầy Trần Duy Thanh");
}
});
}
[/code]

Bạn thấy đấy, ở trên Tui không hề dùng findViewById nào cả, Tui dùng biến binding truy suất trực tiếp tới các biến control trên giao diện.

Chạy phần mềm lên ta có kết quả như bình thường:

Như vậy Tui đã hướng dẫn xong bài ViewBinding, tới đây bạn đã có được 2 kỹ thuật truy suất tới các biến control trên giao diện, bạn thích dùng kỹ thuật nào cũng được.

Coding bạn có thể tải ở đây:

https://drive.google.com/open?id=1o-ZDy0AQDG2_lr2bh8lbYOMa7q27sacZ

Các bài sau Tui sẽ trình bày về các control cơ bản như TextView, EditText, Button

Các bạn chú ý theo dõi nhé.

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

Bài 11. findViewById trong Android

Trong Android, để truy suất tới các control bất kỳ ta có nhiều cách: Ta có thể dùng findViewById hoặc dùng ViewBinding.

Trong bài này Tui sẽ trình bày về kỹ thuật dùng findViewById, bài sau sẽ nói về ViewBinding.

Khi lập trình Android, để tương tác với các View/Control trong giao diện chúng ta thường thông qua thuộc tính Id của các view/control để truy suất thay đổi dữ liệu. Vì Android chia màn hình (Activity) thành hai phần: Phần thiết giao diện, phần xử lý nghiệp vụ. Do đó để truy suất được tới các View trong phần giao diện Android cung cấp hàm findViewById (Tạm thời nó sẽ không quen thuộc với những ai đi từ .Net dev qua, ở bài sau học ViewBinding các bạn sẽ thấy dễ chịu hơn):

Ta chú ý mỗi lần đặt Id cho bất kỳ một View nào đó thì Id này sẽ tự động được phát sinh ra trong lớp R của Android. Vì vậy khi truy suất tới View ta dùng R.id.idView.

Phiên bản cũ phải ép kiểu (ở trên thấy (Button)findViewById)

Phiên bản mới hơn 1 chút không cần ép kiểu

Phiên bản mới ta có thể dùng ViewBinding thay thế cho findViewById.

Ví dụ:

Tạo một dự án tên là “HocFindViewById” có giao diện như sau (cách tạo xem tại đây):

Cod XML layout như dưới đây:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="21dp"
android:background="#FFEB3B"
android:text="Mời bạn nhập số phone:"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<EditText
android:id="@+id/edtPhoneNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="phone"
android:text="0987773061"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:layout_editor_absoluteX="74dp" />

<Button
android:id="@+id/btnCall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gọi điện"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edtPhoneNumber" />
</androidx.constraintlayout.widget.ConstraintLayout>

[/code]

ở trên View/Control Edittext (để nhập liệu) ta đặt id là “edtPhoneNumber”, code bên dưới sẽ truy suất vào control Edittext dựa vào id này.

Bây giờ ta  bổ sung sự kiện cho nut Gọi điện, thêm thuộc tính android:conClick, đặt tên hàm bên trong:

Ví dụ ta đặt tên hàm là xuLyGoiDien, lúc này nó sẽ báo lỗi vì chưa được khai báo trong Java code, giờ ta làm cho nó tự động phát sinh mã lệnh như sau: Click chuột vào hàm, nó xổ ra cái bóng đèn, nhấn vào bóng đèn chọn -> Create ‘xuLyGoiDien(View)’ in ‘MainActivity’ (Hoặc bạn cũng có thể nhấn tổ hợp phím Alt+ Enter)

Lúc này MainActivity sẽ phát sinh ra một hàm xuLyGoiDien như dưới đây:

[code language=”java”]
package tranduythanh.com.hocfindviewbyid;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

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

public void xuLyGoiDien(View view) {

}

}
[/code]

Bây giờ ta bổ sung mã lệnh cho hàm xuLyGoiDien:

[code language=”java”]
public void xuLyGoiDien(View view) {
//lệnh findViewById để truy suất tới control có id tương ứng truyền vào:
EditText edtPhone=findViewById(R.id.edtPhoneNumber);
//Lấy số phone ra:
String phoneNumber=edtPhone.getText().toString();
//Khai báo Intent để quay số gọi điện thoại
Intent intent=new Intent(Intent.ACTION_DIAL);
//Cú pháp gọi điện thoại
Uri uri=Uri.parse("tel:"+phoneNumber);
//gán uri cho intent:
intent.setData(uri);
//Gọi chức năng gọi điện thoại
startActivity(intent);
}
[/code]

Ở trên là hàm findViewById để truy suất vào control theo đúng id tương ứng truyền vào trong hàm. Với Android, mỗi lần 1 control được kéo thả vào màn hình, nó sẽ có 1 id, ta có thể sửa lại id hoặc đặt id mới. Thì Id này sẽ tự động được lưu trong file R (R là file tự động).

Android version mới không cần phải ép kiểu, nó tự tìm ra đúng kiểu control.

Chạy phần mềm lên ta được:

Như vậy Tui đã trình bày xong kỹ thuật dùng findViewById để truy suất tới các biến control trên giao diện, nó áp dụng cho mọi control nhé (Android họ thường gọi control là View).

coding tải ở đây: https://drive.google.com/open?id=1ADI-5lsDMgdnFjiNupIrPcoFbJszSjtO

Ở bài sau Tui sẽ hướng dẫn các bạn kỹ thuật dùng ViewBinding để truy suất trực tiếp vào các control mà không cần thông qua findViewById, giúp tiết kiệm thời gian hơn cho lập trình viên, cũng như làm quen thuộc hơn cho những ai đi từ .Net dev qua.

Các bạn chú ý làm lại bài này trước nhé, phải hiểu cơ chế hoạt động của nó, biết nhiều kỹ thuật để trong mọi trường hợp ta có thể áp dụng được các kỹ thuật khác nhau.

Các bạn chú ý theo dõi nhé

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

Bài 10. Các Layout trong Android

Layout là nơi để tổ chức sắp xếp control/View trên giao diện và thường được sử dụng đầu tiên khi ta thiết kế giao diện. Các Layout này được Android Studio bố trí trong Palette/Layouts:

Trong bài này Tui sẽ trình bày về các layout:
10.1. ConstraintLayout
10.2. Frame Layout 
10.3. Linear Layout
10.4. Table Layout
10.5. Relative layout 

Dưới đây là các kiến thức chi tiết:

10.1. ConstraintLayout

Constraint layout dùng để định vị trí tương đối của Một control/View trên màn hình với các phần tử khác trong layout:

Ta có thể xác định một constraint cho một hay nhiều mặt của một view bằng chế độ kết nối bất kỳ sau đây :

  • Điểm neo nằm trên một View khác.
  • Một cạnh của layout.
  • Một guideline.

Android cung cấp các loại Constraint sau: Relative positioning, Margins,Centering positioning,Visibility behavior,Dimension constraints,Chains. Layout này được áp dụng để thiết kế các màn hình Responsive không lệ thuộc vào độ phân giải.

Cấu trúc XML của ConstraintLayout được mô tả như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
[/code]

Android Studio còn cung cấp chức năng chuyển đổi từ ConstraintLayout qua các layout khác(và ngược lại), bằng cách bấm chuột phải vào Layout bất kỳ/chọn Convert View ==>Chọn layout đích mà ta muốn chuyển đổi:

Với Sinh Viên mới học thì nên chọn LinearLayout, sau khi chọn LinearLayout:

LineLayout lại vừa có Horizontal và Vertical, ta có thể bấm chuột phải vào nó để đổi tiếp:

10.2. Frame Layout 

Sử dụng trong các trường hợp xây dựng bố cục tổ chức hiển thị một đối tượng duy nhất. Đối tượng mặc định vị trí top-left trên FrameLayout, View khai báo sau sẽ chồng nên View khai báo trước, có thể sử dụng thuộc tính Gravity để thiết lập lại vị trí.

[code language=”xml”]
<FrameLayout android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/h0"
android:id="@+id/imageView3"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/h1"
android:id="@+id/imageView4" />
</FrameLayout>
[/code]

Ta thấy hình h1 khai báo sau nên h1 sẽ chồng nên h0, cả hai hình này đều được neo ở góc top-left của màn hình: FrameLayout được sử dụng rất nhiều trong Tabhost

10.3. Linear Layout

Sử dụng trong các trường hợp xây dựng bố cục tổ chức hiển thị các đối tượng theo một chiều duy nhất (chiều dọc-vertical hoặc ngang-horizontal).
Đối tượng mặc định vị trí top left trên LinearLayout , có thể sử dụng thuộc tính Gravity để thiết lập lại vị trí.

[code language=”xml”]

<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout1"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

[/code]

Ta thay đổi chiều dọc (android:orientation= “vertical”), chiều ngang (android:orientation= “horizontal”) các View sẽ tự động sắp xếp:

LinearLayout hỗ trợ thuộc tính text android:gravity để căn chỉnh chữ trong View, android:layout_gravity để căn chỉnh vị trí tương đối của View trong layout.

Ngoài ra LinearLayout còn hỗ trợ nhiều thuộc tính khác như android:padding để tăng độ dày của View, android:layout_margin để tăng/giảm khoảng cách giữa các View.

10.4. Table Layout

TableLayout kế thừa từ LinearLayout, cho phép hiển thị các đối tượng theo nhiều dòng (TableRow). Mỗi dòng có thể chứa nhiều View, mỗi View được xem là một cột. Đặc biệt TableLayout lấy dòng có số lượng View nhiều nhất làm số cột, tức là nếu TableLayout có 3 dòng: dòng đầu tiên có 2 View, dòng thứ hai có 5 View và dòng cuối cùng có 4 View thì cột được xác định cho TableLayout này là 5.

TableLayout cho phép ta Meger(trộn) các ô trong TableRow bằng cách thiết lập thuộc tính layout_span cho View trong TableRow:

Hay layout_column để di chuyển vị trí của View tới một cột nào đó trong TableRow:

Dùng stretchColumns để dãn đều các control, các cell (ta thường dùng dấu “*” để cấu hình cho toàn bộ các cột, hoặc nhập số để cấu hình cho cột được chỉ định):

[code language=”xml”]

<TableLayout
android:stretchColumns="*"
android:layout_width="match_parent"
android:layout_height="match_parent">

[/code]

10.5. Relative layout 

RelativeLayout cho phép sắp xếp các View theo vị trí tương đối giữa các View khác trên giao diện (kể cả View chứa nó). Thường nó dựa vào Id của các View khác để sắp xếp theo vị trí tương đối. Do đó khi làm RelativeLayout ta phải chú ý là đặt Id của View cho chuẩn xác, nếu sau khi Layout xong mà ta lại đổi Id của các View thì giao diện sẽ bị xáo trộn (do đó nếu đổi ID thì phải đổi luôn các tham chiếu khác sao cho khớp với Id mà ta mới đổi).

Trên giao diện lúc kéo thả các View trên RelativeLayout ta tự căn chỉnh, lúc này các View sẽ tự động sắp xếp theo cách ta kéo thả trên màn hình.

Như vậy là Tui đã trình bày xong một số layout thường dùng trong Android. Việc nắm rõ cách thức hoạt động của layout rất quan trọng, trước khi thiết kế một giao diện, điều đầu tiên là phải nghĩ tới layout trước. Nó giống như khi chúng ta xây dựng một căn nhà, thì phải có bản vẽ kỹ thuật trước vậy.

Các bạn nhớ đọc kỹ lại nhé để hiểu rõ các layout

Bài học sau Tui sẽ trình bày về findViewById và ViewBinding. Một trong những kỹ thuật để truy suất tới các control trên giao diện. Nó rất quan trọng, các bạn chú ý theo dõi nhé

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

Bài 9. Cấu trúc và các quy tắc của một dự án Android

Như vậy tới đây các bạn đã thực sự rành cách sử dụng cộng cụ Android Studio rồi, ở bài này Tui sẽ nói chi tiết hơn về cấu trúc của một dự án Android. Từ cấu hình AndroidManifest cấp quyền đọc trộm tin nhắn, đọc dữ liệu trong SDCard, tới các quy tắc đặt tên file, cấu hình màn hình chạy đâu tiên, cách thức thêm thư viện biên dịch….

Các bạn mở lại dự án thần thánh “HelloWorld” nhé.

  • AndroidManifest: Tập tin rất quan trọng, dùng để thiết lập các quyền, Activity, Service, BroadCast Receiver… cho ứng dụng
  • Các file mã nguồn: Tất cả các lớp, Activity, Service, …. xử lý nghiệp vụ người dùng đều nằm trong này
  • Các XML Giao diện: Tất cả các giao diện đều nằm trong mục layout này. Android Studio tách riêng một màn hình tương tác thành Mã lệnh và giao diện riêng.
  • Các Hình ảnh, Xml Resource: Ta có thể đưa hình ảnh vào ứng dụng thông qua hai thư mục drawable và mipmap
  • Các Values: Nơi để ta tạo các tài nguyên như chuỗi, màu, độ phân giải…
  • Cấu hình biên dịch: Build.gradle giúp ta hiệu chỉnh các thông số khi biên dịch phần mềm, cho phép nhúng các thư viện bên ngoài vào ứng dụng…

Ta xem file AndroidManifest.xml:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com.helloworld">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
[/code]

Ta lưu ý mọi màn hình (Activity) khi được tạo mới thì nó phải được khai báo ở đây, và Activity nào có cấu trúc như trên (MainActivity) thì nó sẽ được kích hoạt chạy lên khi phần mềm được cài vào thiết bị.

Android cho phép nhiều Activity cùng cấu hình là Main Launcher, khi cái vào nó sẽ tạo ra nhiều short cut trong thiết bị tương ứng với từng màn hình.

Khi chúng ta thêm 1 Activity trong phần mềm, thì Activity này sẽ tự động được đưa vào file AndroidManifest.

Để cấp quyền sử dụng cũng như khai thác các tài nguyên phần cứng, ta cũng phải khai báo trong này. Ví dụ muốn cho phần mềm được phép nghe nghe và đọc trộm tin nhắn, muốn cho phần mềm lấy dữ liệu trong SD Card thì cấu hình như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com.helloworld">
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
[/code]

Ở trên ta thấy lệnh uses-permission dùng để cấp quyền sử dụng. Ta lưu ý là từ version Android 6.0, Google đã tăng mức bảo mật. Cho dù cấp quyền chỗ này thì cũng phải thêm 1 bước bảo mật nữa, đó là người dùng phải cấp quyền sử dụng trong thiết bị (vá lỗ hổng bảo mật). Do đó thường khi coding mà chạy lên thì nó báo lỗi hoặc làm thinh, khi nào cấp quyền thì sẽ thực hiện được (Tui sẽ nói chi tiết hơn ở chỗ cấp quyền trong các bài lấy dữ liệu từ thiết bị). Còn khi người dùng tải app từ Google Play thì Google cũng có bước hỏi là Phần mềm này có sử dụng các quyền sau, có thể gây mất tiền, bạn có chắn chắn muốn sử dụng không…. và người dùng thường không đọc cho OK hết. Cấp càng nhiều quyền thì càng nhanh hết Pin thôi. Các phần mềm như Zalo, Facebook Messenger, Facetime, Tango… đều là các phần mềm thu thập dữ liệu người dùng cả, chúng đều có chức năng đọc và lấy toàn bộ danh bạ trong thiết bị của bạn, đọc tin nhắn, đọc hình ảnh, truy suất tài nguyên trong thiết bị…. được lưu lên server của họ. Các phần mềm chính thống có cam kết riêng tư thì không sao, nhưng nhiều phần mềm trôi nổi sẽ tấn công bạn. Ngay cả Facebook đó thôi, 1 hãng lớn cam kết là không xâm phạm riêng tư, thì cuối cùng cũng xác nhận là có đọc trộm thông tin bí mật của khách hàng.

Dưới đây là minh họa khi có thêm một màn hình mới, thì Activity này sẽ tự động được khai báo trong AndroidManifest (Bạn không được phép xóa, xóa là lỗi ngay):

Bấm chuột phải vào Package/ chọn New/ chọn Activity/ chọn Empty Activity

Đặt tên là WelcomeActivity (lưu ý các màn hình thì phải luôn có Activity đằng sau nha), nhấn Finish để tạo:

Ta thấy nó tự đưa vào trong AndroidManifest.

Giả sử bây giờ ta muốn WelcomeActivity sẽ được kích hoạt chạy đầu tiên khi phần mềm được cài vào được thoại. Ta cấu hình như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com.helloworld">

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".WelcomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">

</activity>
</application>

</manifest>
[/code]

Ta thấy đó, chỉ việc CUT intent-filte trong MainActivity chuyển lên cho Welcome là được:

[code language=”xml”]
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
[/code]

Nếu mà cả Welcome và MainActivity cùng có cùng cấu trúc intent-filter như trên thì làm sao? Thì khi cài vào, điện thoại sẽ mở luôn 2 màn hình này, và  2 màn hình này cũng có Icon trên HomScreen của điện thoại.

Nói thêm về thư mục drawable:

Thư mục này sẽ chưa hình ảnh, tài nguyên xml để làm các việc như làm background, làm animation cho phần mềm.

Khi đưa hình ảnh hay file xml vào drawable thì phải đặt theo quy tắc của tên biến: Không được In Hoa ký tự đầu, không có khoảng trắng, không dùng dấu Tiếng Việt, không chứ số đằng trước…

Và nó tương tự cho thư mục mipmap nhé.

Tiếp theo vào thư mục values/colors.xml:

Trước mặt chúng ta là bảng màu. Ta có thể định nghĩa màu như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="maudo">#b90702</color>
</resources>
[/code]

Ở trên Tui có dùng biến tên là “maudo

Các bạn là dân Amater đồ họa thì dùng https://www.color-hex.com/ cho lẹ để lấy màu.

ở trên ta tham chiếu tới sài.

Tương tự cho strings.xml:

[code language=”xml”]
<resources>
<string name="app_name">HelloWorld</string>
<string name="hello">Xin chào Thầy Trần Duy Thanh</string>
</resources>
[/code]

dùng biến “hello”:

Kết quả:

Tiếp tục vào phần build.gradle (Module):

Ở đây có:

compileSdkVersion -> API để biên dịch

minSdkVersion-> API tối thiểu mà điện thoại khách hàng phải có

targetSdkVersion->API mà ta mong muốn khách hàng có version y chang như ta cấu hình trong dự án.

Cụ thể:

minSdkVersion là 26. Thì điện thoại khách hàng phải tối thiểu là 26. Còn 25 trở xuống là không có cài đặt được phần mềm, ngay bản thân Google Play nó cũng tự filter không cho khách hàng nhìn thấy phần mềm của ta.

targetSdkVersion là 29 (thường nó bằng compileSdkVersion ): Ta mong muốn rằng phần mềm này chỉ có thể chạy tốt nhất khi điện thoại khách hàng có version là 29. Điều có có nghĩa là gì? nếu điện thoại khách hàng là 30 đi, thì vẫn chạy được (do 30 lớn hơn min 26). Nhưng cái ta cần target tới là 29.

Nếu có sự thay đổi cấu hình gì trong này thì nhớ bấm Sync Now.

Ngoài ra nó còn có nhiều cấu hình khác, khi nào gặp thì Tui nói thêm

Như vậy tới đây bạn đã rành hơn về cấu trúc của một dự án Android rồi nhé

Bài sau ta bắt đầu vào học các Control cơ bản!

Các bạn chú ý theo dõi nhé

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

Bài 8. Cách sử dụng Android Studio phiên bản 2020

Với Android Studio phiên bản 2020 có một số thay đổi về mặt bố trí giao diện thiết kế. Ở trong dự án thần thánh “HelloWorld” Tui cũng đã nói sơ cách tạo Dự án, ý nghĩa một số thành phần rồi, Tuy nhiên nó mới chỉ là sơ bộ để các bạn nhanh chóng hiểu cách tạo dự án, chạy máy ảo, chạy máy thật, Ánh xạ điện thoại thật vào máy tính….. Trong bài này Tui sẽ tiếp tục trình bày chi tiết hơn công cụ lập trình Android Studio phiên bản 2020, cụ thể Tui sẽ nói các phần sau:

8.1. Các cấu hình quan trọng trong Android Studio
8.1.1. AVD Manager
8.1.2. SDK Manager
8.1.3. Setting
8.1.4. Default Project Structer
8.1.5. Check for Update
8.2. Các chức năng thường dùng
8.2.1. Tạo dự án mới
8.2.2. Mở dự án cũ
8.2.3. Import dự án từ Eclipse
8.3. Các màn hình quan trọng thường thao tác
8.3.1. Màn hình Project và cách thay đổi layout quan sát
8.3.2. Màn hình thiết kế giao diện
8.3.3. Màn hình thanh công cụ Palette
8.3.4. Màn hình Component Tree
8.3.5. Màn hình Atrributes
8.3.6. Màn hình Logcat
8.3.7. Màn hình Device Explore
8.4. Các menu và toolbar quan trọng thường thao tác
8.4.1. Các menu thường dùng
8.4.2. Các toolbar thường dùng

Chi tiết:

8.1. Các cấu hình quan trọng trong Android Studio

Công cụ Android Studio có một số cấu hình quan trọng mà chúng ta cần phải biết để giúp ích cho việc quản lý phiên bản Android SDK, cấu hình JDK, plug in… Google có gom nhóm trong “Configure” ở cuối màn hình Welcome (và nó cũng tồn tại trong các Menu lúc ta mở 1 Project):

    8.1.1. AVD Manager

AVD Manager là chức năng cho phép ta cấu hình tạo điện thoại giả lập .

Chi tiết cách sử dụng AVD Manager, các bạn xem trong Bài 3. Cách tạo Điện thoại giả Lập trong Android Studio  nhé

  8.1.2. SDK Manager

Chức năng SDK Manager cho phép ta quản lý phiên bản Android SDK, việc này rất quan trọng vì trong quá trình triển khai dự án Android ta phải kiểm thử trên nhiều dòng máy và trên nhiều phiên bản khác nhau. Từ màn hình khởi động ta chọn Configure->SDK Manager:

Sau khi chọn SDK Manager, Màn hình Android SDK sẽ hiển thị như bên dưới:

Trong màn hình Android SDK Manager chương trình liệt kê ra danh sách các phiên bản Android, ta cần kiểm tra trên phiên bản nào thì ta CHECKED vào để cài đặt phiên bản đó. Google thường đề nghị ta cập nhật phiên bản mới nhất nếu có.

Chỗ này cũng cho phép ta đổi lại nơi lưu trữ Android SDK.

8.1.3. Setting

Màn hình Setting dùng để cấu hình toàn bộ các thành phần liên trong công cụ Android Studio: Cấu hình Appearance & Behavior, keymap, Editor, plug in, build, execution, tools…kể cả SDK Manager. Mọi vấn đề liên quan tới các cấu hình ta vào mục Setting này để làm việc. Từ màn hình khởi động ta chọn Settings:

Sau khi chọn Setttings, màn hình Default Settings sẽ hiển thị ra dưới đây, ta tiến hành lựa chọn các cấu hình theo ý muốn:

Ta có thể chỉnh màu chữ, cỡ chũ, biên dịch thực thi, tất tần tạt trong này.

Sau khi đổi cấu hình xong thì nhớ nhấn nút OK để Android Studio thiết lập lại cho bạn.

8.1.4. Default Project Structer

Project Structer là màn hình cho phép ta lựa chọn đường dẫn cài đặt JDK và Android SDK. Màn hình này rất quan trọng, nếu chỉ định không đúng nơi cài đặt JDK và Android SDK thì không thể chạy được ứng dụng Android. Đôi khi di chuyển dự án Android từ máy này qua máy khác mà đường dẫn khác nhau, do đó ta phải vào đây để chỉnh lại.

Chương trình sẽ hiển thị màn hình Project Structer như hình dưới đây:

Ta chọn nơi đã cài đặt JDK và Android SDK… một cách chính xác rồi nhấn OK.

    8.1.5. Check for Update

Chức năng Check for Update được sử dụng để kiểm tra phiên bản Android Studio mới do Google phát triển. Từ màn hình khởi động ta chọn “Check for Update”:

Sau khi chọn, màn hình Checking for Updates sẽ xuất hiện như dưới đây, nếu có phiên bản mới sẽ tiến hành tải về máy (dưới đây là hình minh họa các bước, bạn đừng quan tâm bên trong là version nào):

Sau khi chương trình tải hết các phiên bản mới về máy thì màn hình “Platform and Plug in Updates” xuất hiện, ta bấm “Update and Restart”:

Sau khi bấm “Update and Restart”, chương trình sẽ tiến hành cài đặt:

Ta chờ chương trình cập nhật mới xong, Android Studio sẽ khởi động lại. Lúc này màn hình Complete Installation sẽ xuât hiện, ta chọn mục “I want to import my settings from a previous version…” nếu muốn lấy từ version cũ qua, con không muốn lấy gì cả thì chọn “I do not have a previous version of Studio….” rồi bấm OK:

Sau khi bấm OK, chương trình sẽ tiến hành mở màn hình khởi động của Android với phiên bản mới nhất mà ta vừa cập nhật.

Ngoài ra Ta còn có thể chỉnh lại cách thức tải các loại phiên bản, lúc chọn “Check UpDate”, trong màn hình bên dưới nó có nút “Configure” (kể cả màn hìn báo cáo phiên bản mới cũng có nút này nha, xem hình trên), ta nhấn vào nó:

Sau khi nhấn Configure:   Màn hình cấu hình cách thức update sẽ xuất hiện như dưới đây:

Android Studio đưa ra 4 cách thức loại chọn:

Canary Channel-> coi như là đang R&D

Dev Channel -> bản đang Dev lỗi um sùm

Beta Channel -> Cũng đang chạy thử, lỗi um sùm

Stable Channel -> Phiên bản đã chạy ổn định

Thường các Công ty sẽ chọn cái cuối cùng “Stable Channel”. Còn dân nghiên cứu thì nên chọn Canary để cầm đèn chạy trước xe bò, có cái gì mới thì nghiên cứu trước (nhưng nguy hiểm vì lỡ nó bỏ luôn thì mất công, nhưng với Google thì hiếm khi). Nên nếu ai chọn An toàn thì chọn Stable Channel. Còn Tui thì chọn Canary Channel. Khoảng thời giãn giữa các loại này khá nhiều.

Sau khi chọn xong thì bấm OK.

8.2. Các chức năng thường dùng

8.2.1. Tạo dự án mới

Đã trình bày kỹ trong Bài 2. Cách tạo dự án trong Android Studio phiên bản năm 2020

8.2.2. Mở dự án cũ

Thao tác mở dự án cũ được sử dụng rất nhiều lần trong quá trình lập trình Android, để mở dự án cũ ta có thể nhấn trực tiếp vào danh sách dự án liệt kê trong mục Recently bên trái màn hình (1) hoặc bấm vào “Open an existing android Studio project” (2):

Khi chọn dự án từ mục Recently thì Android Studio tự động mở dự án này lên, khi chọn “Open an existing Android Studio project” cửa sổ chọn dự án cũ xuất hiện:

Ta chọn dự án cũ mong muốn rồi bấm OK, lúc này Android Studio sẽ tiến hành mở lại dự án này cho ta.

8.2.3. Import dự án từ Eclipse

Vì Android Studio mới được phát triển gần đây, do đó rất nhiều dự án trước kia được xây dựng bằng công cụ Eclipse, Google đã hỗ trợ chức năng import dự án từ Eclipse vào Android Studio bằng cách nhấn “Import project (Eclipse ADT, Gradle, etc.)”:

8.3. Các màn hình quan trọng thường thao tác

Android Studio có rất nhiều màn hình thao tác, Tui liệt kê một số màn hình quan trọng thường dùng như: Xem cấu trúc Project, thiết kế giao diện, Palette, component tree, properties và Logcat….

  8.3.1. Màn hình Project và cách thay đổi layout quan sát

Trong một dự án Android Studio có rất nhiều chế độ quan sát cấu trúc, để thay đổi ta nhấn vào mục khoanh tròn rồi lựa chọn các kiểu quan sát:

Mỗi layout quan sát thì cấu trúc Project sẽ hiển thị khác nhau, nhưng ta sử dụng nhiều nhất vẫn là chế độ Android, dưới đây là ví dụ một số loại layout quan sát (lần lượt: Project, Packages, Project Files, Android ):

Ta thường chọn loại hiển thị là “Android

8.3.2. Màn hình thiết kế giao diện

Màn hình thiết kế giao diện trong Android Studio được sử dụng rất nhiều, Các mục chính trong phần này gồm:

Code, Split, Design: Đây là Ba chỗ được dùng để thiết kế giao diện cho ứng dụng, phần Design để thiết kế giao diện bằng kéo thả, phần code dùng để thiết kế bằng mã XML, phần Split để vừa thấy code XML vừa thấy giao diện chạy theo.

Ta đã biết một màn hình tương tác người dùng trong Android gồm có hai phần (xử lý sự kiện và phần giao diện), hai thành phần này lúc tạo sẽ tự động được tách ra làm hai tập tin (MainActivity.java và activity_main.xml):

Mặc định phần Design của màn hình thiết kế(activity_main.xml) sẽ hiển thị khi ta tạo một dự án, ta có thể kéo thả trực tiếp các control từ thanh Palette vào đây:

Trước mặt chúng ta mặc định là mục “Design”, ta có thể kéo thả các control trong Palette vào giao diện.

Nhấn vào “Code” để thiết kế giao diện bằng cách viết lệnh XML:

Ta có thiết viết XML để tạo giao diện

Ngoài ra khi bấm vào “Split”, ta sẽ viết code XML vừa thấy giao diện:

Chế độ hiển thị điện thoại: Android Studio cung cấp cho ta màn hình điện thoại để thiết kế:

Chọn Design: Ra mỗi khung trắng để kéo thả control

Chọn BluePrint: Ra khung xanh xem cấu trúc

Chọn Design & BluePrint: Xem cả khung trắng cả khung xanh

Ở màn hình trên ta có thể xoay đứng màn hình (Portrait), xoay ngang màn hình (Landspace).

Đổi độ dòng máy để test thử:

Đổi phiên bản API: Khi thay đổi biên dịch phân mềm với phiên bản Android SDK nào thì ta chọn API đó.

Đổi Theme: Android Studio cho phép ta đổi Theme điện thoại tùy theo nhu cầu sử dụng, để đổi Theme ta chọn AppTheme:

Khi chọn AppTheme, Android Studio sẽ hiển thị màn hình danh sách các Theme cho phép ta thay đổi:

Phóng to, thu nhỏ, di chuyển giao diện: Trong quá trình thiết kế giao diện, việc phóng to thu nhỏ màn hình rất tiện lợi cho lập trình viên:

8.3.3. Màn hình thanh công cụ Palette

Công cụ Palette cho phép ta kéo thả các control vào màn hình thiết kế của điện thoại:

Android Studio phân nhóm các loại control giúp ta dễ dàng chọn lựa kéo thả ra màn hình thiết kế: commond (textview, button…), Text (TextView, Edittext…), Text(Edittext, Password…), Layout(LinearLayout, FrameLayout…)

Để kéo thả Control ra màn hình điện thoại ta chỉ cần chọn một control bất kỳ nào đó trong Palette rồi nhấn chuột kéo trực tiếp vào màn hình điện thoại màu trắng sau đó nhả chuột ra.

8.3.4. Màn hình Component Tree

Màn hình Component Tree giúp ta quan sát được cấu trúc của các control kéo thả trên giao diện, hỗ trợ rất tốt cho việc điều chỉnh thiết kế:

Đặc biệt ta cũng có thể kéo thả control trực tiếp vào Component Tree để thiết kế giao diện.

8.3.5. Màn hình Attributes

Màn hình Attributesrất quan trọng, được sử dụng thường xuyên trong quá trình thiết lập các trạng thái cho control trên giao diện (đặt Id, độ rộng, độ cao, font chữ, vị trí….):

 8.3.6. Màn hình Logcat

Màn hình Logcat rất quan trọng cho lập trình viên trong quá trình theo dõi lỗi phát sinh khi chạy phần mềm, dựa vào các mô tả chi tiết lỗi trong Logcat mà ta có thể dễ dàng tìm ra các giải pháp để sửa lỗi một cách nhanh chóng. Ta quan sát dưới cùng màn hình Android Studio có mục Android Monitor, ta chọn mục này để xuất hiện màn hình Logcat:

 8.3.7. Màn hình Device Explore

Màn hình để ta tương tác vào cấu trúc bên trong của thiết bị:

8.4. Các menu và toolbar quan trọng thường thao tác

8.4.1. Các menu thường dùng

Android Studio cung cấp rất nhiều menu hỗ trợ đắc lực cho lập trình viên, giáo trình giới thiệu một số menu chính yếu:

Menu Tool/Android: Dùng để cấu hình máy ảo, SDK, ADB, Layout inspector, Theme Editor, Firebase…

Menu Build: Cho phép ta lựa chọn các thức biên dịch ứng dụng

Clean Project: Xóa các biên dịch trước đó

Rebuild Project: Build lại ứng dụng

Build Bundle(s)/APK(s): Build ứng dụng ra tập tin apk để thử nghiệm

Generate Signed Bundle/APK: Build ứng dụng và xác thực apk để đưa lên Google Play

Menu Run: Dùng để biện dịch và chạy ứng dụng lên thiết bị

Trong quá trình viết phần mềm, để thử nghiệm gỡ lỗi từng bước ta chọn Debug, để chạy luôn ứng dụng ta chọn Run.

8.4.2. Các toolbar thường dùng

Android Studio cung cấp các lệnh trong toolbar rất hữu ích,  giúp ta nhanh chóng truy suất tới các chức năng trong phần mềm.

Như vậy Tui đã hướng dẫn xong Cách sử dụng Android Studio phiên bản 2020

Các bạn nhứo xem kỹ để dễ thao tác sau nay nhé

Bài sau Tui sẽ nói về Cấu trúc của một dự án Android để chúng ta có thêm hiểu biết ý nghĩa của từng hạng mục

Các bạn chú ý theo dõi nhé

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

 

 

Bài 7. Cách cài Vysor – phần mềm Ánh xạ điện thoại vào máy tính

Như vậy các bạn đã xong 6 bài học, 6 bài này các bạn đã biết cách sử dụng Android Studio, biết cách tạo dự án, tạo máy ảo, cấu hình máy thật. Chạy sương sương được 1 phần mềm lên thiết bị. Vậy cũng OK rồi.

Tiếp nối các bài đó, Tui hướng dẫn thêm cách sử dụng phần mềm Vysor để nó Ánh xạ điện thoại thật của bạn và Máy vi tính của bạn. Nó rất tiện lợi cho Giảng Viên trình chiếu giảng dạy, các bạn Sinh Viên trình chiếu báo cáo đồ án, các team work làm việc nhóm, triển khai dự án.

Phần mềm Vysor rất hay, nó cho phép chúng ta tương tác 2 chiều. Có thể từ Vysor trong máy tính điều khiển điện thoại và ngược lại.

Bước 1: Vào https://www.vysor.io/

Bước 2: Chọn phiên bản để download:

Nhấn Download, chương trình sẽ hỏi phiên bản cài đặt:

Máy tính bạn dùng hệ điều hành nào thì tải bản tương ứng nhé.

Của Tui là Windows nên Tui chọn “Windows” để tải, nó ra file “Vysor-win32-ia32.exe”

 

Nhấn Save để tải về nhé.

Tải xong thì bấm vào nó để cài đặt nhé, vô cùng đơn giản, bấm rồi chờ xíu là xong, Vysor chạy lên và ta sẽ thấy các thiết bị điện thoại sẽ được hiển thị như hình bên dưới, dĩ nhiên là chỉ điệnt hoại nào đã cấu hình USB Debugging nhé, đọc hướng dẫn tại đây.

Ta muốn Ánh xạ điện thoại nào vào máy tính thì chọn View ở thiết bị đó, kết quả:

Tới đây ta có thể điều khiển điện thoại ngay trên Máy tính của mình, có thể trình chiếu… rất hay.

Xem màn hình toàn cảnh:

Như vậy Tui đã hướng dẫn xong cách sử dụng Vysor để Ánh xạ điện thoại vào máy tính, các Bạn dùng tool này để dạy học, để báo cáo đồ án, để báo cáo dự án…. Và trong quá trình học các bài Tui hướng dẫn, nếu có điện thoại thật thì dùng luôn, chạy phần mềm lên điện thoại thật để test cho nó truất!

Bài học sau Tui sẽ quay lại vấn đề sử dụng Android Studio để tiếp tục các bài lập mang âm hưởng kỹ thuật trình Android.

Các bạn chú ý theo dõi nhé!

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

Bài 6. Cách chạy một dự án Android trên điện thoại thật

bài 5 các bạn đã được học cách chạy một phần mềm trong Android Studio lên Điện thoại giả lập. Nhưng các bạn lưu ý là khi triển khai phần mềm cho khách hàng sử dụng thì ta cần test cả trên điện thoại thật. Vậy làm sao có thể làm được điều này?

Trước tiên ta cần có điện thoại sử dụng hệ điều hành Android, các hãng nổi tiếng thường là SamSung, HTC…. hoặc các bạn ra ngoài chợ mua 1 cái điện thoại Hồ Cẩm Đào giá 500k, xin khéo có khi được cho, dùng tạm OK.

Với bất kỳ điện thoại thật nào, muốn chạy phần mềm (Debug) từ Android Studio thì ta phải cấu hình USB Debugging. Tùy mỗi dòng máy, mỗi hãng mà chỗ này nó được bố trí khác nhau, tuy nhiên là dân công nghệ thì ta mò một hồi nó ra thôi, vì mò là nghề của dân công nghệ mà.

Dưới đây là Tui thao tác và chụp cách làm trên cái điện thoại thật cùi bắp của Tui, SAM SUNG thế hệ nồi đồng cối đá (bạn sài loại nào thì ráng mò ra, miễn làm sao thấy được chức năng Tui hướng dẫn là OK, và Tui chắc chắn là nó có nha, Tui không thể hướng dẫn hết các trường hợp được, nó tùy thuộc và kỹ năng mò của các bạn):

Bước 1: Vào setting

Bước 2: Vào About device

Bước 3: Vào Software info

Bước 4: Nhấn 5 lần liên tục vào Build Number

Sau khi nhấn 5 lần liên tục vào Build Number, điện thoại thật sẽ thông báo “You are now a developer”. Sau đó ta quay lại màn hình Setting thì thấy Developer options như hình bên dưới:

Bước 5: Cấu hình USB Debugging

Khi điện thoại thật của ta đã có Developer options, ta cần cấu hình USB debugging bởi vì điện thoại thường kết nối với máy tính thông qua sợi cáp USB, ngoài ra ta cũng có thể kết nối không giây. Giáo trình chỉ tập trung vào phần USB cab.

Bạn thấy cái USB debugging không? nhớ chọn nó nha.

Lúc này bạn cắm dây cable USB của Điện thoại vào Máy tính của bạn thì có thể chạy được phần mềm lên rồi nhé:

Bước 6: Chạy phần mềm từ Android Studio lên điện thoại thật:

Cắm USB, Xem Tui chụp hình điện thoại cùi bắp nối với Laptop của Tui nhé:

Lúc này trên phần mềm Android Studio sẽ thấy điện thoại thật của Tui:

Cụ thể là cái SAM SUNG, bạn chọn SAM SUNG-> Nhấn START để chạy–> Phần mềm “HelloWorld” sẽ được cài trên điện thoại thật.

bài học sau, Tui sẽ hướng dẫn các bạn cách dùng phần mềm Vysor để Ánh Xạ Điện thoại thật vào máy tính, giúp chúng ta dễ dàng thao tác lập trình, debug, trình chiếu…

Các bạn chú ý theo dõi nhé!

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