Why is FragmentPagerAdapter saveState always null? - android

I want to save the state of my FragmentPagerAdapter so I can reuse it after the orientation of the screen changed. Unfortunately the method saveState returns always null.
My Adapter consists of an ActionBar with two Fragments.
Here ist my method call
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(FRAGMENT, viewPager.getCurrentItem() + 1);
outState.putParcelable(ADAPTER, fragmentTabAdapter.saveState());
super.onSaveInstanceState(outState);
}
But the Adapter in outState is always null. I don't understand why. Is there something special I missed about the use of saveState?
Hope you can help me!

this example works if the fragment is not destroyed
private int pageID;
#Override
public void onPause() {
super.onPause();
pageID = mViewPager.getCurrentItem(); // 1 save
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mViewPager.setCurrentItem(pageID, false); // 2 load
}

Related

Recyclerview in fragment not loading after screen rotate

I want to save my fragment with recycler view, to restore it whlie screen rotate. I was looking for instructions in the net and I get:
In my Fragment
private Parcelable recyclerViewState;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
list.getLayoutManager().onRestoreInstanceState(recyclerViewState);
}
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
recyclerViewState = layoutManager.onSaveInstanceState();
}
in my Activity
//onCreate
if (savedInstanceState != null) {
getSupportFragmentManager().getFragment(savedInstanceState, LIST_USERS_FRAGMENT);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().getFragment(outState, LIST_USERS_FRAGMENT);
}
I was debbuging and it looks fine, however while I rotate my screen I get blank fragment, with no recycler view. Could You help me investigate why it's happening ?
The default behavior in Android is destroying all the attached fragments on configuration changes. To bypass fragment recreation you should use setRetainInstance(true) in the OnCreate callback of the fragment.
There are a different options to handle the orientation changes:
Lock screen orientation
<activity
android:name="com.example.test.activity.MainActivity"
android:screenOrientation="portrait"/>
Prevent Activity to recreated
<activity
android:name="com.example.test.activity.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"/>
Save basic state
public class MainActivity extends Activity{
private static final String SELECTED_ITEM_POSITION = "ItemPosition";
private int mPosition;
#Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
// Save the state of item position
outState.putInt(SELECTED_ITEM_POSITION, mPosition);
}
#Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Read the state of item position
mPosition = savedInstanceState.gettInt(SELECTED_ITEM_POSITION);
}
}
Save complex objects
Override
onRetainNonConfigurationInstance()
getLastNonConfigurationInstance()
After API level 13 these methods have been deprecated in favor of the more Fragment’s setRetainInstance(boolean) capability, which provides a much cleaner and modular means of retaining objects during configuration changes.

saving using onSaveInstanceState in Fragment

There is a Fragment in my android project in which it gets data dynamically from another class.I save that data(one string and Int) into bundle and And I want that bundle to be restored when screen rotates. So I have used onSaveInstanceState method.
In this fragment, "respond" method get data(one string and Int) from another class. I can print those strings in Logcat in respond method.
Fragment Code:
public class Images extends android.support.v4.app.Fragment implements Imageinfo {
private RecyclerView IRecyclerView;
private RecyclerView.Adapter IAdapter;
private RecyclerView.LayoutManager ILayoutManager;
private Context ctx;
private Bundle bundle=new Bundle();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.images, container, false);
Log.d("ONCREATE VIEW", "TRUE");
IRecyclerView = (RecyclerView) v.findViewById(R.id.images_tab);
IRecyclerView.setHasFixedSize(true);
ILayoutManager = new LinearLayoutManager(getContext());
IRecyclerView.setLayoutManager(ILayoutManager);
if(savedInstanceState!=null){
Log.d("BUNDLE ADDED NOT NULL", String.valueOf(savedInstanceState.size()));
IAdapter = new ImageAdapter(this.getContext(),((fileselect)getContext()).imageset,bundle);
IRecyclerView.setAdapter(IAdapter);
}
else{
Log.d("BUNDLE ADDED NULL", "TRUE");
IAdapter = new ImageAdapter(this.getContext(),((fileselect)getContext()).imageset,null);
IRecyclerView.setAdapter(IAdapter);
}
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState=bundle;
Log.d("SAVING TIME", String.valueOf(outState.size()));
super.onSaveInstanceState(outState);
}
#Override
public void respond(String str,int type) {
if(str!=null) {
if (type == 1) {
bundle.putString(str, str);
Log.d("BUNDLE ADDED", bundle.getString(str));
Log.d("BUNDLE ADDED Size",String.valueOf(bundle.size()));
} else {
bundle.remove(str);
Log.d("BUNDLE REMOVED Size", String.valueOf(bundle.size()));
}
}
}
}
PROBLEM:
Although the method respond receiving data(one string and Int) and saving into Bundle, bundle is becoming size zero in onSaveInstanceState when screen rotated. onSaveInstanceState is getting called whenever i rotate screen but the bundle is becoming size zero. As bundle is becoming size zero, I could not restore the two strings.
OK the problem is that, instead of adding content to the outstate variable, you are trying to reference a local variable.
The point is that the instance of the Images class is destroyed on rotation, and so will your bundle variable.
The correct way to achieve what you are trying to do is to add your strings to the outstate variable in the onSaveInstanceState method, and read it from the savedInstanceState in the onCreateView.
Try this out:
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("YOUR_STRING_NAME", bundle.getString("YOUR_STRING_NAME"));
Log.d("SAVING TIME", String.valueOf(outState.size()));
super.onSaveInstanceState(outState);
}

onSaveInstanceState in Fragment not working?

I need help.I don't know what is wron here.Need Saved Instance Data in fragment but it's not working for me? Can anyone help ? Here is my code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
if (savedInstanceState == null) {
Log.e(getActivity().getClass().getSimpleName(),"DATA is NULL");
}else{
Log.e(getActivity().getClass().getSimpleName(),"DATA IS NOT NULL " + savedInstanceState.getString(Constans.SAMPLEDATA));
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(Constans.MOVIE, movie);
outState.putString(Constans.SAMPLEDATA, "sampleData");
}
This is happening because on screen rotate your activity gets recreated so does the fragment inside it start from initial position again as it was started on activity first launch
You need to add this in onCreate of your activity and set the fragment inside if statement like this example
if (savedInstanceState == null){
launchfragment
} else {
// do nothing
}
hope this helps
Add super.onSaveInstanceState(outState);
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelable(Constans.MOVIE, movie);
outState.putString(Constans.SAMPLEDATA, "sampleData");
super.onSaveInstanceState(outState);
}

How do I prevent viewpager from making network request, if the network request has already been made for all the pages

I have a viewpager with three pages that uses FragmentStatePagerAdapter.
The fragment for each page is same but the data changes depending on the position of the page. The inflation logic for each item on the page is defined in fragment's OnCreateView, and thats why each time new instance of fragment is inflated the network calls are repeated even though they have been already made on previous visit to that page.
My question is how do I prevent this. I am new to android and I know I am missing something here, IF my approach is wrong please point out about how should I prevent this behavior.
Some Code :
inside activity's oncreate
ViewPager mViewPager = (ViewPager) findViewById(R.id.vpBooks);
PagerAdapter mPagerAdapter = new BooksPageAdapter(getSupportFragmentManager(), MainActivity.this, extras);
mViewPager.setAdapter(mPagerAdapter);
inside viewpageradapter
public BooksPageAdapter(FragmentManager fm, Context context, Bundle extras) {
super(fm);
this.extras = extras;
this.cls = extras.getStringArray("cls");
this.context = context;
}
#Override
public Fragment getItem(int position) {
return BooksPageFrag.newInstance(extras, cls[position]);
}
#Override
public int getCount() {
return cls.length;
}
inside fragment :
#Override
public void onCreateView(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
url = getArguments().getString("url");
urlFare = getArguments().getString("Fare");
Log.d("url sapf", url);
queue = Volley.newRequestQueue(this.getActivity());
getBooks();// HERE network calls are made
}
so what I want is if the fragement for a particular cls[position] is instantiated and data is fetched then on revisiting same position it should not make new network calls
You need to use parcelable . I think you are using a list array of a class object
.Follow the following steps
1.) Implement parcelable in the class object
2.)In the OnSavedInstanceState use the following code
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("key", mListParcel);
}`
3.) In the onCreate method use this code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
/*Set Your RecyclerView Stuff here*/
if(savedInstanceState!=null)
{
//Fragment has been loaded earlier\
mArrayList=savedInstanceState.getParcelableArrayList("key");
//Use list here
}
else
{
//Fragment New
// Make Request Here
}
}

Saving the state of fragments?

I have a fragment class. Here is it below:
public class FragmentA extends Fragment {
Button button;
WebView myWebView;
int mCurCheckPosition;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved)
{
View mainView = (View) inflater.inflate(R.layout.frag_a, group, false);
myWebView = (WebView) mainView.findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
myWebView.getSettings().setPluginsEnabled(true);
myWebView.getSettings().setBuiltInZoomControls(false);
myWebView.getSettings().setSupportZoom(false);
myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.getSettings().setAllowFileAccess(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.loadUrl("http://www.bbc.co.uk");
return mainView;
}
public class MyWebViewClient extends WebViewClient {
/* (non-Java doc)
* #see android.webkit.WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String)
*/
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".mp4"))
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
view.getContext().startActivity(intent);
return true;
}
else {
return super.shouldOverrideUrlLoading(view, url);
}
}
}
}
The problem is when I move to and from another fragment, the state of the original fragment (what web page it was on) is lost.
How can I prevent this? I want the state of the web page to remain switching to and from each fragment.
Thanks
You should use the WebView.saveState(Bundle state) method to in your onSaveInstanceState(Bundle outState) method and then restore the state using WebView.restoreState(Bundle state) in your onActivityCreated(Bundle savedInstanceState) method
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mWebView.saveState(outState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mWebView.restoreState(savedInstanceState);
}
Also keep in mind the Fragment Lifecycle. If your unsure where to restore the state (onCreate, onCreateView, onActivityCreated), take a look at the Fragment Lifecycle documentation to figure out the right place.
http://developer.android.com/guide/components/fragments.html
onCreate()
The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
onCreateView()
The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
onActivityCreated()
Called when the fragment's activity has been created and this fragment's view hierarchy instantiated. It can be used to do final initialization once these pieces are in place, such as retrieving views or restoring state. It is also useful for fragments that use setRetainInstance(boolean) to retain their instance, as this callback tells the fragment when it is fully associated with the new activity instance. This is called after onCreateView(LayoutInflater, ViewGroup, Bundle) and before onStart().
I was having the same problem with webView content in a fragment. What worked for me was hiding the current fragment when loading a new one instead of replacing it. This causes the view to remain in the previous fragment and not be destroyed. View code below.
protected void showTableFragment( Fragment fragment, boolean allowBack, Asset table ) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (table != null)
tableSection = (SectionTable) table;
Fragment lastFragment = fragmentManager.findFragmentByTag("first_frag" );
if ( lastFragment != null ) {
transaction.hide( lastFragment );
}
if ( fragment.isAdded() ) {
transaction.show( fragment );
}
else {
transaction.add( R.id.fragment, fragment, "second_frag" ).setBreadCrumbShortTitle( "second_frag" );
}
if ( allowBack ) {
transaction.addToBackStack( "second_frag" );
}
transaction.commit();
}

Categories

Resources