Vận dụng lợi thế Kotlin để viết hàm Add và Replace Fragment mà Java không làm nổi trong Android

Nhưng chúng ta đã biết tại Google I/0 2017 thì Google đã đưa Kotlin và hướng đến nó sẽ trở thành ngôn ngữ lập trình chính cho Android. Trong quá trình tìm hiểu và học hỏi Kotlin để bắt kịp xu thế công nghệ, tôi thường hay đem Kotlin so sánh với Java liệu nó có điểm nào hơn, có những gì nó làm được mà Java không làm được. Hay đơn giản đặt câu hỏi tại sao Google lại muốn Kotlin thay thế Java trong lập trình Android. Trong quá trình tìm hiểu đó tôi rút ra và học hỏi được khá nhiều cách làm việc với Kotlin và trước kia đối Java chúng ta sẽ mất nhiều thời gian cho nó. Trong phạm vi bài viết này tôi sẽ chia sẻ cho các bạn một thủ thuật làm việc tận dụng ưu thế của Kotlin vào lập trình Android trong việc tạo hàm Add hoặc Replace Fragment 😃

Nếu bạn làm việc với Android thì ắt bạn không thể không biết việc Add và Replace Fragment qua Fragment Manager Hãy cũng thử xem với Java chúng ta sẽ làm gì:

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(frameId, fragment);
transaction.commit();

Để tránh code phải viết đi viết lại và tránh lỗi trong các Activity thì ta thường hay cho vào 1 class mang tên ActivityUtils và đặt static cho nó và gọi bất cứ đâu, miễn là truyền đúng Context là Activity là được

public static void addFragmentToActivity(FragmentManager manager, Fragment fragment, int frameId) {
    
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.add(frameId, fragment);
    transaction.commit();
    
}

và đây là cách mà ta sử dụng nó

ActivityUtil.addFragmentToActivity(
        getSupportFragmentManager(), fragment, R.id.frag_container);

Tất cả vậy đó, có gì thú vị ở đây không nhỉ, có bao giờ bạn nghĩ chính bản thân thằng Activity nó có sẵn hàm Add hoặc Replace Fragment cho bạn dùng không? Tôi cũng không biết nữa, trong tương lại Google có support việc đó hay không, tuy nhiên với kotlin bạn có thể viết thêm cho Acitivty hàm đó mà lại không cần tạo lớp mở rộng cho Acitivity nhé. Hãy cũng tôi tìm hiểu tại sao với Kotlin ta lại có thể làm được việc đó.

Loại bỏ sai xót với beginTransaction() và commit()

Có bao giờ bạn mất hàng chục phút hay có khi hàng giờ để debug app vì mấy fragment khi add vào bạn quên commit() hay beginTransaction() không? Để tránh sai xót đó ta sẽ tạo 1 phương thức mở rộng cho FragmentManager và sử dụng Lamda như một tham số Dưới đây là 1 số kiến thức cần có về Kotlin bạn cần biết để có thể hiểu được tiếp những gì tôi sắp nói dưới đây

Giới thiệu nhanh về tính năng của Kotlin mà sẽ sử dụng trong bài viết Extension function : Là cách mà Kotlin cho phép bạn thêm 1 function hoặc thuộc tính vào 1 class có sẵn kể cả là class của SDK.Bên trong fuction đó ta có thể truy cập vào thuộc tính hoặc phương thức public . Về thực tế nó không sửa code của class có sẵn, nó chỉ mở rộng thêm mà thôi Higher Order Function: là cho phép function có thể dùng 1 function khác làm tham số hoặc trả về 1 function. Chúng ta có thể truyền vào hoặc trả về 1 function như một data thông thường Lambda with Receiver: là sự kết hợp của 2 chức năng nó trên Higher order function và Hàm mở rộng để truyền 1 Reciver vào như 1 tham sổ. Trong biết thức lamda chúng ta có thể dùng mọi thuộc tính và phương thức của Receiver Hơi khó hiểu phải không nào cũng xem ví dụ dưới đây cho dễ hiểu nhé This is the Extension function to the FragmentManager which accepts a Lambda with Receiver as its argument, whereas the FragmentTransaction is the Receiver. Đầu tiên ta sẽ định nghĩa 1 function mở rộng cho FragmentManager chấp nhận một Lamda Receiver là tham số, ở đây FragmentTransaction là Receiver

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
    val fragmentTransaction = beginTransaction()
    fragmentTransaction.func()
    fragmentTransaction.commit()
}

Theo như code thì ở đây func là một tham số và nó cũng chính là 1 hàm rộng của FragmentTransaction với tham số truyền vào trống và giá trị trả về là Unit (Khống trả về gì) , func sẽ được gọi sau khi beginTransaction() và sau khi func được gọi thì commit() sẽ được gọi ngay sau đó. Để sử dụng hàm mở rộng này ở Activity ta dùng như sau:

supportFragmentManager.inTransaction {
    add(R.id.frameLayoutContent, fragment)
}

Trong biết thức Lamda bạn hoàn toàn có thể gọi thêm remove hoặc cả add và remove miễn là phương thức của FragmentTransaction vì đây là hàm mở rộng của FragmentTransaction. Bằng việc sử dụng trên chúng ta sẽ không cần quan tâm việc gọi beginTransaction() hay commit() nữa. Cũng xem cách gọi công việc trong phương thức này như nào:

supportFragmentManager.inTransaction {
    remove(fragmentA)    
    add(R.id.frameLayoutContent, fragmentB)
}

Có thể thấy ta vừa remove Fragment A và thêm vào **Framgment B.

Mở rộng phương thức cho Acitivty

Như phần mở đâu tôi có nói : Activity có support add hay remove Fragment không? Chắc chắn là không rồi, và làm sao để thêm phương thức cho nó. Như kiến thức phía trên ta dùng Extension function cho Activity là xong phải không nào. Sẽ chả cần ActivityUtisl nữa, mà ta sẽ có thể gọi trực tiếp trong Activity luôn. Ta tạo hàm add và replace Fragment mở rộng cho Activity như sau:

fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int){
    supportFragmentManager.inTransaction { add(frameId, fragment) }
}


fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
    supportFragmentManager.inTransaction{replace(frameId, fragment)}
}

Sau khi định nghĩa hàm này rồi thì các Activity của bạn về sau bạn chỉ cần

addFragment(fragment, R.id.fragment_container)

replaceFragment(fragment, R.id.fragment_container)

để có thể add hoặc remove Fragment một cách dễ dàng rồi.

Với Kotlin ta còn làm được nhiều hơn thế nữa, tuy nhiên trong phạm vi bài viết tôi chỉ có thể giới thiệu ứng dụng của nó trong việc cụ thể là add và replace Fragment. Hãy cũng chờ đón các bài viết tiếp theo của tôi để cùng khám phá sự tuyệt vời của Kotlin bạn nhé?

Tham khảo medium.com