6

세로 모드에서 내 ViewPager에는 A, B, C 세 조각이 있지만 가로 모드에서는 조각 A와 C가 두 개뿐입니다. 따라서 각 모드에 대해 2 FragmentStatePagerAdapter을 만듭니다. 문제는 화면 방향이 변경되었을 때입니다. ViewPager은 이전 방향의 이전 조각을 복원하고 사용합니다. 예를 들어 세로에서 가로로 방향을 변경하면 ViewPager은 A와 C 대신 2 개의 조각 A, B를 표시합니다. 왜 이런 일이 발생하는지 알고 있지만 이에 대한 좋은 해결책을 찾을 수 없습니다.세로 및 가로 방향에 대해 서로 다른 어댑터가있는 ViewPager

내 현재 해결 방법은 ViewPager (예 : portrait의 경우 id/viewpager_portrait, 가로 레이아웃의 경우/viewpager_portrait)에 다른 ID를 사용하여 조각을 재사용하지 못하게하지만 이전 조각이 삭제되지 않으므로 메모리 누수가 발생합니다. 여전히 기억에 남을 것입니다.

액티비티의 onCreate에서 super.onCreate (null)을 호출하거나 액티비티 onSaveInstanceState에서 ViewPager 조각을 제거하는 등의 임시 해결책을 시도했지만 모두 내 애플리케이션을 중단시킵니다.

오리엔테이션을 변경했을 때 FragmentStatePagerAdapter에 하나 이상의 조각을 재사용하지 않으려면 어떻게해야합니까?

도움을 주시면 감사하겠습니다. 미리 감사드립니다.

+0

'onSaveInstanceState'를 무시하고 해당 메소드에서'super.onSaveInstanceState'를 호출하지 않았습니까? 이렇게하면'Fragment'가 저장되지 않습니다. –

+0

그것이 현재의 해결 방법이지만 super.onSaveInstanceState를 호출하지 말고 ViewPager가 만든 모든 상태를 지 웁니다. ViewPager 내부에서 충돌이 발생하기 때문에 이것이 최선의 해결책이라고 생각하지 않습니다. – Wayne

답변

3

문제는 아마도 그 내장 된 안드로이드에서 제공 Fragment들에 대한 PagerAdapter 구현 항목이 일정하게 유지, 그래서 유지하고 ViewPager에 추가되는 모든 Fragment s의 인덱스 기반 참조를 다시 사용한다고 가정합니다. 이러한 참조는 Activity (및 Fragment)이 구성 변경 또는 프로세스가 종료되어 다시 작성된 후에도 FragmentManager을 통해 유지 관리됩니다. 당신이해야 할 일은

가있는 Fragment의 각 Fragment와 사용자 정의 태그를 연결하고 저장 PagerAdapter 당신 자신의 구현을 작성하는 것입니다 태그 기반 형식 (대신 인덱스 기반의). getItem() 메소드와 함께 색인을 기반으로 태그를 제공하기위한 추상 메소드를 추가 한 후 기존 메소드 중 하나에서이를 일반 구현으로 파생시킬 수 있습니다. 물론 이전 구성에서 추가 된 고아/미사용 FragmentViewPager에서 제거해야합니다 (이상적으로 상태를 유지하는 동안).

전체 솔루션을 직접 구현하지 않으려면 CWAC-Pager 라이브러리에있는 ArrayPagerAdapter을 사용하여 약간의 노력으로 합리적인 방법으로 구현할 수 있습니다. 초기화시 해당 제공된 태그를 기반으로 관련 Fragment을 분리하고 적절하게 제거/추가 할 수 있습니다.

+0

내 자신의 어댑터가 문제를 해결할 것이라는 것을 알고 있지만, StackOverflow에서 묻는 것보다 더 쉽고 간편한 솔루션이 있다고 생각합니다. – Wayne

+0

@Wayne : 답변 끝나고 [CWAC-Pager] (https://github.com/commonsguy/cwac-pager) 라이브러리 사용에 대한 추가 정보를 추가했습니다. – corsair992

+0

corsair992 주셔서 감사합니다. 제 해결책은 PagerAdapter 소스를 복사하고 답변에 약간의 코드 기반을 변경하는 것입니다. 죄송합니다. 지난 주말 온라인에 없었기 때문에 전액을 선물로주는 것을 잊었습니다/ – Wayne

1

어댑터에서 getItemPosition()을 덮어 쓰고 POSITION_NONE을 반환하십시오. 따라서 ViewPager를 다시 만들면 getItemPosition()이 호출되고 여기에서 POSITION_NONE을 반환 했으므로 getItem()이 호출됩니다. 이 getItem()에서 새 조각을 반환해야합니다. Ref : http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getItemPosition%28java.lang.Object%29

+0

아, getItemPosition()을 잊어 버렸습니다. 아마 이것은 좋은 해결책이 될 것입니다. 감사합니다 – Wayne

+1

이 답변은 정확하지 않습니다. 'ViewPager'는'PagerAdapter'에서'notifyDataSetChanged()'를 호출 할 때만 항목 위치의 변화를 찾습니다. 그리고 아이템이 불변이라고 가정하기 때문에'FragmentStatePagerAdapter'에서 아이템을 제거하는데 적절하게 작동하지 않을 것입니다. 그것은 국가 협회를 구해 냈다. 'FragmentPagerAdapter'에 대해서도 똑같은 것을 가정하고 있지 않기 때문에 원래의'Fragment'를 재사용 할 것입니다. – corsair992

1

왜 방향을 바꿀 때 단편 B를 제거 할 수있을 때, 뷰 페이지에 두 개의 다른 ID를 사용합니까?

이 같은 onCreateView() 또는 onResume() 안에 당신의 조각 (이 예는 부모 조각 내부에 작동하지만 (onResume에서 같은 부모 활동 안에 또한 사용 가능하다)) 검색 할 수 있습니다

@Override 
public void onResume() { 
    super.onResume(); 

    // ... initialize components, etc. 

    pager.setAdapter(pagerAdapter); 

    List<Fragment> children = getChildFragmentManager().getFragments(); 

    if (children != null) { 
     pagerAdapter.restoreFragments(children, orientation); 
    } 
} 

을 그런 다음 어댑터 내부 :

@Override 
public void restoreFragments(List<Fragment> fragments, int orientation) { 
    List<Fragment> fragmentsToAdd = new ArrayList<Fragment>(); 
    Collections.fill(fragmentsToAdd, null); 
    if (Configuration.ORIENTATION_LANDSCAPE == orientation) { 
     for (Fragment f : fragments) { 
      if (!(f instanceof FragmentB)) { 
       fragmentsToAdd.add(f); 
      } 
     } 
    } 
    this.fragmentsInAdapter = Arrays.copyOf(temp.toArray(new Fragment[0]), this.fragments.length); // array of all your fragments in your adapter (always refresh them, when config changes, else you have old references in your array! 
    notifyDataSetChanged(); // notify, to remove FragmentB 
} 

그래야합니다.

btw. 지원 라이브러리 V13을 사용하는 경우 FragmentManager.getFragments()를 사용할 수 없으므로 ID 또는 태그로 가져와야합니다.

1

활동의 OnConfigurationChanged()를 재정의하십시오 (또한 Manifest의 활동에 android : configChanges = "orientation"을 추가하십시오). 이렇게하면 방향 변경을 수동으로 관리 할 수 ​​있습니다. 이제 "모두"해야 할 일은 OnOrientaionChanged에서 어댑터를 변경하는 것입니다 (또한 현재 위치 추적). 이렇게하면 단일 레이아웃, 단일 ViewPager를 사용할 수 있으며 조각을 재활용하지 않는 것에 대해 걱정할 필요가 없습니다. 물론 잘 처리 할 수 ​​있습니다. 행운을 빈다!

관련 문제