Получить фрагмент по тегу

Я использую FragmentPagerAdapter для создания многостраничного пользовательского интерфейса с разными фрагментами. Что я хочу сделать, так это найти фрагмент, используя положение фрагмента.

Я применил метод поиска имен фрагментов и использую .FindFragmentbyTag(), но .FindFragmentbyTag всегда возвращает мне нулевое значение. Структура кажется правильной, поэтому я не уверен, почему я получаю нулевые значения, пожалуйста, просмотрите, и помощь приветствуется.

Вот код

MainActivity.java
public void onCreate(Bundle savedInstanceState) {
    this.getSupportFragmentManager();
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    MainActivity.instance=this;
    //Initialize pager
    vpPager = (ViewPager)findViewById(R.id.mypager);
    pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
    vpPager.setAdapter(pagerAdapter);
    this.mapFragment = (MapFragment)this.findFragmentByPosition(0);
    this.drFragment = (DRFragment)this.findFragmentByPosition(1);
    this.sensorFragment = (SensorFragment)this.findFragmentByPosition(2);
    ......
}

protected Fragment  findFragmentByPosition(int position) {
    int pagerid = this.vpPager.getId();
    long pagerAdapterid = this.pagerAdapter.getItemId(position);
    return getSupportFragmentManager().findFragmentByTag("android:switcher:" + pagerid + ":" + pagerAdapterid + "");
}

MyPagerAdapter.java
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.View;

public class MyPagerAdapter extends FragmentPagerAdapter {
    private static final String TAG = "TM_PageAdapter";
    private static int numItems = 3;

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

    public int getCount() {
        return numItems;
    }

    @Override
    public Fragment getItem(int position) {
        switch(position){
            case 0:
                return MapFragment.newInstance(0, "Map Information");
            case 1:
                return DRFragment.newInstance(1, "DR Information");
            case 2: 
                return SensorFragment.newInstance(2, "Sensor Information");
            default: 
                return null;
        }
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch(position){
            case 0:
                return "Map Information";
            case 1:
                return "DR Information";
            case 2: 
                return "Sensor Information";
            default:
                return null;
        }
    }

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


    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == ((View) arg1);

    }

    @Override
    public Parcelable saveState() {
        return null;
    }

Вот один из кодов .newInstance:

public static MapFragment newInstance(int position, String title){
    MapFragment mapFragment = new MapFragment();
    Bundle args = new Bundle();
    args.putInt("current_page", 0);
    args.putString("page_tile", "Map Information");
    mapFragment.setArguments(args);
    return mapFragment;
}

person Thomas Dang    schedule 17.07.2014    source источник
comment
Я нигде не вижу, чтобы вы вызывали makeFragmentName(...) . Можете ли вы предоставить какой-нибудь код, например, содержимое MapFragment.newInstance(...)?   -  person Daniel Zolnai    schedule 17.07.2014
comment
Я добавил часть кода для .newInstnce. Я впервые работаю с FragmentPagerAdapter, поэтому я в основном следую онлайн-учебнику. Я могу пропустить какую-то важную часть (я так подозреваю). Пожалуйста, покажите мне, где я скучаю, спасибо :)   -  person Thomas Dang    schedule 17.07.2014
comment
Из того, что я вижу, вы не вызываете makeFragmentName(), поэтому у фрагментов не будет никаких тегов. Это причина, по которой findFragmentByTag() не найдет их. Кроме того, вам не нужно добавлять viewId в тег. Просто индекса должно быть достаточно.   -  person Daniel Zolnai    schedule 17.07.2014
comment
Вот что я получил из другого сообщения: stackoverflow.com/questions/11976397/ Фрагменты, предоставленные FragmentPagerAdapter, автоматически помечаются при создании экземпляра. Вы можете получить тег с помощью этого метода: .... Так разве функция findFragmentbyPosition(position) в MainActivity не помогает? Я думаю, что применил оба ответа на этой странице и забыл удалить один   -  person Thomas Dang    schedule 17.07.2014
comment
@DanielZolnai и ThomasDang, кажется, проблема была в другом, давайте избавимся от всех этих бесполезных комментариев.   -  person HpTerm    schedule 17.07.2014


Ответы (3)


В findFragmentByPosition вы не используете индекс при поиске фрагмента:

getSupportFragmentManager().findFragmentByTag("android:switcher:" + pagerid + ":" + pagerAdapterid + "");

Второй должен быть индексом, а не pagerAdapterId. Таким образом, правильный код будет таким:

getSupportFragmentManager().findFragmentByTag("android:switcher:" + pagerid + ":" + position);

Также нет необходимости объединять последнюю пустую строку.

person Daniel Zolnai    schedule 17.07.2014
comment
Функция: long pagerAdapterid = this.pagerAdapter.getItemId(position); будет выдавать то же самое, что и позиция (я использовал режим отладки и выяснил), так что это не проблема. Я также дважды проверяю, изменяя код в соответствии с вашим ответом. все еще нулевой указатель @@. Но спасибо за помощь - person Thomas Dang; 17.07.2014
comment
Тогда вы просто добавляете лишний шаг :) Также возможно, что вашего фрагмента просто не существует, потому что он не виден и был уничтожен. Вы можете увеличить количество сохраняемых фрагментов с помощью ViewPager.setOffscreenPageLimit(int pages); - person Daniel Zolnai; 17.07.2014
comment
Однако я не уверен, как создается фрагмент, когда я пытаюсь поставить точку останова в getItem (позиция) в MyPagerAdapter, она не прошла после vpPager.setAdapter (pagerAdapter); Учебник, которому я следовал: github.com/thecodepath/android_guides/wiki/ И вроде бы я сделал то, что нужно @@. - person Thomas Dang; 17.07.2014
comment
Также возможно, что ViewPager еще не создал фрагменты, потому что вы ссылаетесь на них, как только устанавливаете адаптер. SensorFragment наверняка будет нулевым, потому что пейджер загружает первый фрагмент, а в фоновом режиме еще один. - person Daniel Zolnai; 17.07.2014
comment
Загрузит ли пейджер все имеющиеся у меня фрагменты, поскольку я ссылаюсь на все фрагменты. И есть ли способ для основного действия дождаться завершения загрузки страниц, а затем продолжить? Спасибо за вашу помощь :) - person Thomas Dang; 17.07.2014
comment
Вы не ссылаетесь на них, вы пытаетесь получить ссылку на них. Вы можете использовать ViewPager.OnPageChangeListener и запросить ссылку в onPageSelected(int position). - person Daniel Zolnai; 17.07.2014
comment
В моей программе всего 3 вкладки, и я собираюсь загрузить их все за один раз с помощью vpPager.setOffScreenLimit(2); И поскольку я загружаю все фрагменты, я хочу получить ссылку на все из них. Get onPageSelected даст мне ссылку только на активную страницу. Это может показаться глупым, но есть ли способ удерживать фронт до тех пор, пока вы не загрузите все страницы? - person Thomas Dang; 17.07.2014

Я использовал этот подход в прошлом, и он работал довольно хорошо.

В вашем адаптере вы можете объявить переменную экземпляра следующим образом:

private Map<Integer, Fragment> mPageReferenceMap = new HashMap<Integer, Fragment>();

В вашем getItem() поместите ссылку на фрагмент на карту

mPageReferenceMap.put(position, f);

Переопределите метод InstantiateItem:

/**
 * After an orientation change, the fragments are saved in the adapter, and
 * I don't want to double save them: I will retrieve them and put them in my
 * list again here.
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
   Fragment fragment = (Fragment) super.instantiateItem(container, position);
   mPageReferenceMap.put(position, fragment);
   return fragment;
}

Переопределите onDestroyItem для очистки ссылок:

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

И, наконец, получить фрагмент в зависимости от его положения:

public Fragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Надеюсь, поможет.

person AlexBalo    schedule 17.07.2014
comment
Спасибо, я попробую это. Благодарю за помощь, отмечу правильный ответ, если получится :) - person Thomas Dang; 17.07.2014

Похоже, что причина, по которой моя ссылка стала нулевой, заключается в том, что загрузка фрагментов выполняется в фоновом режиме, и когда я ссылаюсь на эти фрагменты, загрузка еще не завершена (спасибо, Даниэль Золнаи, за указание на это, я бы дал вам правильный ответ) если вы поставите это как ответ) Мои мысли о решении сейчас:

-Загрузить все страницы, которые у вас есть, если количество страниц невелико, используя (ViewPager).setOffScreenLimit(int limit)

-Приостановите основное действие и дождитесь загрузки всех страниц, затем продолжайте.

Теперь я застрял во второй части, если кто-нибудь знает, как дождаться или отложить MainActivty для загрузки страниц для завершения или перевести задачу загрузки на передний план, это было бы для меня большой помощью, спасибо

person Thomas Dang    schedule 17.07.2014