FragmentPagerAdapter를 사용할 때 기존 조각을 가져 오는 방법


99

나는 탭 관리를 구현하는 도우미 클래스 와 관련된 모든 세부 정보를 Activity사용하는을 통해 서로 통신하는 내 조각을 만드는 데 문제 가 있습니다 . Android 샘플 프로젝트 Support4Demos 에서 제공하는 것과 똑같이 구현 했습니다 .FragmentPagerAdapterViewPagerTabHostFragmentPagerAdapter

주요 질문은 FragmentManagerId 나 Tag가없는 경우 어떻게 특정 조각을 얻을 수 있습니까? FragmentPagerAdapter조각을 만들고 ID와 태그를 자동으로 생성합니다.



@ jk2K 어떻게 이것이 1 년 후 질문 한 질문의 중복 일 수 있습니다
Davi

시간 관련이없는 레이블처럼 중복 @Dawit, 나중에 질문이 더 전망이
jk2K

여기에있는 대부분의 답변은 프로덕션에서 작동하지 않으므로 stackoverflow.com/a/54280113/2413303
EpicPandaForce

답변:


194

문제 요약

참고 :이 답변에서는 FragmentPagerAdapter소스 코드 를 참조하겠습니다 . 그러나 일반적인 솔루션은 FragmentStatePagerAdapter.

당신이 당신이 아마 이미 알고 읽는 경우 FragmentPagerAdapter/ FragmentStatePagerAdapter생성하기위한 것입니다 Fragments당신을 위해 ViewPager,하지만 활동 휴양에 따라 이러한 (앱이 메모리를 회복 죽이는 장치 회전 또는 시스템에서 여부를) Fragments다시 생성되지 않습니다, 대신 자신을 에서 검색된 인스턴스FragmentManager . 이제 작업을 수행 Activity하기 위해 이들 Fragments에 대한 참조가 필요 하다고 말하십시오 . 내부적으로 설정 했기 때문에 id또는 tagfor이 생성 되지 않았습니다 . 그래서 문제는 어떻게 그 정보없이 그들에 대한 참조를 얻는 것입니다 ...FragmentsFragmentPagerAdapter

현재 솔루션의 문제점 : 내부 코드에 의존

이 질문과 유사한 질문에 대해 본 많은 솔루션 은 내부적으로 생성 된 태그를Fragment 호출 FragmentManager.findFragmentByTag()하고 모방하여 기존 에 대한 참조를 얻는 데 의존합니다 .. 이것의 문제는 당신이 내부 소스 코드에 의존하고 있다는 것입니다. 우리 모두가 알고 있듯이 영원히 동일하게 유지된다는 보장은 없습니다. Google의 Android 엔지니어 는 기존 .NET에 대한 참조를 찾을 수 없도록 코드를 손상 시키는 구조를 쉽게 변경할 수 있습니다 ."android:switcher:" + viewId + ":" + idtagFragments

내부에 의존하지 않는 대체 솔루션 tag

다음 은에 대한 내부 집합에 의존하지 않는 에서 Fragments반환 된에 대한 참조를 가져 오는 방법에 대한 간단한 예입니다 . 핵심은 에서 대신 참조 를 재정의 하고 저장하는 입니다 .FragmentPagerAdaptertagsFragmentsinstantiateItem()getItem()

public class SomeActivity extends Activity {
    private FragmentA m1stFragment;
    private FragmentB m2ndFragment;

    // other code in your Activity...

    private class CustomPagerAdapter extends FragmentPagerAdapter {
        // other code in your custom FragmentPagerAdapter...

        public CustomPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // Do NOT try to save references to the Fragments in getItem(),
            // because getItem() is not always called. If the Fragment
            // was already created then it will be retrieved from the FragmentManger
            // and not here (i.e. getItem() won't be called again).
            switch (position) {
                case 0:
                    return new FragmentA();
                case 1:
                    return new FragmentB();
                default:
                    // This should never happen. Always account for each position above
                    return null;
            }
        }

        // Here we can finally safely save a reference to the created
        // Fragment, no matter where it came from (either getItem() or
        // FragmentManger). Simply save the returned Fragment from
        // super.instantiateItem() into an appropriate reference depending
        // on the ViewPager position.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            // save the appropriate reference depending on position
            switch (position) {
                case 0:
                    m1stFragment = (FragmentA) createdFragment;
                    break;
                case 1:
                    m2ndFragment = (FragmentB) createdFragment;
                    break;
            }
            return createdFragment;
        }
    }

    public void someMethod() {
        // do work on the referenced Fragments, but first check if they
        // even exist yet, otherwise you'll get an NPE.

        if (m1stFragment != null) {
            // m1stFragment.doWork();
        }

        if (m2ndFragment != null) {
            // m2ndFragment.doSomeWorkToo();
        }
    }
}

또는 당신이 작업하는 것을 선호하는 경우 tags클래스 멤버 변수 대신 /를 참조 Fragments당신은 또한 잡을 수 tags에 의해 세트를 FragmentPagerAdapter같은 방식으로 참고 :이 적용되지 않습니다 FragmentStatePagerAdapter설정되지 않기 때문에 tags그것을 만들 때 Fragments.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
    // get the tags set by FragmentPagerAdapter
    switch (position) {
        case 0:
            String firstTag = createdFragment.getTag();
            break;
        case 1:
            String secondTag = createdFragment.getTag();
            break;
    }
    // ... save the tags somewhere so you can reference them later
    return createdFragment;
}

이 메서드는 내부 tag설정 을 모방하는 데 의존하지 FragmentPagerAdapter않고 대신 적절한 API를 사용하여 검색합니다. 이렇게하면 tag향후 버전의 변경 사항 SupportLibrary이 여전히 안전 할 것입니다.


잊지 마십시오 당신의 디자인에 따라 것을 ActivityFragments당신이 일에 작업을 시도하고 또는 당신이 그렇게함으로써 그것을 위해 계정에 아직 존재하지 않을 수 있습니다 null귀하의 참조를 사용하기 전에 검사를.

또한 대신 을 사용하는 경우FragmentStatePagerAdapter 하드 참조 Fragments가 많을 수 있고 하드 참조가 불필요하게 메모리에 유지 될 수 있으므로 하드 참조를 유지하고 싶지 않습니다 . 대신 표준 Fragment참조 WeakReference대신 변수에 참조를 저장하십시오 . 이렇게 :

WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
    // reference hasn't been cleared yet; do work...
}

3
이것은 정말 좋은 솔루션입니다,하지만 당신이 전달됩니다 얼마나 많은 조각 모르는 경우는 그 효과를 잃을 것으로 보인다.
폭동 으릉 간다

3
@Zorpix는 HashMap에 생성 조각을 저장할 수 있습니다. map.put (position, createdFragment);
Tom Bevelander

12
이것은 체크 표시가 필요합니다! 이를 수행하는 매우 영리하고 포괄적 인 방법입니다. 많이 도와 주셔서 감사합니다!
young_souvlaki

2
처음에는이 솔루션이 너무 복잡해 보였기 때문에 건너 뛰었습니다. 하지만 다른 답변이 만족스럽지 않았기 때문에 마침내 다시 돌아 왔습니다. 그리고 생각만큼 어렵지 않았습니다.
Suragch

1
아무것도 재정의 할 필요가 없으며 실제로 재정의 해서는 안됩니다instantiateItem . 이를 수행하는 적절한 방법은 및로 둘러싸인 활동의 메소드 를 호출 instantiateItem 하는 onCreate것입니다 . 자세한 내용은 내 대답을 참조하십시오startUpdatefinishUpdate
morgwai

82

다음 게시물을 기반으로 내 질문에 대한 답변을 찾았습니다. fragmentpageradapter에서 조각 재사용

내가 배운 몇 가지 :

  1. getItem(int position)에서 FragmentPagerAdapter이 방법이 실제로 무엇을하는지 오히려 오해의 소지가 이름입니다. 기존 조각을 반환하지 않고 새 조각을 만듭니다. 따라서 메서드의 이름을 createItem(int position)Android SDK 와 같은 이름으로 변경해야합니다 . 따라서이 방법은 조각을 얻는 데 도움이되지 않습니다.
  2. 포스트 지원 FragmentPagerAdapterholds의 설명에 따라 이전 조각에 대한 참조를 유지 해야 FragmentPagerAdapter합니다. 따라서 조각 또는 해당 태그에 대한 참조가 없음을 의미합니다. 조각 태그가있는 경우를 FragmentManager호출 하여에서 쉽게 참조를 검색 할 수 있습니다 findFragmentByTag(). 주어진 페이지 위치에서 조각의 태그를 찾는 방법이 필요합니다.

해결책

클래스에 다음 도우미 메서드를 추가하여 조각 태그를 검색하고 findFragmentByTag()메서드로 보냅니다 .

private String getFragmentTag(int viewPagerId, int fragmentPosition)
{
     return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}

노트! 이것은 FragmentPagerAdapter새 조각을 만들 때 사용 하는 것과 동일한 방법입니다 . http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104 링크를 참조하십시오 .


Btw,이 Q & A에 주제에 대한 자세한 내용이 있습니다 : stackoverflow.com/questions/6976027/…
Thomas

1
viewId 입력 매개 변수는 무엇입니까? 어떤 견해?
Nilzor 2014

@Nilzor viewId는 ViewPager의 ID입니다.
Dr.jacky

아마도 태그를 추측하는 대신 조각이 태그를 활동에 대해 말할 수 onAttach()있습니까?
basin

4
이것은 올바른 방법이 아닙니다. @Tony Chan의 대답은 가장 좋고 올바른 방법입니다.
Morteza Rastgoo

16

조각 태그를 수동으로 생성 instantiateItem하여 내부 makeFragmentName메서드 와의 호환성 을 재정의 하거나 의존 할 필요가 없습니다 .
instantiateItemA는 공공 방법 당신이 할 수있는 그래서 실제로 해야 에 전화를 onCreate활동의 방법은 호출에 둘러싸여 startUpdatefinishUpdate에 설명 된 방법 PagerAdapter 의 javadoc :

PagerAdapter 메서드 startUpdate (ViewGroup)에 대한 호출은 ViewPager의 내용이 곧 변경됨을 나타냅니다. instantiateItem (ViewGroup, int) 및 / 또는 destroyItem (ViewGroup, int, Object)에 대한 하나 이상의 호출이 이어지며 업데이트의 끝은 finishUpdate (ViewGroup) 호출에 의해 신호를받습니다.

그런 다음 위의 방법으로 필요한 경우 조각의 인스턴스에 대한 참조를 로컬 변수에 저장할 수 있습니다. 예보기 :

public class MyActivity extends AppCompatActivity {

    Fragment0 tab0; Fragment1 tab1;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);
        ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);

        adapter.startUpdate(viewPager);
        tab0 = (Fragment0) adapter.instantiateItem(viewPager, 0);
        tab1 = (Fragment1) adapter.instantiateItem(viewPager, 1);
        adapter.finishUpdate(viewPager);
    }

    class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager manager) {super(manager);}

        @Override public int getCount() {return 2;}

        @Override public Fragment getItem(int position) {
            if (position == 0) return new Fragment0();
            if (position == 1) return new Fragment1();
            return null;  // or throw some exception
        }

        @Override public CharSequence getPageTitle(int position) {
            if (position == 0) return getString(R.string.tab0);
            if (position == 1) return getString(R.string.tab1);
            return null;  // or throw some exception
        }
    }
}

instantiateItem먼저에서 기존 조각 인스턴스에 대한 참조를 가져 오려고합니다 FragmentManager. 아직 존재하지 않는 경우에만 getItem어댑터의 방법을 사용하여 새 항목을 만들고 FragmentManager나중에 사용할 수 있도록에 "저장"합니다 .

조각에 대한 참조를 얻을 필요가 없더라도 다음 과 같이 메서드 에서 / 로 instantiateItem둘러싸인 모든 탭을 호출해야한다는 점에 유의해야 합니다.startUpdatefinishUpdateonCreate

    adapter.startUpdate(viewPager);
    // ignoring return values of the below 2 calls, just side effects matter:
    adapter.instantiateItem(viewPager, 0);
    adapter.instantiateItem(viewPager, 1);
    adapter.finishUpdate(viewPager);

그렇게하지 않으면, 당신은 당신의 조각 인스턴스는 않을 것이라는 점을 걸고 최선을 다하고 없습니다FragmentManager활동 전경이 될 때 : instantiateItem당신의 조각을 얻기 위해 자동으로 호출되지만, startUpdate/ finishUpdate 없습니다 (구현 세부 사항에 따라) 기본적으로 그들이 무엇을 해야 할 일은 시작 / 커밋입니다 FragmentTransaction.
및 필요한 것보다 훨씬 더 자주 재 (당신이 당신의 화면을 회전 할 때, 예를 들어) 매우 신속하게 손실되는 생성 된 단편 인스턴스에 대한 참조 초래한다. 프래그먼트가 얼마나 무거운 지에 따라 무시할 수없는 성능 결과가있을 수 있습니다.
또한 이러한 경우 로컬 변수에 저장된 조각의 인스턴스 부실해집니다 : FragmentManager어떤 이유로 든 안드로이드 플랫폼이 그것들을 얻으려고 하면 실패 할 것이고 따라서 새로운 것을 만들고 사용하게 될 것입니다.하지만 여러분의 vars는 여전히 오래된 것을 참조 할 것입니다.


1
어떤 경우에는 최상의 솔루션이 될 수 있습니다. 하지만 FragmentManger가 조각을 죽이고 다시 기록하면 어떻게 될까요?
woltran

1
@woltran FragmentManager은 무작위로 죽일 수 없습니다 ( 파괴 는 여기에서 올바른 단어입니다). Fragment( Fragment현재 표시되고 있는 a를 죽이기로 결정하면 어떻게 될지 생각 해보세요 ;)). 일반적으로 a의 수명주기는 Fragment그에 묶여 있습니다 Activity(자세한 내용은 github.com/xxv/android-lifecycle 참조)-> a Fragment는 파괴 된 경우에만 파괴 될 수 있습니다 Activity. 이 경우 사용자가 지정된 위치로 다시 이동하면 Activity해당 항목 onCreate이 다시 호출되고의 새 인스턴스 Fragment가 생성됩니다.
morgwai

이것이 REAL 답변입니다
MJ Studio 19

예를 들어 사용자가 ViewPager를 스크롤 할 때 생성되는 것에 의존하지 않고 실제로 조각을 만들어야합니까?
Yar

@Yar 예, 정말해야합니다. 내가 제공 한 문서 발췌 부분에 명확하게 설명되어 있으며 "몇 가지 추가 정보"섹션에서 그 이유를 설명합니다.
morgwai

11

내가 한 방식은 다음과 같이 WeakReferences의 Hashtable을 정의하는 것입니다.

protected Hashtable<Integer, WeakReference<Fragment>> fragmentReferences;

그런 다음 다음과 같이 getItem () 메서드를 작성했습니다.

@Override
public Fragment getItem(int position) {

    Fragment fragment;
    switch(position) {
    case 0:
        fragment = new MyFirstFragmentClass();
        break;

    default:
        fragment = new MyOtherFragmentClass();
        break;
    }

    fragmentReferences.put(position, new WeakReference<Fragment>(fragment));

    return fragment;
}

그런 다음 메서드를 작성할 수 있습니다.

public Fragment getFragment(int fragmentId) {
    WeakReference<Fragment> ref = fragmentReferences.get(fragmentId);
    return ref == null ? null : ref.get();
}

이것은 잘 작동하는 것 같고 나는 그것이

"android:switcher:" + viewId + ":" + position

FragmentPagerAdapter가 구현되는 방식에 의존하지 않기 때문입니다. 물론 FragmentPagerAdapter에 의해 조각이 해제되었거나 아직 생성되지 않은 경우 getFragment는 null을 반환합니다.

누구든지이 접근 방식에서 잘못된 점을 발견하면 의견을 환영합니다.


int fragmentId로 변경해야한다int position
lmaooooo

7
나는 매우 유사한 접근 방식을 사용하고있었습니다. 그러나 이는 savedState 번들에서 호출기가 생성 될 때 실패합니다. 예 : 활동이 백그라운드로 이동하고 onSavedStateInstance ()가 호출 된 후 포 그라운드로 돌아옵니다. 이 경우 getItem () 메서드가 호출되지 않습니다.
Anoop 2015 년

FragmentManager에 이미 항상 up2date 인 맵이 있기 때문에 자신 만의 맵을 만드는 이유는 무엇입니까? 자세한 내용은 내 대답을 참조하십시오.
morgwai

또한 조각이 파괴되었다는 사실이 해당 조각에 대한 강력한 참조가 없다는 것을 보장하지는 않습니다 (그럴 가능성이 있지만 보장 되지는 않음 ).이 경우 맵에 여전히 오래된 조각이 포함됩니다.
morgwai

1
시스템이 조각을 다시 만든 후에는 제대로 작동하지 않습니다.
EpicPandaForce

10

나는 현재 조각에 대한 참조를 얻기 위해 작동하는이 방법을 만들었습니다.

public static Fragment getCurrentFragment(ViewPager pager, FragmentPagerAdapter adapter) {
    try {
        Method m = adapter.getClass().getSuperclass().getDeclaredMethod("makeFragmentName", int.class, long.class);
        Field f = adapter.getClass().getSuperclass().getDeclaredField("mFragmentManager");
        f.setAccessible(true);
        FragmentManager fm = (FragmentManager) f.get(adapter);
        m.setAccessible(true);
        String tag = null;
        tag = (String) m.invoke(null, pager.getId(), (long) pager.getCurrentItem());
        return fm.findFragmentByTag(tag);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } 
    return null;
}

니스는 성능 향상을 위해 방법 이외의 방법 및 필드를 만드는 기억
마르코스 바스 콘셀 로스

2

@ personne3000가 제시 한 해결책은 좋은,하지만 한 가지 문제가 있습니다 활동이 배경으로 이동하고는, 복원 후 (일부 무료로 메모리를 얻기 위해) 시스템에 의해 살해됩니다 때 fragmentReferences비어있을 것입니다 때문에 getItem되지 않을 것 전화.

아래 클래스는 이러한 상황을 처리합니다.

public abstract class AbstractHolderFragmentPagerAdapter<F extends Fragment> extends FragmentPagerAdapter {

    public static final String FRAGMENT_SAVE_PREFIX = "holder";
    private final FragmentManager fragmentManager; // we need to store fragment manager ourselves, because parent's field is private and has no getters.

    public AbstractHolderFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
        fragmentManager = fm;
    }

    private SparseArray<WeakReference<F>> holder = new SparseArray<WeakReference<F>>();

    protected void holdFragment(F fragment) {
        holdFragment(holder.size(), fragment);
    }

    protected void holdFragment(int position, F fragment) {
        if (fragment != null)
            holder.put(position, new WeakReference<F>(fragment));
    }

    public F getHoldedItem(int position) {
        WeakReference<F> ref = holder.get(position);
        return ref == null ? null : ref.get();
    }

    public int getHolderCount() {
        return holder.size();
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) { // code inspired by Google's FragmentStatePagerAdapter implementation
        super.restoreState(state, loader);
        Bundle bundle = (Bundle) state;
        for (String key : bundle.keySet()) {
            if (key.startsWith(FRAGMENT_SAVE_PREFIX)) {
                int index = Integer.parseInt(key.substring(FRAGMENT_SAVE_PREFIX.length()));
                Fragment f = fragmentManager.getFragment(bundle, key);
                holdFragment(index, (F) f);
            }
        }
    }

    @Override
    public Parcelable saveState() {
        Bundle state = (Bundle) super.saveState();
        if (state == null)
            state = new Bundle();

        for (int i = 0; i < holder.size(); i++) {
            int id = holder.keyAt(i);
            final F f = getHoldedItem(i);
            String key = FRAGMENT_SAVE_PREFIX + id;
            fragmentManager.putFragment(state, key, f);
        }
        return state;
    }
}

1

조각에 대한 핸들을 얻는 주요 도로 블록은 getItem ()에 의존 할 수 없다는 것입니다. 방향 변경 후 조각에 대한 참조는 null이되고 getItem ()이 다시 호출되지 않습니다.

다음은 태그를 가져 오기 위해 FragmentPagerAdapter의 구현에 의존하지 않는 접근 방식입니다. getItem ()에서 생성되었거나 조각 관리자에서 찾은 조각을 반환하는 instantiateItem ()을 재정의하십시오.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object value =  super.instantiateItem(container, position);

    if (position == 0) {
        someFragment = (SomeFragment) value;
    } else if (position == 1) {
        anotherFragment = (AnotherFragment) value;
    }

    return value;
}

0

FragmentPagerAdapter에서 조각을 반환하는 방법 은 이 게시물 을 참조하십시오 . 조각의 인덱스를 아는 것에 의존하지만 이것은 getItem ()에서 설정됩니다 (인스턴스화에서만)


0

태그 대신 ID를 사용하여이 문제를 해결했습니다. (나는 내 ​​사용자 정의 Fragment를 사용하는 FragmentStatePagerAdapter를 사용하고 있으며 여기에서 onAttach 메서드를 재정 의하여 ID를 어딘가에 저장합니다.

@Override
public void onAttach(Context context){
    super.onAttach(context);
    MainActivity.fragId = getId();
}

그런 다음 활동 내에서 쉽게 조각에 액세스 할 수 있습니다.

Fragment f = getSupportFragmentManager.findFragmentById(fragId);

0

이것이 최선의 방법인지는 모르겠지만 다른 것은 나를 위해 일하지 않았습니다. getActiveFragment를 포함한 다른 모든 옵션이 null을 반환했거나 앱이 중단되었습니다.

화면 회전에서 조각이 연결되어 있다는 것을 알았으므로 조각을 활동으로 다시 보내는 데 사용했습니다.

단편에서 :

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnListInteractionListener) activity;
        mListener.setListFrag(this);
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

그런 다음 활동에서 :

@Override
public void setListFrag(MyListFragment lf) {
    if (mListFragment == null) {
        mListFragment = lf;
    }
}

마지막으로 onCreate () 활동에서 :

if (savedInstanceState != null) {
    if (mListFragment != null)
        mListFragment.setListItems(items);
}

이 접근 방식은 새 조각을 만들지 않고 실제 보이는 조각을 활동에 연결합니다.


0

내가 자바 / 안드로이드의 상대적인 초보자이기 때문에 내 방법이 올바른지 또는 최선의 방법인지 확실하지 않지만 작동했습니다 (객체 지향 원칙을 위반하지만 다른 솔루션은 내 사용 사례에 적합하지 않습니다).

FragmentStatePagerAdapter와 함께 ViewPager를 사용하는 호스팅 활동이 있습니다. FragmentStatePagerAdapter에 의해 생성 된 Fragments에 대한 참조를 얻기 위해 FragmentStatePagerAdapter에서 콜백 인터페이스를 생성했습니다.

public interface Callbacks {
    public void addFragment (Fragment fragment);
    public void removeFragment (Fragment fragment);
}

호스팅 활동에서 인터페이스를 구현하고 조각을 추적하기 위해 LinkedHasSet을 만들었습니다.

public class HostingActivity extends AppCompatActivity implements ViewPagerFragment.Callbacks {

    private LinkedHashSet<Fragment> mFragments = new LinkedHashSet<>();

    @Override
    public void addFragment (Fragment fragment) {
        mFragments.add(fragment);
    }

    @Override
    public void removeFragment (Fragment fragment) {
        mFragments.remove(fragment);
    }
}

ViewPagerFragment 클래스 내에서 onAttach 내의 목록에 조각을 추가하고 onDetach에서 제거했습니다.

public class ViewPagerFragment extends Fragment {

    private Callbacks mCallbacks;

    public interface Callbacks {
        public void addFragment (Fragment fragment);
        public void removeFragment (Fragment fragment);
    } 

    @Override
    public void onAttach (Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
        // Add this fragment to the HashSet in the hosting activity
        mCallbacks.addFragment(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // Remove this fragment from the HashSet in the hosting activity
        mCallbacks.removeFragment(this);
        mCallbacks = null;
    }
}

이제 호스팅 활동 내에서 mFragments를 사용하여 현재 FragmentStatePagerAdapter에 존재하는 조각을 반복 할 수 있습니다.


0

이 클래스는 내부 태그에 의존하지 않고 트릭을 수행합니다. 경고 : 조각은 getItem 메서드가 아닌 getFragment 메서드를 사용하여 액세스해야합니다.

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private final Map<Integer, Reference<Fragment>> fragments = new HashMap<>();
    private final List<Callable0<Fragment>> initializers = new ArrayList<>();
    private final List<String> titles = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    void addFragment(Callable0<Fragment> initializer, String title) {
        initializers.add(initializer);
        titles.add(title);
    }

    public Optional<Fragment> getFragment(int position) {
        return Optional.ofNullable(fragments.get(position).get());
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment =  initializers.get(position).execute();
        return fragment;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.put(position, new WeakReference<>(fragment));
        return fragment;
    }

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

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

-5

이 코드를 시도하십시오.

public class MYFragmentPAdp extends FragmentPagerAdapter {

    public MYFragmentPAdp(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return 2;
    }

     @Override
     public Fragment getItem(int position) {
         if (position == 0)
             Fragment fragment = new Fragment1();
         else (position == 1)
             Fragment fragment = new Fragment2();
         return fragment;
     }
}

Najib, 아래 내 대답에서 설명한 것처럼 getItem ()은 주어진 이름 getcreate를 기대할 수 있으므로 기존 조각을 반환하는 대신 새 조각을 생성 합니다. 같은 게시물에서 내 솔루션을 참조하십시오.
Ismar Slomic 2012

조각 조각 = new YourCustomFragmentClass (); 여기에 쓰십시오.
Najib Ahmed Puthawala 2012

나는 아직도 당신이 대신에 새로운 조각을 생성한다는 사실 방법이 변경 내용을 이해 해달라고 점점 .. 하나의 기존
Ismar Slomic

Fragment fragment = new YourFragment ();와 같이 여전히 사용자 지정 조각에 대해서만 초기화하고 반환합니다. 반환 조각;
Najib Ahmed Puthawala
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.