Android

Một số điểm cần lưu ý khi thao tác với Fragment

Thao tác với Fragment không khó. Tuy nhiên, để ứng dụng hoạt động hiệu quả, ít bị dừng, cũng như tối ưu hóa dữ liệu, thì bạn cần lưu ý một số vấn đề mà tôi sẽ trình bày bên dưới. Cũng xin nói trước là chúng không phải là toàn bộ tất cả các điều liên quan tới Fragment. Bạn cần thao tác nhiều để rút ra thêm các kinh nghiệm, cũng như tối ưu hóa code cho project của bạn.

1. Constructors

Có một điều mà các bạn làm nhiều, làm “cả đời” rồi nhưng chưa hề để ý: Bạn không tạo Constructor trong các class về Activity hay Service. Ví dụ bạn làm một Activity mới, thì bạn làm một class cho extends (AppCompat)Activity rồi khai báo field members và bắt đầu thao tác trong onCreate(Bundle). Trong lúc thao tác với Fragment thì cũng vậy thôi. Không bao giờ được xóa Constructor rỗng không có tham số bằng Constructor có tham số. Thực tế là trong những trường hợp cực kì hiếm gặp, bạn có thể phải làm Fragment với Constructor cần tham số, mà thông thường nhất là do bạn cần các kiểu params có kiểu dữ liệu mà Bundle (arguments của Fragment) không hỗ trợ, chẳng hạn như bạn muốn “quất” luôn một View hay một SQLiteDatabase hay một FirebaseDatabase instance. Tuy nhiên, bạn vẫn không được bỏ cái Constructor rỗng đi được. Lí do là như sau:

Về mặt Activity, thì khi Android system khởi tạo một JVM để chạy ứng dụng của bạn, thì cái ứng dụng chạy đầu tiên không phải là cái Activity có IntentFilter là MAIN/LAUNCHER (tôi tạm gọi là FirstActivity) đâu, mà lạ một tên Zygote. Zygote chứa hàm main(String[] args) của Java (nên bấy giờ bạn hiểu là tại sao trong code của bạn không có hàm main này rồi đó, cái này đã được lo liệu rồi). Khi nó gọi Activity đầu tiên (hay các Activity gọi lẫn nhau cũng vậy) thì nó sẽ tạo một instance của FirstActivity như sau:

Bạn có để ý thấy nó tạo instance qua public Constructor rỗng, không có một param nào cả. Nếu tự dưng bạn định nghĩa một Constructor khác có tham số, và theo mặc định thì khi có Constructor nào mà người code định nghĩa thì compiler sẽ tự động bỏ Constructor rỗng mặc định, chẳng hạn:

Như vậy, tự dưng cái Constructor FirstActivity() sẽ bị thay thế bởi cái bạn vừa định nghĩa – trừ khi bạn tự định nghĩa lại một cái rỗng – và khi Zygote chạy tới FirstActivity activity = new FirstActivity(); thì nó sẽ dừng, vì “Có cái Constructor nào như vậy đâu để tôi tạo instance”, chưa tính tới việc cái aString phải truyền vào là cái gì nữa, vì bạn có thấy class Zygote này và thao tác với nó được đâu để định nghĩa aString kia. Và như vậy, là ứng dụng của bạn toi luôn. Hay không bằng may. Nếu bạn cứ code ào ào mà không để ý tới Constructor của Activity thì có khi lại hay.

Tương tự như vậy, khi Activity gọi Fragment, nếu như bạn định nghĩa Fragment Constructor có tham số và truyền các tham số tương ứng vào trong các hàm của Activity thì không sao. Tuy nhiên, nếu bạn tính tới chuyện save Fragment state với FragmentManager và Bundle savedInstanceState của Activity, thì coi chừng là toi, vì theo mặc định thì FragmentManager sẽ gọi public Constructor rỗng của các Fragment được lưu, và nếu không có Constructor rỗng thì èo… Ứng dụng sẽ dừng.

Vì vậy, khi bạn thao tác với Activity, Service, Fragment, hay tạo các data classes, thì bạn phải luôn có public Constructor rỗng không có tham số (có thể có nội dung hay không thì tùy bạn). Thà có mà không dùng còn hơn không có để rồi ngồi trách “sá xị lại có gas”. Tốt nhất, hãy làm hàm public static newInstance để gián tiếp truyền tham số vào Fragment thay cho Constructor.

2. Nên dùng thư viện Support trừ khi bạn chắc chắn 100% là bạn không cần.

Cho dù bạn đang targetApi là 25, mới nhất, hay targetApi là 16, cũ nhất, thì vẫn nên cân nhắc dùng thư viện Support thay cho thư viện Framework về Fragment. Thứ nhất, như tôi đã “ca đi hát lại” mấy lần, thư viện Support, cụ thể là vơ sần 25, sẽ resemble các class của các thư viện Framework của Api25, như vậy bạn có thể dùng được các APIs của Nougat_7.1 trên các mức Api cũ hơn chẳng hạn như 16. Bạn sẽ không cần xét tới việc các thư viện Framework của thiết bị khách có hỗ trợ hàm này, hàm kia không, vì thư viện Support sẽ được đóng gói với ứng dụng của bạn. Thứ hai, các thư viện support luôn được cập nhật và sửa lỗi đều đặn – vốn là điều không thể với thư viện Framework trừ khi có bản cập nhật mới.

3. Fragment không tách khỏi Activity.

Để gọi Fragment, thì bạn phải đi từ Activity, gọi getFragmentManager() hoặc getSupportFragmentManager() và rồi gọi tiếp beginTransaction(). Do FragmentManager chỉ gọi được từ Activity nên Fragment bao giờ cũng không tách rời khỏi Activity. Vì vậy, bạn không nên cố gắng “nâng tầm” Fragment lên và cố nhồi nhét các tính năng của Activity cho nó, chẳng hạn như getIntent() trực tiếp. Thay vào đó, bạn đi từ Activity, tức là getIntent từ Activity chứa Fragment đó.

4. Tận dụng Fragment.

Không có một điều luật nào yêu cầu là mỗi Fragment chỉ được gắn vào một Activity duy nhất, hay được sử dụng một lần duy nhất, hoặc được sử dụng với một mục đích duy nhất. Chẳng hạn thay vì làm hai PreferenceFragment cho hai loại Settings khác nhau, tôi chỉ làm một cái duy nhất. Chẳng hạn:

Hoặc gần gũi hơn nữa là làm ViewPager, với dữ liệu Fragment nào cũng na ná nhau, chẳng hạn như các Fragment chứa nội dung bản tin của Google Play Newsstand, thì bạn chỉ làm một loại Fragment và truyền tham số là Url gốc tới bản tin là được. Với số lượng bản tin không đoán trước được, thì bạn biết phải làm bao nhiêu cái giống y chang nhau cho đủ hoặc hợp lí đây!

Trên đây là một số gợi ý nhỏ mà các bạn khi mới tập tành làm Fragment sẽ cần và gặp. Trong quá trình thao tác lâu dài, sẽ có những điểm khác mà chính các bạn sẽ tự rút ra kinh nghiệm để trước hết là tránh bị thrown các Exception, sau là tinh giản, tối ưu hóa code để vừa giảm được số dòng code dài dòng, vừa giảm bớt dung lượng của ứng dụng và tăng tốc thực thi của các Activity. Chúc các bạn thành công.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.