[컴][안드로이드] ViewPager refresh 하는 법



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를 참고하자.


References


  1. http://stackoverflow.com/questions/10849552/android-viewpager-cant-update-dynamically/10852046#10852046
  2. Fragment 의 life cycle

댓글 없음:

댓글 쓰기