Application which I'm writing has 3 Fragments. Main Fragment Activity has a Search Box with Search button when I press on a Search button the function below is called:
Fragments.values()[tabControl.getCurrentItem()].getFragment().search(tv.getText().toString(), MainActivity.this.getApplicationContext());
Everything works Okay until I press HOME button wait for 30 minutes and relaunch application, after I press Search button in FragmentYellowPages
Fragment application crashes on the lines
lvYellowPages.setVisibility(View.VISIBLE);
as lvYellowPages
in this case is null, but In a logs I can see that onCreateView
function is called. Can you please help me, I can share my code with you.
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>
If there is something that you need to initialize in your fragment that depends upon the activity's onCreate() having completed its work, you can use onActivityCreated() for that initialization work. onDestroyView() is called before onDestroy() . This is the counterpart to onCreateView() where you set up your UI.
FragmentActivity does not inherit from Fragment . Hence, you cannot inherit from Activity or FragmentActivity and somehow also inherit from Fragment .
A fragment is not required to be a part of the Activity layout ; you may also use a fragment without its own UI as an invisible worker for the Activity but it needs to be attached to an Activity in order to appear on the screen.
According to the Android documentation, a fragment is a part of applications user interface that is bound to an activity. Fragments have their lifecycle and layouts or UI components. Fragments help enrich your UI design, pass data between different screens, and adapt to different device configurations.
It's hard to pinpoint the exact problem but I'm almost sure it has to do with the way you built the adapter for the ViewPager
.
Everything works Okay until I press HOME button wait for 30 minutes and relaunch application, after I press Search button in FragmentYellowPages Fragment application crashes
As the Activity
is in the background(and apparently killed) it will recreate its content when comming back to the foreground. At this point the ViewPager
will rebuild its content, but its adapter will not call getItem()
as it has all the data to recreate the previous fragments on it own. So you'll end up with two fragment version, the ones currently visible in the ViewPager
(so you see the onCreateView()
being called) and those that are in the enum
. Those fragments from the enum
aren't tied to the Activity
and so the entire callbacks stack isn't run for them, so onCreateView()
will not be called, which will make your lvYellowPages ListView
null
.
Btw, this is the first time I've seen the fragments of an adapter being built in a enum
and I recommend that you avoid this.
The solution is to not reference the fragments of the ViewPager
outside. Make the getItem()
method return a Fragment
instance and if you need to access those fragment there are ways to do it without storing the ViewPager
's fragment in lists/enums etc(a quick search on stackoverflow should show you a question about this):
@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;
}
Also:
setRetainInstance(true);
I wouldn't use this. It doesn't make sense to retain a fragment used by a ViewPager
(as I don't think you're planing to move it somewhere else) and it will also not protect you from the activity being killed in the background.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With