Android получает фрагмент, который находится в FragmentPagerAdapter

У меня следующая проблема: у меня есть одно действие, в котором у меня есть две вкладки, которые сделаны как фрагменты с использованием FragmentPagerAdapter. В какой-то момент я хотел бы изменить представление одного из этих фрагментов, но я не могу на findFragmentById() или findFragmentByTag(). Я не могу установить идентификатор, потому что я не объявляю Fragment в XML из-за FragmentPagerAdapter. когда я пытаюсь установить тег, я получаю следующую проблему:

08-15 21:46:23.805: E/AndroidRuntime(9297): java.lang.IllegalStateException: Can't  change tag of fragment Companies{416d7b78 id=0x7f04002e companies}: was companies now android:switcher:2130968622:1

Мой код пейджера FragmentPagerAdapter:

public class TabsAdapter extends FragmentPagerAdapter implements    ActionBar.TabListener, ViewPager.OnPageChangeListener {
    private final FragmentActivity mContext;
    private final ActionBar mActionBar;
    private final ViewPager mViewPager;
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();


    final class TabInfo {
        private final Class<?> clss;
        private final Bundle args;

        TabInfo(Class<?> _class, Bundle _args) {
            clss = _class;
            args = _args;
        }
    }

    public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
        super(activity.getSupportFragmentManager());
        mContext = activity;
        mActionBar = activity.getSupportActionBar();
        mViewPager = pager;
        mViewPager.setAdapter(this);
        mViewPager.setOnPageChangeListener(this);
    }

    public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
        TabInfo info = new TabInfo(clss, args);
        tab.setTag(info);
        tab.setTabListener(this);
        mTabs.add(info);
        mActionBar.addTab(tab);
        notifyDataSetChanged();
    }

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

    @Override
    public Fragment getItem(int position) {
        TabInfo info = mTabs.get(position);
        FragmentTransaction ft=mContext.getSupportFragmentManager().beginTransaction();
        Fragment fragment=Fragment.instantiate(mContext, info.clss.getName(), info.args);

        if(position==1){
            ft.add(mViewPager.getId(), fragment, "companies");
        }else{
            ft.add(mViewPager.getId(), fragment);
        }
        Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
        ft.commit();
        Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
        return fragment;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
        mActionBar.setSelectedNavigationItem(position);
        new Thread(new Runnable() {

            @Override
            public void run() {
                MainActivity.this.hideKeyboard();

            }
        }).start();

    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        Object tag = tab.getTag();
        for (int i = 0; i < mTabs.size(); i++) {
            if (mTabs.get(i) == tag) {
                mViewPager.setCurrentItem(i);                   
            }
        }


    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {


    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }
}

Заранее спасибо за ваши ответы.


person ziky90    schedule 15.08.2012    source источник


Ответы (5)


Фрагменты, предоставляемые FragmentPagerAdapter, автоматически помечаются при создании экземпляра. Вы можете получить тег с помощью этого метода:

private static String makeFragmentName(int viewPagerId, int index) {
     return "android:switcher:" + viewPagerId + ":" + index;
}

Справочник: повторное использование фрагментов в адаптере fragmentpageradapter

person DeeV    schedule 15.08.2012
comment
Примечание для таких людей, как я: viewId — это идентификатор ViewPager. - person htafoya; 08.11.2013
comment
Я думал, что метод помещен в класс, расширяющий FragmentPagerAdapter, но метод должен быть просто помещен в класс Fragment. - person Robert; 20.07.2015
comment
@Robert: Фрагменты не всегда используются в пейджерах, но FragmentPagerAdapter всегда используются с пейджерами. Не имеет смысла иметь его в Fragment. - person DeeV; 20.07.2015
comment
@DeeV Извините, моя вина, что это не фрагмент, это Activity. В моем случае это Activity с ViewPager внутри. И ViewPager содержит FragmentPagerAdapter из 2 фрагментов. Поэтому, чтобы повторно использовать фрагменты, я поместил метод в Activity - findFragmentByTag() в макете ViewPager. - person Robert; 21.07.2015
comment
Зачем это делать? Я имею в виду, если вы генерируете имя фрагмента из его позиции, просто получите его непосредственно по позиции. .getSupportFragmentManager().getFragments().get(position) или .getChildFragmentManager().getFragments().get(position) - person worked; 23.11.2015
comment
Это правильный путь: stackoverflow.com /вопросы/6976027/ - person Morteza Rastgoo; 27.12.2015

С помощью этой функции вы можете найти фрагмент по положению адаптера пейджера.

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Пример кода для поддержки API v4.

person Daniel De León    schedule 18.06.2013

Я нашел немного менее грубый способ получить дескриптор Fragment, созданного FragmentPagerAdapter. Вместо того, чтобы имитировать способ создания тегов, переопределите instantiateItem(), получите Fragment, возвращаемый суперклассом, и сохраните тег в TabInfo. Это работает для меня на API> = 15, может работать с более низким. Это по-прежнему делает некоторые предположения о приватном коде.

static final class TabInfo {
    private final Class<?> clss;
    private final Bundle args;
    private String tag; // ** add this

    TabInfo(Class<?> _class, Bundle _args) {
        clss = _class;
        args = _args;
    }
}


@Override
public Object instantiateItem(ViewGroup container, int position) {
    final Fragment fragment = (Fragment) super.instantiateItem(container, position);
    final TabInfo info = mTabs.get(position);
    info.tag = fragment.getTag(); // set it here
    return fragment;
}

Или в API ‹ 16, я думаю, instantiateItem() принимает View() вместо ViewGroup(), вот так:

public Object instantiateItem(View container, int position);

Затем дайте возможность получить Fragment, удерживая взлом.

public Fragment getFragment(int index) {
    return mContext.getFragmentManager().findFragmentByTag(mTabs.get(index).tag);
}

Чтобы это работало, объявление для mContext должно измениться на Activity, оно в любом случае передается как Activity:

private final Activity mContext;
person nash    schedule 24.09.2012
comment
пытаюсь применить это решение, но super.instantiateItem(container, position) выдает NPE для меня как FragmentPagerAdapter, так и FragmentStatePagerAdapter - person Sash0k; 23.01.2013

Более простой подход к этому — получить теги непосредственно из диспетчера фрагментов; так:

fm.getFragments().get(0).getTag()

Вы можете заменить позицию, в зависимости от фрагмента, для которого вам нужен тег. Надеюсь, это поможет другим!

person Chriss Villegas    schedule 10.07.2017

Очень поздно отвечать на этот вопрос, но я много искал, никто не сказал мне точного ответа. Может быть, кто-то нашел его полезным.

Я установил свои фрагменты через FragmentPagerAdapter и установил связь между фрагментами

https://developer.android.com/training/basics/fragments/communicating.html#Deliver

по этой ссылке и для FindFragmentById я просто использовал viewpager.getId() в основной активности.

person Suruchi Mahajan    schedule 25.06.2016