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를 참고하자.
댓글 없음:
댓글 쓰기