2015-07-16 3 views
2

Я только что переключил старый проект Android от Eclipse на Android Studio, и в этом процессе я обновил из старых библиотек поддержки 19.0.1 до 22.2.0. После этого я получаю некоторые ошибки в моем предыдущем рабочем коде. Я загрузил все SDK между ними и проверил, где ошибка сначала вошла в игру, и, похоже, она находится в версии 21.1.0 и выше. Я смотрел в release notes для этой версии, но не мог найти ничего интересного.Android: NullPointerException с помощью findFragmentById() после библиотек поддержки ugrading

Моя ошибка в том, что я получаю NullPointerException здесь. Обратите внимание, что этот метод является частью Activity, а не родителем Fragment.

public synchronized void onRecipesFiltered(ArrayList<Recipe> filteredRecipes) 
{ 
    FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment) 
     getSupportFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment); 

    // filteredRecipesListFragment becomes null 
    filteredRecipesListFragment.onRecipesFiltered(filteredRecipes); 
} 

The Fragment я получаю здесь является ListFragment, который является частью файла XML, который надувается при запуске приложения. Похоже, что ListFragment добавляется к FragmentManagerвнутри родительский Fragment во время инфляции. Вероятно, поэтому я получаю nullpointer при получении FragmentManagerActivity. Таким образом, мой вопрос:

Как я могу получить ListFragment в Activity? Нужно ли хранить ссылку на родителя Fragment, чтобы получить ListFragment через его FragmentManager? Родитель Fragment раздувается при возврате new MyFragment() в FragmentPagerAdapter#getItem(), больше нигде, поэтому немного более сложно получить правильную ссылку в Activity.

Есть еще одна вещь, которую следует отметить: я видел сообщения, в которых говорилось, что я должен обновить до JDK 1.7, что я и сделал (OpenJDK 1.7). Я не помню, что я сделал, но в разделе «Внешние библиотеки» я вижу <1.7> (/usr/lib/jvm/java-1.7.0-openjdk-amd64). Не уверен, если это имеет значение.

ответ

1

Я решил проблему, следуя this ответ. Похоже, что на самом деле невозможно получить Fragment s от ViewPager, поэтому они должны храниться в качестве ссылок после создания и при необходимости.

Я копирую главный код ответа здесь, на всякий случай. Основная идея состоит в том, чтобы сохранить Fragment s в SparseArray, чтобы получить их при необходимости. Они должны быть вставлены и удалены после создания/перед удалением.

public class MyPagerAdapter extends FragmentStatePagerAdapter { 
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); 

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

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

    @Override 
    public Fragment getItem(int position) { 
     return MyFragment.newInstance(...); 
    } 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     Fragment fragment = (Fragment) super.instantiateItem(container, position); 
     registeredFragments.put(position, fragment); 
     return fragment; 
    } 

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

    public Fragment getRegisteredFragment(int position) { 
     return registeredFragments.get(position); 
    } 
} 

После этого я мог бы переписать свой метод к следующему, используя getChildFragmentManager() как отметил @Skizo:

public synchronized void onRecipesFiltered(ArrayList<Recipe> filteredRecipes) 
{ 
    MyPagerAdapter myPagerAdapter = (MyPagerAdapter) mMyViewPager.getAdapter(); 
    FilteredRecipesFragment filteredRecipesFragment = (FilteredRecipesFragment) 
      myPagerAdapter.getRegisteredFragment(PagerConstants.PAGE_FILTER_RECIPES); 

    if (filteredRecipesFragment == null) 
    { 
     // Fragments that has not yet been instantiated will be returned as null. Cannot do anything about it. 
     // Should be fairly unlikely. See: 
     // https://stackoverflow.com/a/15261142/1139324 
     return; 
    } 

    FilteredRecipesListFragment listFragment = (FilteredRecipesListFragment) 
      filteredRecipesFragment.getChildFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment); 
    listFragment.onRecipesFiltered(filteredRecipes); 
} 
0

Попробуйте заменить:

FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment) 
    getSupportFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment); 

к:

FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment) 
    getChildFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment); 

Узнайте больше о getChildFragmentManager() на getChildFragmentManager() documentation

+0

Это означает, что я должен сохранить ссылку на родителя 'Fragment' куда-нибудь быть в состоянии вызвать 'getChildFragmentManager()'. Метод в вопросе помещается в 'Activity', чтобы действовать как шлюз между' Activity' и его 'Fragments'.I * может * содержать ссылку на родительский «Фрагмент», но это часть «FragmentPagerAdapter», поэтому не так просто провести ссылку, потому что 'FragmentPagerAdapter # getItem()' возвращает 'new FilteredRecipesFragment()'. Каков наилучший способ сделать это? –

+0

У меня нет идей ... позвольте мне подумать об этом –

Смежные вопросы