Tài liệu lập trình android

Công ty cổ phần thương mại Vạn Tín Việt

Xây dựng 1 view

Đầu tiên các bạn cần clone dự án  về máy tính của mình và sử dụng android studio để viết code, ngôn ngữ lập trình là java

Để xây dựng môt view chúng ta cần tạo các phần sau

1.Fragment_items_list.xml

Fragment_item_list.xml

Tên file cần tạo: fragment_item_list.xml

Cấu trúc tên 

Fragment_items_list.xml: trong đó items là các đối tượng mà chúng ta muốn hiển thị ví dụ như Fragment_cars_list.xml, Fragment_pets_list.xml...

Nơi đặt file này: app/src/main/res/layout

Nơi này để chứa danh sách các items

Nội dung của file như sau

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<data>

<variable
name="loadingMore"
type="boolean" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/itemListRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingTop="@dimen/space_16"
android:paddingStart="@dimen/space_20"
android:paddingEnd="@dimen/space_20"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="@+id/progressBar3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

<ProgressBar
android:id="@+id/progressBar3"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:visibleGone="@{loadingMore}" />

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

Trong đó các bạn lưu ý phần bôi đậm. 

itemListRecyclerView: Phần này là tên của RecyclerView. ở đây items là một đối tượng mà chúng ta muốn tạo, ví dụ carsRecyclerView. petsRecyclerView....

 

Tạo một ViewOjbect cho item

Nội dung file 

Tên file : item.java: trong đó item là đối tượng muốn tạo, ví dụ car.java, pet.java  (Chú ý tên đối tượng cố gắng đặt tên bằng tiếng anh và không phải là số nhiều) và các bạn phải đổi tên file của mình đi nhé. tôi lấy ví dụ item để cho nó chung chung thôi

Nơi đặt File: app/src/main/java/com/vantinviet/adayroionline/viewobject

package com.vantinviet.adayroionline.viewobject;

import androidx.annotation.NonNull;
import androidx.room.Entity;

import com.google.gson.annotations.SerializedName;

@Entity(primaryKeys = "id")// đối với mỗi đối tượng sẽ phải có khóa chính thường thì id là khóa chính
public class Item {

@NonNull
@SerializedName("id")
public String id="";

@SerializedName("property1") // lấy key theo api trả về
public String property1=""; // thuộc tính 1 của đối tượng
@SerializedName("property2") // lấy key theo api trả về
public String property2=""; // thuộc tính 2 của đối tượng
    @SerializedName("added_date")
public final String addedDate;

//thêm nhiều thuộc tính nữa ở đây, nhớ thêm cả ở phương thức khởi tạo nữa nhé
//Phương thức khởi tạo
public Item() {

}
public Item(@NonNull String id, String property1, String property2, String added_date) {
this.id = id!=null?id:this.id;
this.property1=property1!=null?property1:this.property1;
this.property2= property2!=null?property2:this.property2;
this.added_date=added_date!=null?added_date:this.added_date;


}
}
Nếu như trong quá trình đọc tài liệu sẽ có phần bổ xung thêm thuộc tích thì các bạn nhớ vào đây thêm thuộc tính nhé
Kiến thức cơ bản cho phần này: các bạn phải nắm được cách định nghĩa class của lập trình hướng đối tượng
Nhưng nếu trước mắt các bạn chưa nắm được thì chỉ cần hiểu đại khái thế này, các đối tượng thì sẽ có các thuộc tính của nó là property1,property2...., nếu có nhiều hơn thuộc tính thì thêm vào
còn nữa, các thuộc tính này có các kiểu dữ liệu khác nhau do đó cũng cần phải nắm được các kiểu dữ liệu nguyên thủy trong lập trình nói chung và lập trình java nói riêng

Xây dựng file fragment_item.xml

Nội dung file, giả sử item của chúng tả chỉ hiển thị mỗi name và có trường là item_name

Nơi đặt file fragment_item.xml: res/layout

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

<layout 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">

<data>

<variable
name="item" <! -- Đặt tên item để lát hiển thị item_name ở dưới -->
type="com.vantinviet.adayroionline.viewobject.Item" /> <! -- Gọi đối tượng item trong viewobject -->

</data>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">



<! -- Tạo một ô text view để hiện thị item name -->
<TextView
android:id="@+id/item_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@{item.item_name}" <! -- Gọi giá trị của item_name -->
android:textAlignment="viewStart"
android:textColor="@color/md_black_1000"
android:textSize="@dimen/font_title_size"
app:font='@{"normal"}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
tools:text="Name" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>

Chú ý quan trọng: việc xây dựng hiển thị mội item là rất quan trọng do đó các bạn cần phải nắm được các đối tượng thể hiện của item
ví dụ như hiển thị ảnh của item, hiển thị ngày tháng, và hiển thị rất nhiều các thông tin khác.
Để tìm hiểu sâu về phần này các bạn tham khảo tại đây

Xây dựng lớp DAO cho item

Xây dựng lớp DAO

Ứng dụng sử dụng cơ dữ liệu sqlite để lưu dữ liệu được lấy từ phía server về, điều này giúp cho người dùng có cảm giá dữ liệu đang online, giúp tăng phần trải nghiệm người dùng

Thêm file có tên là itemDao.java vào thư mục java/com/vantinviet/adayroionline/db

Nội dung file

package com.vantinviet.adayroionline.db;

import com.vantinviet.adayroionline.viewobject.Item;

import java.util.List;

import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;

@Dao
public interface ItemDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(List<Item> items);

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Item item);

@Query("SELECT * FROM Item WHERE id = :id")
LiveData<Item> getItemById(String id);

@Query("SELECT * FROM Item ORDER BY addedDate desc")
LiveData<List<Item>> getAllItems();

@Query("DELETE FROM Item")
void deleteAll();

}


Các bạn nhớ thay bằng file nội dung của mình nhé

Bổ xung ItemDao vào PSCoreDb

Để có thêm thao tác được với itemDao thì chúng ta cần phải thêm vào PSCoreDb

Mở file PSCoreDb theo đường dẫn java/com/vantinviet/adayroionline/db/PSCoreDb.java

import viewobject item vào trước

anh15

Bổ xung item vào như hình

anh16

Chú ý mũi tên đỏ: mỗi làm khi them một dao bạn cần phải tăng giá trị này lên 1, để hệ thống android thêm được db vào sqlite

 

Tiếp theo cần khai báo dòng sau như hình

anh17

 

 

Bổ xung Dao vào appModule

Bổ xung dao vào appModule, mở file java/com/vantinviet/adayroionline/di/AppModule.java

import class ItemDao

anh18

 

Thêm dòng sau vào cuối class

@Singleton
@Provides
ItemDao provideItemDao(PSCoreDb db) {
return db.itemDao();
}
anh19

 

Xây dựng API gọi Item theo các điều kiện

Bước 4-1: Xây dựng API gọi Item theo các điều kiện

 Mở file java/com/vantinviet/adayroionline/api/PSApiService.java

 

//import view object của Item
import com.vantinviet.adayroionline.viewobject.Item;

Bổ xung xuống cuối của class này

@GET("api/items/get/api_key/{API_KEY}/limit/{limit}/offset/{offset}")
LiveData<ApiResponse<List<Item>>> getAllItem(@Path("API_KEY") String api_key, @Path("limit") String limit, @Path("offset") String offset);

@GET("api/items/get/api_key/{API_KEY}/id/{id}")
LiveData<ApiResponse<Item>> getItemById(@Path("API_KEY") String api_key, @Path("id") String id);

Xây dựng api phía server

Bạn nhấn vào đây là làm theo nhé.

Xây dựng ApiResponseGetItemList

Nơi tạo file java/com/vantinviet/adayroionline/ApiResponse

Tên file cần tạo: ApiResponseGetItemList

 

Nội dung file 

 

package com.vantinviet.adayroionline.ApiResponse;

import com.google.gson.annotations.SerializedName;
import com.vantinviet.adayroionline.viewobject.Item;

import java.util.List;

public class ApiResponseGetItemList {


@SerializedName("result")
public String result;

@SerializedName("code")
public String code;

@SerializedName("errorMessage")
public String errorMessage;

@SerializedName("list_order")
public List<Item> itemList;

public ApiResponseGetItemList(String result, String code, String errorMessage, List<Item> itemList) {
this.result = result;
this.code = code;
this.errorMessage = errorMessage;
this.itemList = itemList;
}


@Override
public String toString() {
return "ApiResponseGetItemList{" +
"result='" + result + '\'' +
", code='" + code + '\'' +
", errorMessage='" + errorMessage + '\'' +
", itemList=" + itemList +
'}';
}
}

Xây dựng lớp ApiResponseGetItem.java

Tên file ApiResponseGetItem.java

 

Nội dung file

package com.vantinviet.adayroionline.ApiResponse;

import com.google.gson.annotations.SerializedName;
import com.vantinviet.adayroionline.viewobject.Item;


public class ApiResponseGetItem {


@SerializedName("result")
public String result;

@SerializedName("code")
public String code;

@SerializedName("errorMessage")
public String errorMessage;

@SerializedName("data")
public Item item;

public ApiResponseGetItem(String result, String code, String errorMessage, Item item) {
this.result = result;
this.code = code;
this.errorMessage = errorMessage;
this.item = item;
}


@Override
public String toString() {
return "ApiResponseGetItem{" +
"result='" + result + '\'' +
", code='" + code + '\'' +
", errorMessage='" + errorMessage + '\'' +
", item=" + item +
'}';
}
}

Tạo ItemListRepository

Nơi tạo java/com/vantinviet/adayroionline/repository

Tạo một thư mục có tên item trong  java/com/vantinviet/adayroionline/repository

Tạo file  file ItemsListRepository bên trong java/com/vantinviet/adayroionline/repository/item

Nội dung file

package com.vantinviet.adayroionline.repository.item;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.vantinviet.adayroionline.ApiResponse.ApiResponseGetItemList;
import com.vantinviet.adayroionline.AppExecutors;
import com.vantinviet.adayroionline.api.ApiResponse;
import com.vantinviet.adayroionline.api.PSApiService;
import com.vantinviet.adayroionline.db.ItemDao;
import com.vantinviet.adayroionline.db.PSCoreDb;
import com.vantinviet.adayroionline.repository.common.PSRepository;
import com.vantinviet.adayroionline.utils.Utils;
import com.vantinviet.adayroionline.viewobject.Item;
import com.vantinviet.adayroionline.viewobject.common.Resource;

import java.io.IOException;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

import retrofit2.Response;

@Singleton
public class ItemListRepository extends PSRepository {

//region variable
private final ItemDao itemDao;
//end region

//region constructor
@Inject
ItemListRepository(PSApiService psApiService, AppExecutors appExecutors, PSCoreDb db, ItemDao itemDao) {
super(psApiService, appExecutors, db);
this.itemDao = itemDao;
}


//region User Repository Functions for ViewModel
public LiveData<Resource<List<Item>>> getAllItem(String api_key,String limit, String offset) {

final MutableLiveData<Resource<List<Item>>> statusLiveData = new MutableLiveData<>(); // To update the status to the listener

appExecutors.networkIO().execute(() -> {

try {

// Call the API Service
Response<ApiResponseGetItemList> response =
psApiService.getAllItem(api_key,limit,offset).execute();
// Wrap with APIResponse Class
ApiResponse<ApiResponseGetItemList> apiResponseGetItemList = new ApiResponse<>(response);
if(apiResponseGetItemList.body.code.equals("101")){
statusLiveData.postValue(Resource.error(apiResponseGetItemList.body.errorMessage, null));
return;
}
// If response is successful
if (apiResponseGetItemList.isSuccessful()) {

db.beginTransaction();

try {
itemDao.deleteAll();

db.setTransactionSuccessful();

} catch (Exception e) {
Utils.psErrorLog("Error in doing transaction of recent transaction list.", e);
} finally {
db.endTransaction();
}
statusLiveData.postValue(Resource.success(apiResponseGetItemList.body.itemList));
} else {
statusLiveData.postValue(Resource.error(apiResponseGetItemList.errorMessage, null));
}

} catch (IOException e) {
statusLiveData.postValue(Resource.error(e.getMessage(), null));
}

});
return statusLiveData;

}




// Get next page transaction list
public LiveData<Resource<Boolean>> getNextPageItemList(String api_key,String limit,String offset) {

final MutableLiveData<Resource<Boolean>> statusLiveData = new MutableLiveData<>(); // To update the status to the listener

appExecutors.networkIO().execute(() -> {

try {

// Call the API Service
Response<ApiResponseGetItemList> response =
psApiService.getAllItem(api_key,limit,offset).execute();


// Wrap with APIResponse Class
ApiResponse<ApiResponseGetItemList> apiResponseGetItemList = new ApiResponse<>(response);
if(apiResponseGetItemList.body.code.equals("101")){
statusLiveData.postValue(Resource.error(apiResponseGetItemList.body.errorMessage, null));
return;
}
// If response is successful
if (apiResponseGetItemList.isSuccessful()) {

db.beginTransaction();

try {

itemDao.deleteAll();
itemDao.insertAll(apiResponseGetItemList.body.itemList);
db.setTransactionSuccessful();

} catch (Exception e) {
Utils.psErrorLog("Error in doing transaction of recent item list.", e);
} finally {
db.endTransaction();
}
} else {
statusLiveData.postValue(Resource.error(apiResponseGetItemList.errorMessage, null));
}

} catch (IOException e) {
statusLiveData.postValue(Resource.error(e.getMessage(), null));
}

});
return statusLiveData;

}
public LiveData<Item> getItemById(String item_id) {
return itemDao.getItemById(item_id);
}

}

Xây dựng view model cho item

Một view mode dùng để kết gọi đến api lấy dữ liệu trả về và thực hiện các theo tác trả dữ liệu cho một adapter

 Tên file : ItemViewModel

Nơi lưu: java/com/vantinviet/adayroionline/viewmodel/item

Chú ý là bạn cần tạo một thư mục item nhé

Nội dung file 

package com.vantinviet.adayroionline.viewmodel.item;

import com.vantinviet.adayroionline.Config;
import com.vantinviet.adayroionline.repository.item.ItemRepository;
import com.vantinviet.adayroionline.utils.AbsentLiveData;
import com.vantinviet.adayroionline.viewmodel.common.PSViewModel;
import com.vantinviet.adayroionline.viewobject.Item;
import com.vantinviet.adayroionline.viewobject.common.Resource;

import java.util.List;

import javax.inject.Inject;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;

public class ItemViewModel extends PSViewModel {
private final LiveData<Resource<List<Item>>> itemsData;
private MutableLiveData<TmpDataHolder> itemsObj = new MutableLiveData<>();

private final LiveData<Resource<Boolean>> nextPageItemsData;
private MutableLiveData<TmpDataHolder> nextPageItemsObj = new MutableLiveData<>();

private final LiveData<Resource<Item>> itemByIdData;
private MutableLiveData<ItemByIdTmpDataHolder> itemByIdObj = new MutableLiveData<>();

public String shopName, shopId;

@Inject
ItemViewModel(ItemRepository repository) {

itemsData = Transformations.switchMap(itemsObj, obj -> {

if (obj == null) {
return AbsentLiveData.create();
}

return repository.getItemList(obj.limit, obj.offset);

});

nextPageItemsData = Transformations.switchMap(nextPageItemsObj, obj -> {

if (obj == null) {
return AbsentLiveData.create();
}

return repository.getNextPageItemList(Config.API_KEY, obj.limit, obj.offset);

});

itemByIdData = Transformations.switchMap(itemByIdObj, obj -> {

if (obj == null) {
return AbsentLiveData.create();
}

return repository.getItemById(obj.id);

});

}

public void setItemsObj(String limit, String offset) {
TmpDataHolder tmpDataHolder = new TmpDataHolder(limit, offset);

this.itemsObj.setValue(tmpDataHolder);
}

public LiveData<Resource<List<Item>>> getItemsData() {
return itemsData;
}

public void setNextPageItemsObj(String limit, String offset) {
TmpDataHolder tmpDataHolder = new TmpDataHolder(limit, offset);

this.nextPageItemsObj.setValue(tmpDataHolder);
}

public LiveData<Resource<Boolean>> getNextPageItemsData() {
return nextPageItemsData;
}

public void setItemByIdObj(String id) {
ItemByIdTmpDataHolder itemByIdTmpDataHolder = new ItemByIdTmpDataHolder(id);

this.itemByIdObj.setValue(itemByIdTmpDataHolder);
}

public LiveData<Resource<Item>> getItemByIdData() {
return itemByIdData;
}


class TmpDataHolder {

String limit, offset;

public TmpDataHolder(String limit, String offset) {
this.limit = limit;
this.offset = offset;
}
}

class ItemByIdTmpDataHolder {

String id;

private ItemByIdTmpDataHolder(String id) {
this.id = id;
}
}
}

Chú ý Item ở trong nội dung file này là một đối tượng cụ thể mà chúng ta cần theo tác với đối tượng đó.

Việc xây dựng hàm, class các bạn cần phải nắm được trong lập trình hướng đối tượng

Ngoài ra còn có một số những nội dung khác ở class này nhưng trước mắt các bạn chưa cần phải nắm hết, chỉ cần nắm được các nội dung nêu ở trên

 

Bổ xung viewModel item vào ViewModelModule

Mở file java/com/vantinviet/adayroionline/di/ViewModelModule.java

import itemViewModel vào như hình

anh13

Chú bạn phải đổi item thành cái của các bạn nhé

Tiếp theo khai báo phương thức trừu tượng như hình 

anh14

Các bạn nhớ đổi tên item thành cái của các bạn nhé

 

 

Xây dựng activity_item_list.xml

Tạo file activity_item_list.xml có nội dung như sau, nhớ đặt tên file theo đúng đối tượng mà bạn định làm nhé
Nơi lưu: res/layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_height="match_parent"
android:layout_width="match_parent">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<androidx.appcompat.widget.Toolbar
style="@style/ToolBarStyle.Event"
android:background="@color/global__primary"
android:id="@+id/toolbar"
android:layout_height="?android:attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

</com.google.android.material.appbar.AppBarLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<FrameLayout
android:id="@+id/content_frame"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

</FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

</layout>
Nội dung của file gần như bạn không phải chỉnh sửa gì

Tạo item_item_list_adapter.xml

Tên file item_item_list_adapter.xml

Nơi lưu: res/layout

Nội dung file

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

<layout 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">

<data>

<variable
name="item"
type="com.vantinviet.adayroionline.viewobject.Item" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/md_white_1000">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/md_white_1000">




<TextView
android:id="@+id/itemNameTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@{item.item_name}"
android:textAlignment="viewStart"
android:textColor="@color/md_black_1000"
android:textSize="@dimen/font_title_size"
app:font='@{"normal"}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
tools:text="Name" />



</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

Xây dụng UI code cho itemListAdapter

Phần này là phần dây dựng các tính năng thao tác với 1 item

Đầu tiên chúng ta cần phải xây dựng một adapter : hiểu nôm na là adapter là một cầu nối dữ liệu giữa data và hiển thị lên app

Chúng ta cần phải tạo một thư mục có tên là item trong thư mục app/src/main/java/com/vantinviet/adayroionline/ui

khi đã có thư mục item rồi chúng ta cần tạo một thư mục trong item có tên là adapter.

Tiếp theo chúng ta sẽ cần phải tạo file java có tên là ItemListAdapter.java (Nhắc lại mội lần nữa về item) ví dụ CarListAdapter.java, PetListAdapter.java: Chú là các chữ cái phải viết hóa nhé như Car. Pet

Nơi đặt file ItemListAdapter.java app/src/main/java/com/vantinviet/adayroionline/ui/item/adapter

 Nội dung file:

package com.vantinviet.adayroionline.ui.item.adapter;
/*
Đưa vào một số thư viện để code, trong quá trình code các bạn chú ý không phải copy nguyên và cũng sẽ có những thứ các bạn cần và không cần
*/
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.databinding.DataBindingUtil;


import com.squareup.picasso.Picasso;

import com.vantinviet.adayroionline.Lib.Factory;
import com.vantinviet.adayroionline.R;
/*
Các bạn lưu ý ở đây các bạn nhìn thấy có hai cái item nhưng các bạn chỉ đối tên cái item bôi đậm ví dụ ItemItemBinding, ItemPetBinding
*/
import com.vantinviet.adayroionline.databinding.ItemItemListAdapterBinding; // Item này là một đối tượng layout lát nữa chúng ta sẽ tạo đối tượng layout này. nếu nó đang lỗi các bạn cứ để nguyên đó không cần phải lo lắng
import com.vantinviet.adayroionline.ui.common.DataBoundListAdapter;
import com.vantinviet.adayroionline.ui.common.DataBoundViewHolder;
import com.vantinviet.adayroionline.utils.CircleTransform;
import com.vantinviet.adayroionline.utils.Constants;
import com.vantinviet.adayroionline.utils.Objects;
import com.vantinviet.adayroionline.utils.Utils;
import com.vantinviet.adayroionline.viewobject.Item; //Đối tượng view object này chúng ta đã tạo ra ở bước 2 rồi, giờ cũng cần phải đưa vào

public class ItemListAdapter extends DataBoundListAdapter<Item /* Truyền đối tượng item vào */, ItemItemListAdapterBinding /*Nhớ đọc kỹ ở phần trên để thay thế cho đúng*/> {

private final androidx.databinding.DataBindingComponent dataBindingComponent;
private final ItemClickCallback callback; // khai báo một sự kiện click (nhấn vào danh sách)
private DiffUtilDispatchedInterface diffUtilDispatchedInterface = null;


public ItemListAdapter(androidx.databinding.DataBindingComponent dataBindingComponent,
ItemClickCallback callback/*tham số callback để khi người dùng nhấn vào*/) {
this.dataBindingComponent = dataBindingComponent;
this.callback = callback; //Tạo một đối tượng click callback

}
//Một số phương thức ghi đè cần có
@Override
protected ItemItemListAdapterBinding createBinding(ViewGroup parent) {
ItemItemListAdapterBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()),
R.layout.item_item_list_adapter/* item_item_list_adapter đã được tạo ở bước 5.2 */, parent, false,
dataBindingComponent);

binding.getRoot().setOnClickListener(v -> {

});
return binding;
}

// For general animation
@Override
public void bindView(DataBoundViewHolder<ItemItemListAdapterBinding> holder, int position) {
super.bindView(holder, position);

}

@Override
protected void dispatched() {
if (diffUtilDispatchedInterface != null) {
diffUtilDispatchedInterface.onDispatched();
}
}

@Override
protected void bind(ItemItemListAdapterBinding binding, Item item) {
//Bây giờ chúng ta sẽ bắt đầu hiển thị dữ liệu cho một item. ví dụ trong trường ví dụ trong trường hợp này chúng ta chỉ cần hiển thị item_name. như vậy các bạn sẽ phải có thuộc tính item_name, thì bạn cần phải bổ sung cho view object ở bước 2 nhé
//Utils.psLog("item.item_name",item.item_name);
//set giá trị cho text
binding.itemNameTextView.setText(item.item_name);

Utils.psLog("some log","content log");


}

/*
Một số phương thức này để kiểm tra khi cần update dữ liệu hiển thị
*/
@Override
protected boolean areItemsTheSame(Item oldItem, Item newItem) {
return Objects.equals(oldItem.id, newItem.id)
&& oldItem.item_name.equals(newItem.item_name);
}

@Override
protected boolean areContentsTheSame(Item oldItem, Item newItem) {
return Objects.equals(oldItem.id, newItem.id)
&& oldItem.item_name.equals(newItem.item_name);
}

public interface ItemClickCallback {
void onClick(Item item);
}


}
Chú ý: các item là một đối tượng cụ thể mà chúng ta muốn sử lý ví dụ car, pet

Xây dụng UI code cho ItemListFragment

Tên file cần tạo ItemListFragment.java

 Nơi đặt file : java/com/vantinviet/adayroionline/ui/item

Nội dung file
//Tên gói
package com.vantinviet.adayroionline.ui.item;

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

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.vantinviet.adayroionline.Config;
import com.vantinviet.adayroionline.R;
import com.vantinviet.adayroionline.binding.FragmentDataBindingComponent;
//import Fragment_Item_List
import com.vantinviet.adayroionline.databinding.FragmentItemListBinding;
//import ItemListAdapter
import com.vantinviet.adayroionline.ui.item.adapter.ItemListAdapter;
import com.vantinviet.adayroionline.ui.common.DataBoundListAdapter;
import com.vantinviet.adayroionline.ui.common.PSFragment;
import com.vantinviet.adayroionline.utils.AutoClearedValue;
import com.vantinviet.adayroionline.utils.Utils;
import com.vantinviet.adayroionline.viewmodel.item.ItemViewModel;
import com.vantinviet.adayroionline.viewobject.Item;
import com.vantinviet.adayroionline.viewobject.common.Status;

import java.util.List;

public class ItemListFragment extends PSFragment implements DataBoundListAdapter.DiffUtilDispatchedInterface {

private final androidx.databinding.DataBindingComponent dataBindingComponent = new FragmentDataBindingComponent(this);
private ItemViewModel itemViewModel;

@VisibleForTesting
private AutoClearedValue<FragmentItemListBinding> binding;
private AutoClearedValue<ItemListAdapter> adapter;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//set item fragment sử dụng layout fragment_item_list
FragmentItemListBinding dataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_items_list, container, false, dataBindingComponent);

binding = new AutoClearedValue<>(this, dataBinding);

return binding.get().getRoot();

}
//Khởi tạo các ui
@Override
protected void initUIAndActions() {
//kiểm tra khi có sự kiện scroll của itemListRecyclerView
binding.get().itemListRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
//Khi người dùng kéo xong
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
LinearLayoutManager layoutManager = (LinearLayoutManager)
recyclerView.getLayoutManager();

if (layoutManager != null) {

int lastPosition = layoutManager
.findLastVisibleItemPosition();

if (lastPosition == adapter.get().getItemCount() - 1) {

if (!binding.get().getLoadingMore() && !itemViewModel.forceEndLoading) {

itemViewModel.loadingDirection = Utils.LoadingDirection.bottom;

int limit = Config.LIST_ITEMS_COUNT;

itemViewModel.start = itemViewModel.start + limit;

itemViewModel.setLoadingState(true);

itemViewModel.setNextPageItemsObj(String.valueOf(Config.LIST_ITEMS_COUNT), String.valueOf(itemViewModel.start));
}
}
}
}
});


binding.get().swipeRefresh.setColorSchemeColors(getResources().getColor(R.color.view__primary_line));
binding.get().swipeRefresh.setProgressBackgroundColorSchemeColor(getResources().getColor(R.color.global__primary));
binding.get().swipeRefresh.setOnRefreshListener(() -> {

itemViewModel.loadingDirection = Utils.LoadingDirection.top;

// reset itemViewModel.offset

itemViewModel.start = 0;

// reset itemViewModel.forceEndLoading
itemViewModel.forceEndLoading = false;

itemViewModel.setItemsObj(String.valueOf(Config.LIST_ITEMS_COUNT), String.valueOf(itemViewModel.start));

// update live data

});

}

@Override
protected void initViewModels() {

itemViewModel = ViewModelProviders.of(this, viewModelFactory).get(ItemViewModel.class);

}

@Override
protected void initAdapters() {

ItemListAdapter nvAdapter = new ItemListAdapter(dataBindingComponent, item -> navigationController.navigateToItemActivity/*Hiện tại hàm này chưa được xây dựng, chúng ta sẽ làm ở bước này nhấn vào đây để xem [Chú ý là bước này chúng ta sẽ làm sau nhé] */(ItemListFragment.this.getActivity(), item.id), this);

this.adapter = new AutoClearedValue<>(this, nvAdapter);
binding.get().itemListRecyclerView.setAdapter(adapter.get());

}
//Khởi tạo dữ liệu
@Override
protected void initData() {
// bắt đầu lấy dữ liệu
itemViewModel.setItemsObj(String.valueOf(Config.LIST_ITEMS_COUNT), String.valueOf(itemViewModel.start));
//Quan sát khi có dữ liệu được lấy về
itemViewModel.getItemsData().observe(this, result -> {

if (result != null) {
switch (result.status) {
//Nếu lấy dữ liệu về thành công
case SUCCESS:
replaceItemList(result.data);
itemViewModel.setLoadingState(false);
break;
//nếu vẫn đang trong quá trình tải
case LOADING:
replaceItemList(result.data);
break;
//nếu phát sinh một lỗi bất kỳ
case ERROR:

itemViewModel.setLoadingState(false);
break;
}
}

});
//Quan sát khi người dùng kéo scroll xuống dưới
itemViewModel.getNextPageItemsData().observe(this, state -> {
if (state != null) {
if (state.status == Status.ERROR) {

itemViewModel.setLoadingState(false);
itemViewModel.forceEndLoading = true;
}
}
});


itemViewModel.getLoadingState().observe(this, loadingState -> {

binding.get().setLoadingMore(itemViewModel.isLoading);

if (loadingState != null && !loadingState) {
binding.get().swipeRefresh.setRefreshing(false);
}

});

}
//Thực hiện việc cập nhật lại dữ liệu item
private void replaceItemList(List<Item> items) {
this.adapter.get().replace(items);
binding.get().executePendingBindings();
}


@Override
public void onDispatched() {
if (itemViewModel.loadingDirection == Utils.LoadingDirection.top) {

if (binding.get().itemListRecyclerView != null) {

LinearLayoutManager layoutManager = (LinearLayoutManager)
binding.get().itemListRecyclerView.getLayoutManager();

if (layoutManager != null) {
layoutManager.scrollToPosition(0);
}
}
}
}
}

Bổ xung ItemListFragment vào MainActivityModule

Mở file java/com/vantinviet/adayroionline/di/MainActivityModule.java

Sau đó nhấn vào dấu cộng để mở rộng nội dunganh8

Thêm nội dung ItemListFragment vào MainActivityModule

nội dung như sau

import com.vantinviet.adayroionline.ui.item.ItemListFragment;anh11

Kéo xuống cuối cùng thêm dòng như hình
anh12

Nhớ là thay item bằng cái của bạn nhé. trong trường hợp này của tôi là item nên tôi thêm như vậy

Xây dụng UI code cho ItemListActivity

Tên File : ItemListActivity.java

Nơi lưu file : java/com/vantinviet/adayroionline/ui/item

Nội dung file 

package com.vantinviet.adayroionline.ui.item;

import android.os.Bundle;

import com.vantinviet.adayroionline.R;
import com.vantinviet.adayroionline.databinding.ActivityItemListBinding;
import com.vantinviet.adayroionline.ui.common.PSAppCompactActivity;

import androidx.databinding.DataBindingUtil;

public class ItemListActivity extends PSAppCompactActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

ActivityItemListBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_item_list);

initUI(binding);

}

private void initUI(ActivityItemListBinding binding) {

// Toolbar
initToolbar(binding.toolbar, getResources().getString(R.string.item_list_title/*Bạn cần bổ xung ngôn ngữ vào string Xem ở đây*/));

// setup Fragment

setupFragment(new ItemListFragment());

}
}

Thêm ItemListActivity vào trong AndroidManifest.xml


Mở file AndroidManifest.xml theo đường dẫn sau anh5
Tìm đến dòng cuối của thẻ application
anh6
Bổ xung itemListActivity vào
anh7
Chú ý là nếu đã có itemListActivity rồi thì bạn không được thêm nữa mà chỉ thêm có một lần thôi

Bổ xung menu để hiển thị list

Mở file res/menu/menu_drawer.xml

anh30

Thao tác như tác như sau

them menu

Các bạn nhớ thay item của các bạn bằng thứ các bạn muốn nhé, ví dụ như car, pet

Xây dựng menu điều hướng tới trang detail

Hiện tại trang detail chưa xây dựng, do đó chúng ta chỉ xây dựng hàm trống để những bước sau chúng ta điều chỉnh lại

Mở file sau: java/com/vantinviet/adayroionline/ui/common/NavigationController.java

Bổ xung phương thức sau vào cuối class

 

public void navigateToItemActivity(Activity activity,String itemId) {
Intent intent = new Intent(activity, ItemActivity.class);
 //Truyền dữ liệu tới   ItemActivity
intent.putExtra("itemId",itemId);

activity.startActivity(intent);
}

Xây dựng layout fragment_item_detail

Sau khi chúng ta xây dựng xong phần list item. giờ chúng ta đi đến phần xây dựng chi tiết item

Tạo file fragment_item_detail.xml trong res/layout

Nội dung file 

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

<layout 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">

<data>

<variable
name="item"
type="com.vantinviet.adayroionline.viewobject.Item" />

</data>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">



<TextView
android:id="@+id/itemNameTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@{item.item_name}"
android:textAlignment="viewStart"
android:textColor="@color/md_black_1000"
android:textSize="@dimen/font_title_size"
app:font='@{"normal"}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
tools:text="Name" />



</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>

Các bạn nhớ thay item thành cái mình làm nhé

Xây dựng layout

Xây dụng UI code cho ItemActivity

Một Activity là gì : các bạn hiểu nôm na là nơi chứ các fragment để hiển thị dữ liệu

Đầu tiên chúng ta cần tạo Activity trước có têm là ItemActivity. java

Nơi lưu là app/src/main/java/com/vantinviet/adayroionline/ui/item

 

Nội dung của file

//Khai báo tên gói package
package com.vantinviet.adayroionline.ui.item;

import android.os.Bundle;

import com.vantinviet.adayroionline.R;
import com.vantinviet.adayroionline.databinding.ActivityItemBinding;// lát chúng ta sẽ cần phải tạo một layout có tên ActivityItem hiện giờ các bạn sẽ thấy bị lỗi nên đừng lo lắng quá
import com.vantinviet.adayroionline.ui.common.PSAppCompactActivity;

import androidx.databinding.DataBindingUtil;

public class ItemActivity extends PSAppCompactActivity {
//Phương thức tạo layout
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Khi tạo layout này các bạn sẽ thấy xuất hiện lỗi tạm thời cứ để đó đã lát chúng ta sẽ thêm ActivityItem
ActivityItemBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_item /*lát sẽ thêm activity_item*/);

initUI(binding);

}
// Đoạn này cũng sẽ phát sinh lỗi
private void initUI(ActivityItemBinding binding) {

// Toolbar
initToolbar(binding.toolbar, getResources().getString(R.string.item_title /*Chúng ta sẽ cần tạo một string cho title của layout này lát đến phần thêm ngôn ngữ chúng ta sẽ tạo chúng*/));

// setup Fragment tại bước tiếp theo chúng ta sẽ tạo ra một ItemFragment nên cũng sẽ bị lỗi các bạn cũng không cần phải lo lắng
setupFragment(new ItemFragment());

}
}
Như vậy chúng ta đã tạo xong activity. các bạn chú ý các item nhé, ví dụ như car, pet


Xây dụng UI code cho ItemFragment

Nội dung file

package com.vantinviet.adayroionline.ui.item;

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

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProviders;


import com.vantinviet.adayroionline.R;
import com.vantinviet.adayroionline.binding.FragmentDataBindingComponent;
import com.vantinviet.adayroionline.databinding.FragmentItemBinding;
import com.vantinviet.adayroionline.ui.common.PSFragment;
import com.vantinviet.adayroionline.utils.AutoClearedValue;
import com.vantinviet.adayroionline.utils.Constants;
import com.vantinviet.adayroionline.utils.PSDialogMsg;
import com.vantinviet.adayroionline.viewmodel.item.ItemViewModel;

public class ItemFragment extends PSFragment {

private final androidx.databinding.DataBindingComponent dataBindingComponent = new FragmentDataBindingComponent(this);
private ItemViewModel itemViewModel;
private String itemId;
private PSDialogMsg psDialogMsg;

@VisibleForTesting
private AutoClearedValue<FragmentItemDetailBinding> binding;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {


FragmentItemDetailBinding dataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_item_detail, container, false, dataBindingComponent);

binding = new AutoClearedValue<>(this, dataBinding);

return binding.get().getRoot();

}

@Override
protected void initUIAndActions() {

psDialogMsg = new PSDialogMsg(getActivity(), false);


}

@Override
protected void initViewModels() {

itemViewModel = ViewModelProviders.of(this, viewModelFactory).get(ItemViewModel.class);

}

@Override
protected void initAdapters() {

}

@Override
protected void initData() {

if (getActivity() != null) {
itemId = getActivity().getIntent().getStringExtra(Constants.ITEM_ID);
}

if (itemId!= null && !itemId.isEmpty()) {
itemViewModel.setItemByIdObj(blogId);

itemViewModel.getItemByIdData().observe(this, result -> {

if (result != null) {
if (result.data != null) {
switch (result.status) {
case SUCCESS:
binding.get().setItem(result.data);
break;

case ERROR:
psDialogMsg.showErrorDialog(getString(R.string.item_detail__error_message), getString(R.string.app__ok));
psDialogMsg.show();
break;

case LOADING:
binding.get().setItem(result.data);
break;
}
}
}
});
}

}
}

Xây dựng file activity_item.xml

File activity_item là file hiển thị nội dung của một item

Nơi đặt file res/layout

Nội dụng file activity_item.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_height="match_parent"
android:layout_width="match_parent">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<androidx.appcompat.widget.Toolbar
style="@style/ToolBarStyle.Event"
android:background="@color/global__primary"
android:id="@+id/toolbar"
android:layout_height="?android:attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

</com.google.android.material.appbar.AppBarLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<FrameLayout
android:id="@+id/content_frame"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/md_white_1000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

</FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

</layout>


Xây dựng các string để sử dụng trong đa ngôn ngữ

Hiện tại app đang xây dựng trên 2 ngôn ngữ chính đó là tiếp anh và tiếng việt

Các file string lưu theo cấu  trúc sau

anh4

Giả sử chúng có cần xây dựng 3 view cần các string sau

 

1.itemList danh sách

Chúng ta cần title của list

2.Item Xem chi tiết một item

3.ItemForm sửa một item

cấu trúc lưu 

<string name="item_title">title</string>

 

Tìm hiểu về Android Manifest

File AndroidManifest.xml trong Android

Nếu AndroidManifest.xml của ứng dụng không được thiết lập chính xác thì bạn có thể gặp phải rất nhiều sự cố – ​​có thể hệ thống Android sẽ không thể định vị tất cả Activity và Services của bạn. Tại sao lại như thế?

Trong bài viết này, freetuts sẽ giới thiệu và phân tích cho các bạn về file AndroidManifest trong Android, giúp các bạn hiểu hơn về bản chất của file AndroidManifest để xử lí các sự cố nếu có gặp phải do bắt nguồn từ file này.

Giới thiệu về AndroidManifest.xml trong Android

AndroidManifest.xml là file quan trọng nhất trong một ứng dụng Android, nó cung cấp thông tin về ứng dụng cho hệ thống Android, bao gồm tên ứng dụng, biểu tượng ứng dụng, phiên bản ứng dụng, quyền truy cập và các thành phần khác của ứng dụng.

Trong file AndroidManifest.xml, các phần quan trọng được định nghĩa bởi các thẻ.

Bài viết này được đăng tại [free tuts .net]

Ví dụ: Thẻ <manifest> chứa thông tin chung về ứng dụng như tên package, phiên bản tối thiểu của hệ điều hành Android được yêu cầu, tên ứng dụng, thẻ <activity> định nghĩa các activity...

Nếu bạn tạo một project Android bằng Android Studio, thì một file Manifest duy nhất sẽ tự động được tạo cho bạn, sau đó điền tất cả các yếu tố cần thiết để project này chạy trên thiết bị Android.

android studio manifest 768x507 jpg

Đoạn code dưới đây là file Manifest được tự động tạo bởi "Empty Activity" của project trong Android Studio.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
   package="com.jessicathornsby.myapplication">
 
   <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>

Hầu hết các mục Manifest bao gồm một phần tử và một thuộc tính.Nếu bạn cần chỉ định nhiều thuộc tính cho cùng một phần tử, thì thông thường bạn sẽ lặp lại phần tử đó với các thuộc tính khác thay vì thêm nhiều thuộc tính vào cùng một phần tử. Ví dụ ở đây, chúng tôi đang khai báo nhiều thuộc tính cho phần tử <uses-feature>:

1
2
3
4
5
6
7
8
<uses-feature android:name="android.hardware.sensor.proximity"
   android:required="true" />
 
<uses-feature android:name="android.hardware.sensor.relative_humidity"
   android:required="true" />
 
<uses-feature android:name="android.hardware.sensor.heartrate"
   android:required="true" />

Bây giờ chúng ta sẽ phân tích kỹ hơn về bản chất của file AndroidManifest.xml trong Android.

Phân tích các thành phần trong file AndroidManifest.xml

  • Package Name: Định nghĩa tên package của ứng dụng. Nó phải là duy nhất trên toàn hệ thống Android.
  • Thẻ Application: Định nghĩa các thuộc tính chung cho toàn bộ ứng dụng, bao gồm tên, biểu tượng, phiên bản, quyền truy cập,...
  • Thẻ Activity : Định nghĩa một hoạt động của ứng dụng. Mỗi hoạt động thường có một giao diện người dùng riêng, và được sử dụng để thực hiện một số chức năng cụ thể của ứng dụng.
  • Thẻ Service : Định nghĩa một dịch vụ của ứng dụng. Dịch vụ là một thành phần không có giao diện người dùng, được sử dụng để thực hiện các tác vụ nền, không cần tương tác với người dùng.
  • Thẻ BroadcastReceiver : Định nghĩa một BroadcastReceiver. BroadcastReceiver là một thành phần được sử dụng để nhận các thông báo từ hệ thống hoặc ứng dụng khác, và thực hiện các tác vụ liên quan.
  • Thẻ Content Provider : Định nghĩa một Content Provider. Content Provider là một thành phần được sử dụng để quản lý và cung cấp dữ liệu cho các ứng dụng khác.
  • Thẻ Permission : Định nghĩa các quyền truy cập mà ứng dụng yêu cầu từ hệ thống. Quyền truy cập có thể được cấp cho các tài nguyên như camera, microphone, địa chỉ,...
  • Thẻ Uses-feature : Định nghĩa các tính năng phần cứng hoặc phần mềm mà ứng dụng yêu cầu để hoạt động. Ví dụ như camera, màn hình cảm ứng,...
  • Thẻ Intent Filter : Định nghĩa các bộ lọc Intent cho các thành phần của ứng dụng. Bộ lọc Intent được sử dụng để xác định các loại Intent mà thành phần có thể xử lý, và khi nếu có một Intent phù hợp, hệ thống sẽ gửi nó đến thành phần đó để xử lý.
  • Thẻ Metadata : Định nghĩa các thông tin bổ sung về thành phần, nhưng không ảnh hưởng đến việc hoạt động của nó. Ví dụ như thông tin về đối tác của ứng dụng,...
  • Thẻ Application Theme: Định nghĩa giao diện mặc định cho toàn bộ ứng dụng.

Ngoài những thành phần chính của file AndroidManifest.xml thì còn một số thuộc tính quan trọng mà lập trình viên cần lưu ý:

  • android:versionCode: Định nghĩa version code của ứng dụng. Version code là một số nguyên, được sử dụng để phân biệt các version khác nhau của ứng dụng.
  • android:versionName: Định nghĩa version name của ứng dụng. Version name là một chuỗi ký tự, được sử dụng để giới thiệu về version của ứng dụng cho người dùng.
  • android:label: Định nghĩa tên của ứng dụng hiển thị trên giao diện người dùng.
  • android:icon: Định nghĩa biểu tượng của ứng dụng hiển thị trên giao diện người dùng.
  • android:theme: Định nghĩa giao diện của một hoạt động hoặc của toàn bộ ứng dụng.
  • android:exported: Xác định xem thành phần có thể được gọi từ ứng dụng khác hay không.
  • android:enabled: Xác định xem thành phần có hoạt động hay không.
  • android:configChanges: Xác định các sự kiện thay đổi cấu hình mà hoạt động có thể xử lý mà không cần bị khởi động lại.
  • android:screenOrientation: Xác định hướng màn hình của activity.
  • android:permission: Xác định quyền truy cập cần thiết để sử dụng thành phần.

Nắm vững các thành phần và thuộc tính này sẽ giúp bạn hiểu rõ hơn về cách ứng dụng Android hoạt động và cách thiết kế, xây dựng các thành phần trong nó.

Cách để ghép nhiều file AndroidManifest.xml trong Android

Mỗi project Android Studio phải chứa ít nhất một file Manifest , nhưng một project cũng có thể chứa nhiều file Manifest. Điều này có thể xảy ra trong các trường hợp sau:

  • Sử dụng các thư viện bên thứ ba: Các thư viện bên thứ ba có thể yêu cầu các quyền hoặc cấu hình cụ thể, cần phải thêm vào file AndroidManifest.xml của ứng dụng chính.
  • Phân tách các thành phần ứng dụng: Khi phát triển ứng dụng, bạn có thể muốn phân tách các thành phần như activity, service, BroadcastReceiver,... ra thành các file AndroidManifest.xml riêng biệt để quản lý dễ dàng hơn.

Để ghép nhiều file AndroidManifest.xml lại với nhau, bạn có thể sử dụng các công cụ build của Android Studio, bao gồm cả Gradle và Android Asset Packaging Tool (AAPT).

  • Sử dụng Gradle: Gradle là công cụ build được sử dụng rộng rãi trong phát triển ứng dụng Android. Để ghép nhiều file AndroidManifest.xml lại với nhau bằng Gradle, bạn có thể sử dụng các lệnh build Gradle để merge các file này lại với nhau. Để thực hiện việc này, bạn có thể sử dụng plugin Gradle Android và cấu hình file build.gradle để chỉ định các file AndroidManifest.xml cần merge.
  • Sử dụng Android Asset Packaging Tool (AAPT): AAPT là công cụ được sử dụng để đóng gói các tài nguyên của ứng dụng Android, bao gồm cả file AndroidManifest.xml. Để ghép nhiều file AndroidManifest.xml lại với nhau bằng AAPT, bạn có thể sử dụng lệnh aapt để merge các file này lại với nhau.

Tùy thuộc vào nhu cầu và công cụ build mà bạn sử dụng, bạn có thể tìm hiểu thêm về cách thực hiện việc ghép nhiều file AndroidManifest.xml lại với nhau trong tài liệu hướng dẫn của Gradle và Android Asset Packaging Tool.

Dưới đây là các bước ghép và kiểm tra việc ghép file AndroidManifest.xml.

  • Bước 1: Mở một trong các file Manifest của bạn trong Android Studio.
  • Bước 2: Chọn tab “Merged Manifest” (nơi con trỏ được định vị trong ảnh chụp màn hình sau). Thao tác này sẽ mở ra chế độ xem “Merged Manifest”.

android studio merged manifest view jpgDạng xem file Manifest đã hợp nhất hiển thị kết quả hợp nhất ở bên trái và thông tin về file Manifest đã hợp nhất ở bên phải.

merging multiple android manifests jpg

Nếu bạn bối rối về bất kỳ thành phần nào của file Manifest được hợp nhất, thì bạn có thể xem thêm thông tin về một thành phần cụ thể bằng cách chọn thành phần đó trong ngăn bên trái, sau đó đọc “Manifest log ” trong ngăn bên phải.

android manifest log jpg

Nếu có bất kỳ xung đột hợp nhất nào xảy ra thì chúng sẽ xuất hiện trong phần “Merging Errors” ở phía bên tay phải của Android Studio, kèm theo một số đề xuất về cách giải quyết xung đột cụ thể này, bằng cách sử dụng các điểm đánh dấu quy tắc hợp nhất.

Tổng kết

Trong bài viết này, chúng ta đã tìm hiểu về thành phần cấu trúc của file AndroidManifest.xml. Việc hiểu rõ các thành phần này sẽ giúp bạn tối ưu hóa quản lý và phát triển ứng dụng Android của mình. Ngoài ra, chúng ta cũng đã tìm hiểu cách để ghép nhiều file AndroidManifest.xml lại với nhau, qua việc sử dụng các công cụ build của Android Studio như Gradle và Android Asset Packaging Tool (AAPT). Hy vọng những kiến thức mà freetuts cung cấp về AndroidManifest.xml trong Android phần nào giúp bạn hiểu được bản chất của nó, hỗ trợ bạn phát triển ứng dụng của mình.

Xem và chỉnh sửa code trong java

Các thành phần được viết bằng Java và được liệt kê trong các thư mục mô-đun trong thư mục java trong dạng xem Dự án: Android. Mỗi tên mô-đun bắt đầu bằng tên miền (chẳng hạn như com.example.android ) và bao gồm tên ứng dụng.

Ví dụ sau đây cho thấy một thành phần hoạt động :

  1. Nhấp vào thư mục mô-đun để mở rộng nó và hiển thị tệp MainActivity cho hoạt động được viết bằng Java (lớp MainActivity).
  2. Bấm đúp vào MainActivity để xem tệp nguồn trong ngăn chỉnh sửa, như thể hiện trong hình bên dưới.Thành phần MainActivity

Ở trên cùng của tệp MainActivity.java là một packagecâu lệnh xác định gói ứng dụng. Tiếp theo là một importkhối cô đặc trong hình trên, với " ...". Nhấp vào dấu chấm để mở rộng khối để xem nó. Các importcâu lệnh nhập thư viện cần thiết cho ứng dụng, chẳng hạn như câu lệnh sau, sẽ nhập thư viện AppCompatActivity:

import android.support.v7.app.AppCompatActivity;

Mỗi hoạt động trong một ứng dụng được triển khai dưới dạng một lớp Java. Khai báo lớp sau mở rộng AppCompatActivitylớp để triển khai các tính năng theo cách tương thích ngược với các phiên bản Android trước:

public class MainActivity extends AppCompatActivity {
    ...
}

Như bạn đã tìm hiểu trước đó, trước khi hệ thống Android có thể khởi động một thành phần ứng dụng chẳng hạn như một hoạt động, hệ thống phải biết rằng hoạt động đó tồn tại bằng cách đọc tệp AndroidManifest.xml của ứng dụng. Do đó, mỗi hoạt động phải được liệt kê trong tệp AndroidManifest.xml.

 

Xem và chỉnh sửa bố cục

Tài nguyên bố cục được viết bằng XML và được liệt kê trong thư mục bố cục trong thư mục res trong dạng xem Project: Android. Nhấp vào res > layout rồi nhấp đúp vào activity_main.xml để xem tệp bố cục trong ngăn chỉnh sửa.

Android Studio hiển thị dạng xem Thiết kế của bố cục, như thể hiện trong hình bên dưới. Chế độ xem này cung cấp ngăn Bảng màu gồm các thành phần giao diện người dùng và lưới hiển thị bố cục màn hình.Bố cục (Chế độ xem thiết kế)

Hệ thống build sản phẩm như thế nào

Gói ứng dụng Android (APK) là định dạng tệp gói để phân phối và cài đặt ứng dụng di động Android. Quá trình xây dựng bao gồm các công cụ và quy trình tự động chuyển đổi từng dự án thành APK.

Android Studio sử dụng Gradle làm nền tảng của hệ thống xây dựng, với nhiều khả năng dành riêng cho Android hơn được cung cấp bởi Plugin Android dành cho Gradle. Hệ thống xây dựng này chạy như một công cụ tích hợp từ menu Android Studio.

Hiểu tệp build.gradle

Khi bạn tạo một dự án, Android Studio sẽ tự động tạo các tệp bản dựng cần thiết trong thư mục Gradle Scripts trong Project: Android view. Các tệp bản dựng Android Studio được đặt tên build.gradle như hình bên dưới:tập lệnh lớp

Mỗi dự án có những điều sau đây:

build.gradle (Dự án: apptitle )

Đây là tệp xây dựng cấp cao nhất cho toàn bộ dự án, nằm trong thư mục gốc của dự án, xác định các cấu hình xây dựng áp dụng cho tất cả các mô-đun trong dự án của bạn. Không được chỉnh sửa tệp này do Android Studio tạo để bao gồm các thành phần phụ thuộc của ứng dụng.

build.gradle (Mô-đun: ứng dụng)

Android Studio tạo build.gradle (Module: app)các tệp riêng biệt cho từng mô-đun. Bạn có thể chỉnh sửa cài đặt bản dựng để cung cấp các tùy chọn đóng gói tùy chỉnh cho từng mô-đun, chẳng hạn như loại bản dựng bổ sung và hương vị sản phẩm, đồng thời ghi đè cài đặt trong tệp kê khai hoặc tệp build.gradle cấp cao nhất. Tệp này thường là tệp cần chỉnh sửa nhất khi thay đổi cấu hình cấp ứng dụng, chẳng hạn như khai báo các thành phần phụ thuộc trong phần dependenciesPhần sau đây hiển thị nội dung của build.gradle (Module: app)tệp dự án:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"
    defaultConfig {
        applicationId "com.example.android.helloworld2"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}

Các tệp build.gradle sử dụng cú pháp Gradle. Gradle là Ngôn ngữ dành riêng cho miền (DSL) để mô tả và thao tác logic xây dựng bằng Groovy , đây là ngôn ngữ động cho Máy ảo Java (JVM). Bạn không cần học Groovy để thực hiện các thay đổi, vì Plugin Android dành cho Gradle giới thiệu hầu hết các thành phần DSL mà bạn cần.

Mẹo : Để tìm hiểu thêm về plugin Android DSL, hãy đọc tài liệu tham khảo DSL .

Plugin và khối Android

Trong tệp trên build.gradle (Module: app), câu lệnh đầu tiên áp dụng các tác vụ xây dựng trình cắm Gradle dành riêng cho Android:

apply plugin: 'com.android.application'

android {
   ...
}

Khối android { }chỉ định những điều sau đây cho bản dựng:

  • Phiên bản SDK mục tiêu để biên dịch mã:
    compileSdkVersion 24
    
  • Phiên bản của công cụ xây dựng sẽ sử dụng để xây dựng ứng dụng:
    buildToolsVersion "24.0.1"
    

Khối defaultConfig

Các mục nhập và cài đặt cốt lõi cho ứng dụng được chỉ định trong một defaultConfig { }khối trongandroid { } block:

   ...
   defaultConfig {
      applicationId "com.example.hello.helloworld"
      minSdkVersion 15
      targetSdkVersion 23
      versionCode 1
      versionName "1.0"
            testInstrumentationRunner
               "android.support.test.runner.AndroidJUnitRunner"
   }
...

Cài đặt minSdkVersionvà targetSdkVersionghi đè mọi cài đặt AndroidManifest.xml cho phiên bản SDK tối thiểu và phiên bản SDK mục tiêu. Xem phần "Khai báo phiên bản Android" trước đó trong chương này để biết thông tin cơ bản về các cài đặt này.

Tuyên testInstrumentationRunnerbố bổ sung hỗ trợ thiết bị để thử nghiệm giao diện người dùng với Espresso và UIAutomator. Chúng được mô tả trong một bài học riêng biệt.

xây dựng các loại

Các loại bản dựng cho ứng dụng được chỉ định trong một buildTypes { }khối, khối này kiểm soát cách ứng dụng được tạo và đóng gói.

...
buildTypes {
   release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'),
                                               'proguard-rules.pro'
   }
}
...

Loại bản dựng được chỉ định là releasedành cho bản phát hành của ứng dụng. Một loại bản dựng phổ biến khác là debugViệc định cấu hình các loại bản dựng được mô tả trong một bài học riêng.

phụ thuộc

Các phần phụ thuộc cho ứng dụng được xác định trong dependencies { }khối, đây là một phần của tệp build.gradle có nhiều khả năng thay đổi nhất khi bạn bắt đầu phát triển mã phụ thuộc vào các thư viện khác. Khối này là một phần của API Gradle tiêu chuẩn và thuộc bên ngoài khối android { }.

...
dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
   })
   compile 'com.android.support:appcompat-v7:24.2.0'
   testCompile 'junit:junit:4.12'
}

Trong đoạn mã trên, câu lệnh compile fileTree(dir: 'libs', include: ['*.jar'])thêm phần phụ thuộc của tất cả các tệp ".jar" bên trong libsthư mục. Cấu compilehình biên dịch ứng dụng chính — mọi thứ trong đó được thêm vào đường dẫn lớp biên dịch và cũng được đóng gói vào APK cuối cùng.

Đồng bộ hóa dự án của bạn

Khi bạn thực hiện các thay đổi đối với tệp cấu hình bản dựng trong một dự án, Android Studio yêu cầu bạn đồng bộ hóa các tệp dự án để có thể nhập các thay đổi cấu hình bản dựng và chạy một số kiểm tra để đảm bảo cấu hình sẽ không tạo ra lỗi bản dựng.

Để đồng bộ hóa các tệp dự án, hãy nhấp vào Đồng bộ hóa ngay trong thanh thông báo xuất hiện khi thực hiện thay đổi hoặc nhấp vào Đồng bộ hóa dự án từ thanh menu. Nếu Android Studio nhận thấy bất kỳ lỗi nào với cấu hình — ví dụ: nếu mã nguồn sử dụng các tính năng API chỉ khả dụng ở cấp API cao hơn compileSdkVersion— cửa sổ Thông báo sẽ xuất hiện để mô tả sự cố.Đồng bộ hóa tệp Gradle trong Dự án Android Studio

Chạy ứng dụng trên trình giả lập hoặc thiết bị

Với trình giả lập thiết bị ảo, bạn có thể thử nghiệm một ứng dụng trên các thiết bị khác nhau như máy tính bảng hoặc điện thoại thông minh — với các cấp API khác nhau cho các phiên bản Android khác nhau — để đảm bảo ứng dụng đó hoạt động tốt và phù hợp với hầu hết người dùng. Mặc dù đó là một ý tưởng hay nhưng bạn không cần phải phụ thuộc vào việc có sẵn thiết bị vật lý để phát triển ứng dụng.

Trình quản lý Thiết bị ảo Android (AVD) tạo một thiết bị ảo hoặc trình giả lập mô phỏng cấu hình cho một loại thiết bị Android cụ thể. Sử dụng Trình quản lý AVD để xác định các đặc điểm phần cứng của thiết bị và cấp độ API của thiết bị, đồng thời lưu thiết bị đó dưới dạng cấu hình thiết bị ảo. Khi bạn khởi động trình giả lập Android, nó sẽ đọc một cấu hình đã chỉ định và tạo một thiết bị giả lập trên máy tính của bạn hoạt động giống hệt như phiên bản vật lý của thiết bị đó.

Tạo một thiết bị ảo

Để chạy trình giả lập trên máy tính của bạn, hãy sử dụng Trình quản lý AVD để tạo cấu hình mô tả thiết bị ảo. Chọn Công cụ > Android > Trình quản lý AVD hoặc nhấp vào biểu tượng Trình quản lý AVD Biểu tượng Trình quản lý AVDtrên thanh công cụ.

Màn hình "Thiết bị ảo của bạn" xuất hiện hiển thị tất cả các thiết bị ảo đã tạo trước đó. Nhấp vào nút +Tạo thiết bị ảo để tạo một thiết bị ảo mới.Trình quản lý AVD

Bạn có thể chọn một thiết bị từ danh sách các thiết bị phần cứng được xác định trước. Đối với mỗi thiết bị, bảng hiển thị kích thước màn hình chéo (Kích thước), độ phân giải màn hình tính bằng pixel (Độ phân giải) và mật độ điểm ảnh (Mật độ). Ví dụ: mật độ pixel của thiết bị Nexus 5 là xxhdpi, có nghĩa là ứng dụng sử dụng các biểu tượng trong thư mục xxhdpi của thư mục mipmap . Tương tự như vậy, ứng dụng cũng sẽ sử dụng bố cục và đối tượng có thể vẽ từ các thư mục được xác định cho mật độ đó.Chọn Định nghĩa Thiết bị

Bạn cũng chọn phiên bản hệ thống Android cho thiết bị. Tab Đề xuất hiển thị các hệ thống được đề xuất cho thiết bị. Các phiên bản khác có sẵn trong tab Hình ảnh x86 và Hình ảnh khác .

Chạy ứng dụng trên thiết bị ảo

Để chạy ứng dụng trên thiết bị ảo mà bạn đã tạo trong phần trước, hãy làm theo các bước sau:

  1. Trong Android Studio, chọn Chạy > Chạy ứng dụng hoặc nhấp vào biểu tượng Chạy Biểu tượng Chạy Android Studio trên thanh công cụ.
  2. Trong cửa sổ Chọn mục tiêu triển khai, bên dưới Trình mô phỏng khả dụng, chọn thiết bị ảo bạn đã tạo và nhấp vào OK .

Trình giả lập khởi động và khởi động giống như một thiết bị vật lý. Tùy thuộc vào tốc độ máy tính của bạn, quá trình này có thể mất một lúc. Ứng dụng được xây dựng và khi trình giả lập đã sẵn sàng, Android Studio sẽ tải ứng dụng lên trình giả lập và chạy nó.

Bạn sẽ thấy ứng dụng được tạo từ mẫu Hoạt động trống ("Xin chào thế giới") như minh họa trong hình dưới đây, cũng hiển thị ngăn Chạy của Android Studio hiển thị các tác vụ được thực hiện để chạy ứng dụng trên trình giả lập.

Lưu ý: Khi thử nghiệm trên trình giả lập, bạn nên khởi động nó một lần ngay từ đầu phiên của mình và không đóng nó cho đến khi hoàn tất để không phải thực hiện lại quá trình khởi động.

Nhật ký giả lập và chạy

Trong hình trên:

  1. Trình giả lập chạy ứng dụng.
  2. Ngăn Chạy . Phần này hiển thị các hành động được thực hiện để cài đặt và chạy ứng dụng.

Chạy ứng dụng trên thiết bị vật lý

Luôn kiểm tra ứng dụng của bạn trên thiết bị thực vì người dùng sẽ sử dụng ứng dụng trên thiết bị thực. Mặc dù trình giả lập khá tốt nhưng chúng không thể hiển thị tất cả các trạng thái có thể có của thiết bị, chẳng hạn như điều gì sẽ xảy ra nếu có cuộc gọi đến trong khi ứng dụng đang chạy. Để chạy ứng dụng trên thiết bị vật lý, bạn cần những điều sau:

  • Một thiết bị Android như điện thoại thông minh hoặc máy tính bảng.
  • Cáp dữ liệu để kết nối thiết bị Android với máy tính của bạn qua cổng USB.
  • Nếu bạn đang sử dụng Linux hoặc Windows, có thể cần phải thực hiện các bước bổ sung để chạy ứng dụng trên thiết bị phần cứng. Kiểm tra tài liệu Sử dụng thiết bị phần cứng . Trên Windows, bạn có thể cần cài đặt trình điều khiển USB thích hợp cho thiết bị. Xem Trình điều khiển USB OEM .

Để Android Studio giao tiếp với thiết bị, hãy bật Gỡ lỗi USB trên thiết bị Android. Trên phiên bản Android 4.2 trở lên, màn hình Tùy chọn nhà phát triển bị ẩn theo mặc định. Làm theo các bước sau để bật USB Debugging:

  1. Trên thiết bị thực, hãy mở Cài đặt và chọn Giới thiệu về điện thoại ở cuối màn hình Cài đặt.
  2. Nhấn bảy lần vào thông tin Số bản dựng .

    Bạn đã đọc chính xác: Hãy chạm vào nó bảy lần .

  3. Quay lại màn hình trước đó ( Cài đặt ). Tùy chọn nhà phát triển hiện xuất hiện ở cuối màn hình. Nhấn Tùy chọn nhà phát triển .
  4. Chọn Gỡ lỗi USB .

Bây giờ, hãy kết nối thiết bị và chạy ứng dụng từ Android Studio.

 

Khắc phục sự cố kết nối thiết bị

Nếu Android Studio không nhận ra thiết bị, hãy thử cách sau:

  1. Ngắt kết nối thiết bị khỏi máy tính của bạn rồi kết nối lại.
  2. Khởi động lại AndroidStudio.
  3. Nếu máy tính của bạn vẫn không tìm thấy thiết bị hoặc thông báo là "trái phép":

    1. Ngắt kết nối thiết bị khỏi máy tính của bạn.

    2. Trên thiết bị, chọn Cài đặt > Tùy chọn nhà phát triển .

    3. Nhấn Thu hồi ủy quyền Gỡ lỗi USB .

    4. Kết nối lại thiết bị với máy tính của bạn.

    5. Khi được nhắc, hãy cấp quyền.

  4. Bạn có thể cần cài đặt trình điều khiển USB thích hợp cho thiết bị. Xem tài liệu Sử dụng thiết bị phần cứng .
  5. Kiểm tra tài liệu mới nhất, diễn đàn lập trình hoặc nhận trợ giúp từ người hướng dẫn của bạn.

Sử dụng nhật ký

Nhật ký là một công cụ sửa lỗi mạnh mẽ mà bạn có thể sử dụng để xem xét các giá trị, đường dẫn thực thi và ngoại lệ. Sau khi bạn thêm câu lệnh ghi nhật ký vào ứng dụng, thông báo nhật ký của bạn sẽ xuất hiện cùng với thông báo nhật ký chung trong tab logcat của ngăn Màn hình Android của Android Studio.

Để xem ngăn Màn hình Android, hãy nhấp vào nút Android Monito r ở cuối cửa sổ chính của Android Studio. Màn hình Android cung cấp hai tab:

  • Thẻ logcat . Tab logcat hiển thị thông báo tường trình về ứng dụng khi nó đang chạy. Nếu bạn thêm các câu lệnh ghi nhật ký vào ứng dụng, thông báo tường trình của bạn từ các câu lệnh này sẽ xuất hiện cùng với các thông báo tường trình khác trong tab này.
  • Tab Màn hình . Tab Màn hình theo dõi hiệu suất của ứng dụng, điều này có thể hữu ích cho việc gỡ lỗi và điều chỉnh mã của bạn.

Thêm báo cáo ghi nhật ký vào ứng dụng của bạn

Báo cáo ghi nhật ký thêm bất kỳ thông báo nào bạn chỉ định vào nhật ký. Việc thêm các câu lệnh ghi nhật ký tại các điểm nhất định trong mã cho phép nhà phát triển xem xét các giá trị, đường dẫn thực thi và ngoại lệ.

Ví dụ: câu lệnh ghi nhật ký sau đây thêm "MainActivity"và "Hello World"vào nhật ký:

Log.d("MainActivity", "Hello World");

Sau đây là các yếu tố của tuyên bố này:

  • Log: Lớp Nhật ký là API để gửi thông điệp tường trình.
  • d: Bạn chỉ định một mức nhật ký để bạn có thể lọc các thông báo tường trình bằng menu thả xuống ở giữa ngăn tab logcat . Sau đây là các mức nhật ký bạn có thể chỉ định:
    • d: Chọn Debug hoặc Verbose để xem các thông báo này.
    • e: Chọn Error hoặc Verbose để xem các thông báo này.
    • w: Chọn Cảnh báo hoặc Chi tiết để xem các thông báo này.
    • i: Chọn Thông tin hoặc Chi tiết để xem các thông báo này.
  • "MainActivity": Đối số đầu tiên là thẻ nhật ký có thể được sử dụng để lọc thư trong tab logcat . Đây thường là tên của hoạt động mà thông báo bắt nguồn từ đó. Tuy nhiên, bạn có thể biến điều này thành bất kỳ thứ gì hữu ích cho mình để gỡ lỗi ứng dụng. Cách thực hành tốt nhất là sử dụng hằng số làm thẻ nhật ký, như sau:
  1. Xác định thẻ nhật ký là một hằng số trước khi sử dụng nó trong câu lệnh ghi nhật ký:
      private static final String LOG_TAG =
           MainActivity.class.getSimpleName();
    
  2. Sử dụng hằng số trong báo cáo ghi nhật ký:
    Log.d(LOG_TAG, "Hello World");
    
  3. "Hello World": Đối số thứ hai là thông báo thực tế xuất hiện sau cấp nhật ký và thẻ nhật ký trong tab logcat .

Xem thông điệp bản ghi của bạn

Ngăn Chạy xuất hiện thay cho ngăn Màn hình Android khi bạn chạy ứng dụng trên trình giả lập hoặc thiết bị. Sau khi bắt đầu chạy ứng dụng, hãy nhấp vào nút Màn hình Android ở cuối cửa sổ chính, sau đó nhấp vào tab logcat trong ngăn Màn hình Android nếu nó chưa được chọn.Màn hình Android Hiển thị Thông báo Nhật ký

Trong hình trên:

  1. Câu lệnh ghi nhật ký trong onCreate()phương thức của MainActivity.
  2. Ngăn Màn hình Android đang hiển thị logcatthông báo nhật ký, bao gồm thông báo từ câu lệnh ghi nhật ký.

Theo mặc định, màn hình nhật ký được đặt thành Verbose trong menu thả xuống ở đầu màn hình logcat để hiển thị tất cả các thông báo. Bạn có thể thay đổi điều này thành Gỡ lỗi để xem các thư bắt đầu bằng Log.dhoặc thay đổi thành Lỗi để xem các thư bắt đầu bằng Log.e, v.v.

Xây dựng layout fragment_item.xml

Tên file cần tạo : fragment_item.xml

Nơi tạo file res/layout

Nội dung file

 

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

<layout 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">

<data>

<variable
name="car"
type="com.vantinviet.adayroionline.viewobject.Car" />

</data>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">



<TextView
android:id="@+id/car_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@{car.car_name}"
android:textAlignment="viewStart"
android:textColor="@color/md_black_1000"
android:textSize="@dimen/font_title_size"
app:font='@{"normal"}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
tools:text="Name" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>

Cám ơn bạn đã đọc tài liệu của chúng tôi

Công ty cổ phần thương mại Vạn Tín Việt

0936.006.058
0936.006.058