Hiểu Navigation cơ bản trong Android thông qua Demo App !!!
Bài đăng này đã không được cập nhật trong 4 năm
1. Giới thiệu:
Navigation Componentlà một thư viện thành phần trong bộ thư viện củaAndroid Jetpack. Mục đích chính của nó là giúp cho việc điều hướng giữa các màn hình trở nên nhanh gọn và đơn giản hơn, dễ maintain, dễ quản lí cácStackvà được rất nhiều lập trình viên sử dụng trong code base của mình. Trong bài viết này mình sẽ cùng các bạn code một demo cơ bản và dễ hiểu nhất vềNavigationnhé !
2. Setup ban đầu:
- Chúng ta sẽ code trực tiếp trên project demo sẵn, trong đó đã có sẵn 4
fragmentđể chúng ta không phải mất thêm thời gian vẽ layout cũng như tạo các class fragment.kt. Ta sẽ clone về từ link sau : - https://github.com/google-developer-training/android-basics-kotlin-cupcake-app/tree/viewmodel
- Tại đây nếu các bạn checkout đến nhánh
viewmodelđể sử dụng luôn viewmodel có sẵn.
3. Setup navigation cho nút back tại actionBar:
- Tại lớp
MainActivity.ktta sẽ khai báo biến toàn cụcnavControllervà sẽ gọi phương thứcsetUpActionBarWithNavControllertrong phương thứconCreate:
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
}
- Tiếp đến ta gi đè phương thức
onSupportNavigateUpđể chỉ định activity này làhostcủanavigation:
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
4. Tìm hiểu thêm về ngăn xếp:
- Trong Android chúng ta tương tác với thiết bị thông qua các
ActivityvàFragmentmỗi thao tác của chúng ta từ khi khởi động app đều được xếp chồng lên nhau trong ngăn xếp (Back Stack), ta hình dung nó như một chồng bánh quy ( miếng bánh trên cùng mà chúng ta nhìn thấy chính làActivityhoặcFragmentđang hiển thị trên thiết bị. Còn những stack được xếp ở phía dưới nó sẽ được tạm dừng hoạt động và sẵn sàng quay trở lại màn hình chính nếu người dùng bấm nútBackcho đến khi tới stack đó. Quy trình củaBack Stacklà Last In First Out, có nghĩa là Stack nào được thêm vào ngăn xếp sau cùng thì khi bấmBacknó sẽ được mang ra trước rồi lần lượt như vậy. - Lấy ví dụ trong demo app
CupCakemà chúng ta đang viết, mặc dù chỉ có một activity nhưng lại có nhiều fragment nằm trong nó, nên khi chạy ứng dụngStartFragmentđược đẩy vào ngăn xếp và hiện tại đang đứng trên cùng :

- Sau khi bạn chọn số lượng bánh cho đơn hàng,
navigationsẽ điều hướng bạn đếnFlavorFragmentvàFlavorFragmentđược đẩy vàoBackStackvà đứng trên cùng của ngăn xếp :

- Tiếp đến bạn chọn hương vị cho đơn bánh và
navigationsẽ điều hướng bạn đếnPickUpFragmentvà cũng tương tự fragment này được đẩy tiếp vào trên cùng củaBackStack:

- Sau khi bấm
Nextbạn sẽ được điều hướng đếnSummaryFragmentvà cũng tương tự được đẩy vào ngăn xếp :

- Tại thời điểm này bạn bấm nút
Backtrên ActionBar hoặc nút back vật lí trên devices thìSummaryFragmentsẽ bật ra khỏiBackStackvà bị hủy hoàn toàn và bạn sẽ thấyPickUpFragmenthiển thị lên sau thao tác này:

- Tiếp tục bấm nút
Backthêm 2 lần nữa thìPickUpFragmentvàFlavorFragmentcũng lần lượt bị bật ra khỏiBackStackvà chỉ cònStartFragmenthiển thị trên màn hình :

-
Để làm được việc đó ta cần add action cho navigation, các bước như sau :
- Mở trình chỉnh sửa điều hướng:
res>navigation>nav_graph.xmlsau đó chọnDesign - Hiện tại ta đã thấy được từ
StartFragmenttớiFlavorFragmentđã có một hành động điều hướng đi theo chiều của mũi tên và lần lượt cũng vậy từFlavorFragmentcũng có hành động điều hướng đi tớiPickUpFragmentvà tương tự vớiSummaryFragment. Nhưng vấn đề ở chỗ khi bạn đặt hàng xong đơn hàng hoặc đã đến màn nào đó gần cuối nhưng bạn muốn hủy đơn hàng do sai sót gì đó và bạn muốn mình quay trở lạiStartFragmentđể tạo một đơn hàng mới hoàn toàn mà không phải Back lại quá nhiều lần, thì hãy thêm những action khác vào navigation này bằng cách sau. - Click vào
FlavorFragmentkéo đếnStartFragmentsẽ xuất hiện một mũi tên nối giữa hai fragment đó, làm điều tương tự vớiPickUpFragmentvàSummaryFragment. - Cuối cùng
nav_graphhoàn chỉnh sẽ trông như sau :
![Screenshot from 2021-09-12 19-02-09.png]()
- Mở trình chỉnh sửa điều hướng:
5. Thêm button Cancel vào các fragment:
- Việc này như đã nói ở trên sẽ giúp bạn không phải bấm
Backquá nhiều lần mà chỉ cần bấmCancelthì lập tức sẽ trở về fragment đầu tiên và sẵn sàng cho đơn hàng mới. - Thêm đoạn mã sau vào
fragment_flavor.xml:
<Button
android:id="@+id/cancel_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/cancel"
style="?attr/materialButtonOutlinedStyle"
android:layout_marginEnd="@dimen/side_margin"
app:layout_constraintEnd_toStartOf="@id/next_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/next_button" />
- Và sửa
next_buttonthànhapp:layout_constraintStart_toEndOf="@id/cancel_button" - Thực hiện tương tự tại
fragment_flavorvàfragment_summary - Tại class
FravorFragment.ktta thêm phương thức sau :
fun cancelOrder() {
sharedViewModel.resetOrder()
findNavController().navigate(R.id.action_flavorFragment_to_startFragment)
}
- Phương thức này gọi đến
actionđiều hướng từFlavorFragmenttớiStarFragment - Quay lại
fragment_flavor.xmlvà thêmonClickcho buttonCancel:
android:onClick="@{() -> flavorFragment.cancelOrder()}"
- Ta sẽ làm tương tự với
PickUpFragmentvàSummaryFragment. - Tại đây ta có thể chạy ứng dụng và sử dụng nút
Cancelđể tạo đơn hàng mới từ bất cứ fragment nào. - Nhưng có một vấn đề phát sinh ở đây là khi bạn đã đến
SummaryFragmentvà bấmCancelthì màn hìnhStartFragmenthiển thị lên, điều này trông có vẻ đúng. Nhưng nếu tiếp tục bấmBackthì sẽ trở lạiSummaryFragmentvới thông tin bị bỏ trống. Qua đây ta có thể hình dung ra được khi bấmCancellàStartFragmentđược đẩy tiếp tục vào trongBackStackvà nhữngstacktrước đó vẫn còn tồn tại gây ra trải nghiệm xấu cho người dùng :

-
Để giải quyết vấn đề trên ta cần 2 bước:
- Thêm thuộc tính
app:popUpTo = "@id/startFragment"vào trong action của navigation sẽ giúp bật lần lượt các ngăn xếp cho đến khi gặp đượcStartFragment. Sau bước nàyBackStacktrông như sau:
![Screenshot from 2021-09-12 19-22-52.png]()
- Nhưng trên hình ta cũng có thể thấy được là nếu bấm
Backtiếp thì sẽ lại được điều hướng đến một bản sao củaStartFragmentnên ta cần thêm thuộc tínhapp:popUpToInclusive="true"vào trong action của navigation. Điều này sẽ giúp các ngăn xếp được bật ra ngoài lần lượt đến và luôn cảStartFragmentcũ. - Cách thực hiện thì các bạn quay lại thao tác giống bước trên để mở ra cửa sổ chỉnh sửa điều hướng, sau đó click vào mũi tên từ
SummaryFragmentchỉ tớiStartFragmentvà mũi tên đó sẽ sáng lên màu xanh, bạn nhìn sang bảngAttributebên phải và chọnpopUpTochọnStartFragmentcòn dòng bên dướipopUpToInclusivechọntrue
![Screenshot from 2021-09-12 19-29-32.png]()
- Ta làm tương tự với
PickUpFragmentvàFlavorFragment
- Thêm thuộc tính
-
Đến đây ta đã giải quyết tất cả các vấn đề liên quan đến
navigationthông qua việc sử dụng nútBacktrên actionBar, nútBackvật lí và cả nútCancelnữa, hi vọng các bạn sẽ hiểu hơn về việc sửNavigationvà sẽ áp dụng nó vào project của mình. -
Cảm ơn các bạn đã theo dõi bài viết !!
-
Nguồn : https://developer.android.com/codelabs/basic-android-kotlin-training-navigation-backstack#0
All rights reserved


