ViewPager에서 FragmentPagerAdapter 를 이용할 때 FragmentPagerAdapter 의 data 가 변경되었을 때 refresh 를 하는 방법을 알아보자.
ListView 에서 getView() 를 이용하는 것처럼 ViewPager 에 FragmentPagerAdapter를 이용하면, ViewPager 는 FragmentPagerAdapter 의 getItem() 을 통해 fragment 를 얻어서 사용한다.
getItem()
보통 getItem() 내부를 override 해서 new Fragment() 를 하게 된다. 이 때 새로 만들고 싶으면 아래처럼 만들어주면 된다.@Override public Fragment getItem(int position) { switch (position) { case 0: case 1: case 2: case 3: return ListFragment.newInstance(position); default: return ListFragment.newInstance(position); } }
ListView 에 Adapter 를 set 하면, 보통 Adapter.notifyDataSetChanged() 을 호출함으로써 새롭게 바뀐 data 를 다시 그리게 할 수 있다. 그런데 ViewPager 에서는 단순히 PagerAdapter.notifyDataSetChanged() 을 호출하는 것만으로는 화면을 다시 그리지 않는다.
PagerAdapter.setDataSetObserver()
ViewPager.setAdapter() 에서 PagerAdapter 를 ViewPager에 attach 시킨다. 또한, 이 setAdapter() 에서 아래 코드처럼 PagerAdapter 에 DataSetObserver 를 attach 한다.- mAdapter.setDataSetObserver(mObserver);
DataSetObserver 는 ViewPager에 아래처럼 정의되어 있다.
private class DataSetObserver implements PagerAdapter.DataSetObserver { @Override public void onDataSetChanged() { dataSetChanged(); } }
이제 PagerAdapter 가 변경될 때마다 dataSetChanged() 가 호출될 것이다.
void dataSetChanged() { ... boolean isUpdating = false; for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); final int newPos = mAdapter.getItemPosition(ii.object); if (newPos == PagerAdapter.POSITION_UNCHANGED) { continue; } if (newPos == PagerAdapter.POSITION_NONE) { ... mAdapter.destroyItem(this, ii.position, ii.object); needPopulate = true; ... continue; } ... } if (isUpdating) { mAdapter.finishUpdate(this); } ... if (needPopulate) { // Reset our known page widths; populate will recompute them. final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (!lp.isDecor) { lp.widthFactor = 0.f; } } ... requestLayout(); } }
그래서 이 ViewPager 의 Fragment 의 내용이 변경되어서 이를 update 시키기 위해서는 아래 처럼 getItemPosition() 을 override 해 줘야 한다.[ref. 1]
@Override public int getItemPosition(Object item) { ListFragment fragment = (ListFragment) item; if (ischanged()) { return POSITION_UNCHANGED; } else { // after this, onCreateView() of Fragment is called. return POSITION_NONE; // notifyDataSetChanged } }
위와 같은 부분이 새롭게 들어가지 않는다면, dataSetChanged() 가 호출되어도 Fragment 를 다시 그리지 않는다.
그리고 참고로, Fragment 가 update 가 되면, OP_ATTACH 를 통해 onCreateView() 가 호출된다. 그러므로 data 가 변경되고 다시 호출되어야 하는 내용이 있다면 onCreateView() 에 넣어야 한다.
Stack
getItem() Stack
getItem():56, MyPagerAdapter {com.my}
instantiateItem():97, FragmentPagerAdapter {android.support.v4.app}
addNewItem():832, ViewPager {android.support.v4.view}
populate():982, ViewPager {android.support.v4.view}
populate():914, ViewPager {android.support.v4.view}
onMeasure():1436, ViewPager {android.support.v4.view}
onCreate() stack
onCreate():59, MyListFragment {com.my}
performCreate():1477, Fragment {android.support.v4.app}
moveToState():893, FragmentManagerImpl {android.support.v4.app} moveToState():1104, FragmentManagerImpl {android.support.v4.app}
run():682, BackStackRecord {android.support.v4.app}
execPendingActions():1467, FragmentManagerImpl {android.support.v4.app}
executePendingTransactions():472, FragmentManagerImpl {android.support.v4.app}
finishUpdate():141, FragmentPagerAdapter {android.support.v4.app}
populate():1068, ViewPager {android.support.v4.view}
populate():914, ViewPager {android.support.v4.view}
fragment 에서 onCreate() 이 불리고, onCreateView() 가 불리는 과정은 ref. 2를 참고하자.
댓글 없음:
댓글 쓰기