12/08/2018, 15:57

Adapting ViewPager in Android

Khi làm việc với các ứng dụng Android chắc hẳn chúng ta đã khá quen với ViewPager. ViewPager là một layout manager cho phép người dùng flip và xem các trang trái và phải. Nó được sử dụng kết hợp với PagerAdapter, FragmentPagerAdapter hoặc FragmentStatePagerAdapter. Đó là 3 adapter chúng ta sử dụng ...

Khi làm việc với các ứng dụng Android chắc hẳn chúng ta đã khá quen với ViewPager. ViewPager là một layout manager cho phép người dùng flip và xem các trang trái và phải. Nó được sử dụng kết hợp với PagerAdapter, FragmentPagerAdapter hoặc FragmentStatePagerAdapter. Đó là 3 adapter chúng ta sử dụng cùng với ViewPager, giờ chúng ta sẽ tìm hiểu sự khác biệt giữa chúng để xem nên sử dụng adapter nào cho phù hợp.

PagerAdapter

  1. PagerAdapter là lớp cơ sở cho cả FragmentPagerAdapter và FragmentStatePagerAdapter.
  2. Nếu bạn phải hiển thị các custom view (không phải Fragment) thì chỉ cần extend nó và override các phương thức cần thiết
    • instantiateItem(ViewGroup, int)
    • destroyItem(ViewGroup, int, Object)
    • getCount()
    • isViewFromObject(View, Object)

Trong phương thức instantiateItem() ta có thể inflate 1 view nào đó mong muốn và add nó vào ViewGroup của ViewPager

override fun instantiateItem(container: ViewGroup, position: Int): Object {
	val view = inflate(R.layout.photo_layout, container, false)
	
	val title = view.findViewById<TextView>(R.id.title)
	val image = view.findViewById<ImageView>(R.id.image)
	
	val data = Datas[position]
	title.text = data.title
	image.setImageDrawable(data.drawable)
	
	container.addView(view)
	return view
}
  1. PagerAdapter chỉ giữ tối đa 3 view trong bộ nhớ memory, 1 view hiện tại đc hiển thị visible, 1 view bên trái và 1 view bên phải. Trong quá trình scroll để di chuyển các page, các page bị đi ra ngoài sẽ bị destroy trong phương thức destroyItem(ViewGroup, int, Object)
override fun destroyItem(container: ViewGroup, position: Int, object: Object) {
	container.removeView((View) object)
}
  1. getCount() trả về số lượng item sẽ đc show bởi ViewPager
  2. isViewFromObject(View, Object) phương thức kiểm tra xem các đối tượng đc trả về bởi instantiateItem() đc liên kết với View được cung cấp. Chú ý: trong PagerAdapter, PagerFragmentAdapter và PagerFragmentStateAdapter, các View hoặc các Fragments được nhận dạng bởi một key Object chứ không phải bởi index hay position trong adapter. Để đơn giản nhất, chúng ta có thể trả về View hoặc Fragment được tạo ra trong instantiateItem() và trong phương thức isViewFromObject() ta chỉ cần so sánh View và Object để kiểm tra mối liên hệ giữa chúng.
override fun isViewFromObject(view: View, object: Object): Boolean {
	return object == view
}

FragmentPagerAdapter

  1. Trong FragmentPagerAdapter ta chỉ cần implement 2 phương thức getItem() và getCount() để có 1 adapter hoạt động được
  2. getItem() được gọi bởi instantiateItem() để tạo một fragment mới
  3. Trong FragmentPagerAdapter, khi một fragment được tạo, nó sẽ không bao giờ bị phá hủy trong suốt cuộc đời của adapter. Các fragment sẽ được giữ bởi FragmentManager và sẽ được sử dụng lại bất cứ khi nào ta cần một fragment mới để hiển thị. Các fragment cần thiết một lần nữa sẽ được lấy từ FragmentManager và view của nó sẽ được tạo lại thông qua các phương thức onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), và onResume().
  4. Nếu fragment lần đầu tiên đc khởi tạo, các phương thức sẽ lần lượt đc gọi là onAttach(), onCreate(), onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), and onResume().
  5. Nếu fragment di chuyển khỏi màn hình các phương thức onPause(), onStop(), onDestroyView() sẽ đc gọi theo thứ tự. Lưu ý rằng các phương thứconDestroy() va onDetach() sẽ không bao giờ đc gọi khi fragment di chuyển ra khỏi màn hình, điều đó có nghĩa rằng các fragment sẽ không bị phá hủy một khi đã đc tạo ra và nó sẽ đc tổ chức bởi FragmentManager.
override fun getItem(position: Int): Fragment {
	return Fragment.newInstance(datas[position])
}

Nếu số lượng fragment là lớn, sử dụng FragmentPagerAdapter sẽ khiến ta mất rất nhiều bộ nhớ, vì các fragment sẽ không bị phá hủy khi chúng đã đc tạo ra. Nó chỉ destroy phân cấp view và giữ lại trạng thái nội bộ. Vì vậy để khắc phục điều này ta có thể sử dụng FragmentStatePagerAdapter.

FragmentStatePagerAdapter

Trong hầu hết các đặc tính thì FragmentStatePagerAdapter sẽ giống với FragmentPagerAdapter. FragmentStatePagerAdapter chỉ khác FragmentPagerAdapter ở cách mà phá hủy các fragment khi chúng được di chuyển ra khỏi màn hình. Các fragment sẽ được creat, attach, destroy và detach để giữ bộ nhớ luôn ở mức thấp. FragmentStatePagerAdapter giữ tối đa 3 fragment. FragmentStatePagerAdapter sẽ phù hợp cho trường hợp có số lượng lớn fragment, nó sẽ giúp cho việc cải thiện memory tốt hơn.

Trên đây là các đặc điểm của PagerAdapter, FragmentPagerAdapter và FragmentStatePagerAdapter, các khía cạnh điểm giống nhau khác nhau đã được nêu ra, mong rằng bài viết sẽ giúp ích được bạn trong việc xử lý ViewPager và các Fragment.

0