2

FragmentPagerAdapter 안에 ~ 20 개의 프래그먼트가 있습니다. 프래그먼트를 선택하는 목록이 포함되어 있으므로 조각을 다시 만들지 않습니다.FragmentPagerAdapter 안의 Android 변경 프래그먼트 순서

private List<TitledFragment> fragments; 

public SectionsPagerAdapter(FragmentManager fm) { 
    super(fm); 

    this.fragments = new ArrayList<TitledFragment>(); 
} 

@Override 
public Fragment getItem(int i) { 
    return fragments.get(i).getFragment(); 
} 

@Override 
public int getCount() { 
    return fragments.size(); 
} 

@Override 
public CharSequence getPageTitle(int position) { 
    return fragments.get(position).getTitle(); 
} 

public synchronized List<TitledFragment> getFragments() { 
    return fragments; 
} 


public synchronized void addFragment(TitledFragment fragment) { 
    fragments.add(fragment); 
    notifyDataSetChanged(); 
} 

FragmentPagerAdapter는 ViewPager의 어댑터로 설정하고 그 후에 I는 재정렬 된 단편 (셔플 바로 시험 하였다)

Collections.shuffle(mSectionsPagerAdapter.getFragments()); 
mSectionsPagerAdapter.notifyDataSetChanged(); 

어떤 이유 타이틀의 순서

이 경우에도 변경되는 순서대로 getItem에 대한 다른 부분을 반환합니다. 왜 이래서 어떻게 할 수 있습니까?

답변

8

또한 getItemPosition()을 덮어 써야합니다. 기본적으로이 함수는 항상 POSITION_UNCHANGED을 반환하므로 notifyDataSetChanged()을 호출 할 때 어댑터는 모든 조각이 여전히 동일한 위치에 있다고 가정합니다. (getItem()을 다시 호출하지 않습니다. 필요한 모든 조각이 이미 만들어져 있다고 생각하기 때문입니다.) 새 getItemPosition()은 셔플 후 각 조각의 새 위치를 반환해야합니다.

쉬운 해킹은 항상 POSITION_NONE을 반환하고 어댑터는 기존의 모든 조각을 버리고 getItem()을 호출 할 때 올바른 위치에 다시 만듭니다. 물론, 이것은 효율적이지 않으며, 보이는 현재 조각이 변경 될 수있는 추가적인 단점이 있습니다. 그러나 조각을 재정렬하는 데 몇 가지 버그가있을 수 있으므로 my question here을 참조하십시오. POSITION_NONE 접근 방법이 가장 안전한 방법 일 수 있습니다.

+0

나는 그것이 좋은 해결책임을 확인할 수 있습니다! 감사! –

0

허용되는 대답이 최적이 아닙니다. POSITION_NONEint getItemPosition(Object)에서 반환하면 모든 조각을 다시 인스턴스화해야하는 효율적인 조각 관리가 불가능할뿐입니다. 또한 다른 문제를 무시합니다. FragmentPageAdapter는 FragmentManager에 캐시 된 사본을 보관하고 새 Fragment를 인스턴스화 할 때 사본을 찾습니다. 일치하는 조각이라고 생각되는 내용을 찾으면 public Fragment getItem(int) 메서드가 호출되지 않고 캐시 된 복사본이 사용됩니다.

예를 들어 페이지 0과 1이로드되면 FragmentManager에 0과 1 태그가 지정된 캐시 조각이 표시됩니다. 이제 페이지가 인덱스 0에 삽입되고 (예 : notifyDataSetChanged()), 이전 인덱스 0은 1이되고 1은 2가됩니다 (이것은 public int FragmentPageAdapter.getItemPosition(Object) 메서드를 통해 알 수 있습니다). (이것은 새로운 위치이기 때문에) 항목에 대해 0 POSITION_NONE 반환, 그래서 방법 public Object instantiateItem(ViewGroup, int) 위치를 0이라고 :

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) { 
     if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); 
     mCurTransaction.attach(fragment); 
    } else { 
     fragment = getItem(position); 
     ... 

가 어떻게되는지, 캐시 조각의 위치는 0 발견하고, 조각은 당신이 원 위치 1이 이제 위치 0에 있고, 위치 2에서 원하는 조각이 이제 위치 1에 있고 위치 2에서 위치 1의 복제본 인 FragmentPageAdapter.getItem (int)에 의해 반환 된 새 조각을 얻습니다.

어떻게 해결할 수 있을까요? 내가 SO를 포함하여 많은 제안을 보았다 :

  1. 항상 FragmentPageAdapter.getItemPosition() https://stackoverflow.com/a/7386616/2351246에서 POSITION_NONE을 반환 -이 답변이 efficiciency 및 메모리 관리를 무시 (결국 캐시 조각을 지우지 않고 작동하지 않습니다) 추적
  2. 을 단편 태그 https://stackoverflow.com/a/12104399/2351246의 경우 구현 정보가 변경 될 수 있습니다.
  3. 그리고 가장 나쁜 것은 FragmentPageAdapter 구현 https://stackoverflow.com/a/13925130/2351246을 리버스 엔지니어링하여 마술을 사용하는 것입니다. 이것은 끔찍한 일입니다.

메모리 관리를 망치거나 FragmentPagerAdapter의 내부 구현 세부 사항을 추적 할 필요가 없습니다.

@Override 
    public long getItemId(int position) { 
     return System.identityHashCode(fragments.get(position)); 
    } 

이 올바른 조각을 조회하는 데 사용할 수있는 비 위치 기반 ID를 제공합니다 : 모든 해답에서 누락 된 세부 재주문 조각에 원하는 FragmentPagerAdapter는 방법 public long getItemId(int position)를 구현해야한다는 것입니다 페이지를 이동하더라도 FragmentManager 캐시.