Fragment 와 ViewPager
Drawer 와 ViewPager
ViewPager 와 FragmentPagerAdapter 를 사용할 때 주의할 점
아래처럼 drawer 와 view pager 를 함께 쓰고 있다. 그리고 이 viewpager 는 fragment 안에 들어가 있다. 그리고 이 viewpager 를 FragmentPagerAdapter 를 사용하고 있다.
이 view hierarchy 를 그려보면 아래와 같다.
Activity | +---- Drawer | +----- Fragment | | | +---- ViewPager | | | +---- Fragment | | | +---- Fragment | +----- Fragment | | ...
fragment 안에 FragmentPagerAdapter 를 이용하는 viewpager 를 사용할 때 문제점
Drawer 메뉴에서 item 을 선택하면 해당하는 Fragment 를 새로 생성하게 되어 있다. 근데 이때 문제가 발생했다. viewpager 가 fragment 를 새로 생성하지 않았다. 이유를 알기 위해 debugging 을 해봤다.보통 ViewPager 는 아래와 같은 경로로 자신의 adapter (FragmentPagerAdapter)에 있는 fragment 를 가져오게 된다.
이 때 findFragmentByTag를 이용한다. 그래서 문제가 좀 발생한다.
onMeasure():1545, ViewPager (android.support.v4.view)
populate():1025, ViewPager (android.support.v4.view)
populate():1091, ViewPager (android.support.v4.view)
addNewItem():943, ViewPager (android.support.v4.view)
instantiateItem():97, FragmentPagerAdapter (android.support.v4.app)
getItem():86, FragPagerAdapter (com.hbwhale.seedmoney)
@Override public Object instantiateItem(ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { ... mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); } ... return fragment; }
이 상황에서 문제가 되는 것은 먼저 FragmentPagerAdapter 가 fragment 를 만들기 전에 특정 tag name 으로 된 fragment 가 있는지 확인을 해서 있다면 그녀석을 사용하게 된다. 그런데 문제는 tag name 으로 container.getId() + getItemId() 를 사용한다는 것이다.
해결책
결론적으로 이야기 하면 이렇게 같은 Activity 내에서 같은 layout xml을 이용해서 viewpager 를 계속해서 새로 만드는 상황이라면 getItemId() 를 override 해줄 필요가 있다.container.getId() 는 같은 xml 을 이용하니 viewpager 를 생성한다 해도 같은 id 값을 갖게 된다. 그러므로 우리는 getItemId() 를 viewpager 가 새로 생성될 때마다 다른 값을 return 할 수 있도록 해줘야 한다.
그렇게 하지 않으면, 과거의 viewpager 가 가지고 있던 fragment 를 찾아서(mFragmentManager.findFragmentByTag) 이용하려고 하기 때문이다.
아마 이 부분을 확실하게 null 을 return 하게 할 수 있다면 굳이 getItemId() 를 override 할 필요는 없다.
<android.support.design.widget.CoordinatorLayout
... >
<android.support.design.widget.AppBarLayout
...>
<android.support.v7.widget.Toolbar
.../>
<android.support.design.widget.TabLayout
... />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp_main_tabs"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
... />
</android.support.design.widget.CoordinatorLayout>
댓글 없음:
댓글 쓰기