Computer >> Hướng Dẫn Máy Tính >  >> Hệ Thống >> Android

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Thiết kế ứng dụng thường rườm rà và thường có whiteboard với mũi tên chỉ từ điểm này sang điểm khác.

App bạn ban đầu nghĩ chỉ 1-2 activity, bỗng có multiple flow, fragment và nhiều user interaction. Không hay nếu lấy thứ trên whiteboard replicate dễ dàng vào code?

Chào đón Navigation Component.

Đối với người lạ, Navigation Component không phải UI class khác đặt thay layout cho activity/fragment. Hãy coi nó như bản đồ: thay vì lục địa, bạn có fragment, và cần directions để đi từ lục địa này sang lục địa khác. Nó trình bày fragment và kết nối giữa chúng theo cách top-down. Bài này đi qua khía cạnh chính component này và học cách tích hợp vào app.

Sẵn sàng khởi hành? ⛵️

Học cách dùng

Navigation component có từ Android Studio 3.3 trở lên. Để dùng, thêm dependencies sau vào project:

android { ... } dependencies { implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0' implementation 'androidx.navigation:navigation-ui-ktx:2.0.0' }

Để có gì làm việc, tưởng tượng app thiết kế với cấu trúc:

  • Start Fragment
  • Fragment A
  • Fragment B

User có thể đi Fragment A hoặc Fragment B từ Start fragment.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Ứng dụng của chúng ta

Nếu làm không dùng Navigation Component, phải thêm code quen thuộc mở fragment khi button click.

val myFragment : MyFragment = MyFragment() supportFragmentManager.beginTransaction().add(R.id.container, myFragment).commit()

Ví dụ nhỏ này chỉ vài dòng ngắn, đơn giản, nhưng chúng ta đồng ý cách này không scale nếu app lớn và user flow phức tạp.

All Aboard

Để dùng Navigation Component, tạo navigation graph. Graph này làm map, outline user flow trong app. Tạo: right-click res folder → new resource file. Đặt tên: user_flow_graph.xml. Chọn type: Navigation.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Tạo resource file mới

Mỗi chuyến đi có home base, chúng ta cũng vậy. Home gọi là NavHost. Placeholder cho destination swap khi user tương tác UI. Thêm NavHost vào main layout activity:

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="https://schemas.android.com/apk/res-auto" tools:context=".MainActivity"> <fragment android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:defaultNavHost="true" app:navGraph="@navigation/user_flow_graph" /> </androidx.constraintlayout.widget.ConstraintLayout>

Thêm fragment element chứa nơi fragment hiển thị và swap. Chú ý attribute navGraph link đến XML file trước.

Cần thêm starting destination, app không compile nếu không có.

Mở user_flow_graph.xml, click icon plus nhỏ trong Navigation Editor:

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Thêm Destination

Menu popup cho phép tạo placeholder (điền sau) hoặc chọn fragment có sẵn:

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Lựa chọn Destination

User flow bắt đầu từ Start Fragment, chọn nó trước.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Home base (chú ý icon ? nhỏ)

Thêm Fragment A và Fragment B.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Tất cả destination

Kết nối 2 destination: click dot hiện ra khi hover destination, kéo đến destination khác.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Khá gọn gàng, phải không?

Chúng ta vừa tạo giữa Start fragment và Fragment A, B là actions.

Shiver me Timbers

Bạn có thể tự hỏi: chỉ connect destination xong việc, mọi thứ tự động work?

Không.

Cần báo code navigate đến destination. Làm sao? Có chút magic.

Đầu tiên, thêm gradle plugin Safe Args. Đảm bảo type safety khi navigate giữa destination.

 buildscript { /... } dependencies { ... classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.0.0" } }

Cũng cần thêm plugin vào app build.gradle:

apply plugin: "androidx.navigation.safeargs.kotlin" 

Đảm bảo android.useAndroidX=true trong gradle.properties.

Trước khi tiến xa, hiểu tại sao cần config này. Khi tạo actions, behind the scenes Android Studio sinh code dùng để activate action. Code gồm method và class represent mỗi action. Lấy Start fragment ví dụ. Code sinh cho actions khai báo có class StartFragmentDirections. Method cho class này represent actions tạo trước. Cho cả 2 fragment:

  • StartFragmentDirections.actionStartFragmentToFragmentA()
  • StartFragmentDirections.actionStartFragmentToFragmentB()

Actions đã translate thành code, dùng chúng:

val action = StartFragmentDirections.actionStartFragmentToFragmentA() 

Bước cuối: dùng NavController. Object quản lý navigation trong NavHost. Truy cập bằng 3 cách:

  • Fragment.findNavController()
  • View.findNavController()
  • Activity.findNavController(viewId: Int)

Gộp lại:

fragmentABtn.setOnClickListener { button -> val action = StartFragmentDirections.actionStartFragmentToFragmentA() button.findNavController().navigate(action) }

Trim Your Sails

Muốn pass data giữa destination? Giả sử user click item, muốn làm gì đó với item ở destination tiếp theo. Dùng destination arguments. Mở user_flow_graph.xml, click Fragment A. Bên phải, menu attribute Fragment A. Một attribute: Arguments.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Thêm argument: click icon ➕. Popup mở, config argument. Đặt tên, chọn type, thêm default value. Thêm argument String type cho Fragment A, là message từ Start fragment.

Thành thạo Android Navigation Component: Xây dựng, Triển khai & Tối ưu

Trong Start fragment, nơi define action và gọi generated method, pass argument:

fragmentABtn.setOnClickListener { button -> val action = StartFragmentDirections.actionStartFragmentToFragmentA("Hello From Start Fragment") button.findNavController().navigate(action) }

Truy cập ở Fragment A, 2 cách:

  • Access bundle lấy message value
class FragmentA: Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val bundle = arguments val root = inflater.inflate(R.layout.fragment_a, container, false) val textView : TextView = root.findViewById(R.id.textView) textView.text = bundle?.getString("message") return root } }
  • Dùng navArgs nếu dùng -ktx dependencies
class FragmentA: Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val args : FragmentAArgs by navArgs() val root = inflater.inflate(R.layout.fragment_a, container, false) val textView : TextView = root.findViewById(R.id.textView) textView.text = args.message return root } }

✋ Khi dùng navArgs, cần thêm support Java 8 trong build.gradle.

Tất cả code ở đây tại GitHub repository này.