Члены класса в фрагменте становятся нулевыми после нажатия кнопки "Домой" и ожидания

Описание проблемы

Приложение, которое я пишу, имеет 3 фрагмента. Основная функция фрагмента имеет поле поиска с кнопкой "Поиск" , когда я нажимаю кнопку "Поиск" , вызываемая ниже функция:

Fragments.values()[tabControl.getCurrentItem()].getFragment().search(tv.getText().toString(), MainActivity.this.getApplicationContext());

Все работает Хорошо, пока я не нажму кнопку HOME, подождите 30 минут и перезапустите приложение, после того, как я нажму кнопку "Поиск" в FragmentYellowPages Сбой приложения Fragment на линиях

lvYellowPages.setVisibility(View.VISIBLE);

as lvYellowPages в этом случае имеет значение null, но в журналах я вижу, что вызывается функция onCreateView. Можете ли вы мне помочь, я могу поделиться с вами своим кодом.


FragmentPagerAdapter

public class FragmentAdapter extends FragmentPagerAdapter {

    Fragments[] mFragments;

    public FragmentAdapter(FragmentManager fm) {
        super(fm);

        mFragments = Fragments.values();
    }

    public enum Fragments {

        Favorites(App.getStringByResId(R.string.favorites), new FragmentFavorites()),
        Categories(App.getStringByResId(R.string.categories), new FragmentCategories()),
        YellowPages(App.getStringByResId(R.string.yellow_pages), new FragmentYellowPages());

        Fragments(String title, BaseListFragment fragment) {
            this.mTitle = title;
            this.mFragment = fragment;
        }

        String mTitle;
        BaseListFragment mFragment;

        public String getTitle() {
            return mTitle;
        }

        public BaseListFragment getFragment() {
            return mFragment;
        }
    };

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragments[position].getTitle();
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments[position].getFragment();
    }

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

Фрагмент списка

public class FragmentYellowPages extends BaseListFragment {

    final static String TAG = FragmentYellowPages.class.getSimpleName();

    ListView lvYellowPages;
    TextView tvInfo;
    SimpleCursorAdapter scAdapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View yellowPagesView = inflater.inflate(R.layout.fragment_yellow_pages, container, false);

        Log.i(TAG, "onCreateView( )");

        tvInfo = (TextView) yellowPagesView.findViewById(R.id.tvYellowPagesInfo);
        lvYellowPages = (ListView) yellowPagesView.findViewById(android.R.id.list);

        return yellowPagesView;

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.i(TAG, "onCreate( )");

        setRetainInstance(true);

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Log.i(TAG, "onActivityCreated( )"); 
    }


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

        Log.i(TAG, "onResume( )");      
    }

    void updateAdapterOnSearch(final String tts, final String lang) {
        Log.i(TAG, String.format("updateAdapterOnSearch(%s, %s)", tts, lang));

        /* Show "Yellow Pages" list view and hide Info text view. */
        lvYellowPages.setVisibility(View.VISIBLE);
        tvInfo.setVisibility(View.GONE);
        /* Some code .... */
    }

    @Override
    public void search(final String tts, final Context context) {
        Log.i(TAG, String.format("search(%s)", tts));

        /* If user search for the text. */ 
        if (tts != null && tts.length() != 0) {
            updateAdapterOnSearch(tts, lang);
        }
    }

};

Макет фрагмента

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffc8"
    android:tag="FRAGMENT_YELLOW_PAGES_TAG" >

    <ListView android:id="@android:id/list"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:visibility="gone"
              android:background="#ffffc8"/>

    <TextView android:id="@+id/tvYellowPagesInfo"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_centerHorizontal="true"
              android:layout_centerVertical="true"
              android:gravity="center"
              android:padding="5dp"
              android:text="@string/no_companies_were_found"
              android:visibility="gone"/>

</RelativeLayout>

Ответ 1

Трудно точно определить точную проблему, но я почти уверен, что это связано с тем, как вы построили адаптер для ViewPager.

Все работает Хорошо, пока я не нажму кнопку HOME, подождите 30 минут и повторное приложение, после нажатия кнопки поиска в FragmentYellowPages Фрагмент приложения падает

Поскольку Activity находится в фоновом режиме (и, по-видимому, убит), он будет воссоздавать его содержимое, возвращаясь на передний план. На этом этапе ViewPager будет перестраивать свой контент, но его адаптер не будет вызывать getItem(), поскольку он имеет все данные для воссоздания предыдущих фрагментов на своем собственном. Таким образом, вы закончите с двумя версиями фрагмента, теми, которые в настоящее время видны в ViewPager (поэтому вы видите, как вызывается onCreateView()), и те, которые находятся в enum. Те фрагменты из enum не привязаны к Activity, и поэтому весь цикл обратных вызовов не запускается для них, поэтому onCreateView() не будет вызываться, что сделает ваши lvYellowPages ListView null.

Btw, это первый раз, когда я видел фрагменты адаптера, построенного в enum, и я рекомендую вам избегать этого.

Решение состоит в том, чтобы не ссылаться на фрагменты ViewPager снаружи. Сделайте метод getItem() возвратите экземпляр Fragment, и если вам нужно получить доступ к этому фрагменту, есть способы сделать это, не сохраняя фрагмент ViewPager в списках/перечислениях и т.д. (Быстрый поиск в stackoverflow должен показать вам вопрос о это):

@Override
public Fragment getItem(int position) {
    switch (position) {
    case 0:
       return new FragmentFavorites();
    case 1:
       return new FragmentCategories();
    case 2:
       return new FragmentYellowPages();
    }
    return null;
}

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

также:

setRetainInstance(true);

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