I have a fragment that loads json data from server
and display it in a list.
my problem is that when I move to a different fragment on the same activity, that fragments data is being deleted.
when I go back to that fragment all the data is empty, and it's loading again from the server.
is there a way to keep the fragment alive in the background?
that's the code I use to switch fragments :
private void fragmentSwitch() {
this.getFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.fade_out)
.replace(R.id.main_fragment_container, fragment)
.commit();
}
Thanks a lot in advance.
I see 3 different options:
Your activity keeps the data, so you can switch between fragments without loosing data.
After your fragment is created you can call one method of the activity to get the data.
For example you can create a method like getJsonData() in your activity and call it from your fragment (YourActivity)getActivity().getJsonData()
You save data in SharedPreferences and access it from you fragment
You save data in Database and access it from your fragment
Related
I have Fragment1 and Fragment2, RecyclerView1 corresponding to Fragment1, RecyclerView2 corresponding to Fragment2.
Both RecyclerViews have the same data source (the same information).
I use a button, let's say SwitchButton, to switch between the 2 fragments. Both fragments are in the same activity.
Use case: scrolling in RecyclerView1 to position 10, then clicking on the SwitchButton will show Fragment2 with the RecyclerView2 scrolled to position 10.
Where to keep the data? Because I don't want to make calls to server each time I switch between Fragment1 and Fragment2. Hope you understand. Thanks!
You can do it with the help of Interface.
1.create an interface with two methods one to set network call data and other to get the assigned network call data in activity.
2.In both fragments before making network call check whether the assigned data in activity using interface exist.
if it doesn't exist , make network call, save the data to activity variable.
when the fragment destroyed and recreated. the data will not be lost.
Here is my problem area:
I have a Fragment A. Once it is attached, in its onCreateView, I load a webservice to fetch the data from the server and after that I set that data on the list view using a Base Adapter. Now on the Item Clicks of the list view I replace the Fragment A with Fragment B using replace Methods of the Fragment Transactions and addtoBackstack("FragmentA").
FragmentManager fm =getActivity().getFragmentManager();
fm.beginTransaction().replace(R.id.content_frame, Fragment B).commit();
Now here when I press back button on Fragment B, it takes me to Fragment A but the webservice again starts loading.
My Problem: I just want that when it returns to Fragment A, it should show its previous state and should not call the webservices again.
Thanks
OnCreateView for a fragment runs on the creation of the view every time it needs to be drawn. By going back you are causing the view to be recreated and hence the webservices are loading again.
I believe that if you only want the web services to load once then you could move the code to the "onCreate" method instead, but its probably a better idea to move this code to "onResume" instead and include some logic that checks whether you need to load your webservices again or not.
This way everytime the fragment is paused and then loaded again you could ensure that the fragment still has everything it needs.
(source: xamarin.com)
EDIT:
So for example you could have
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
if (data == null) { //Or list is empty?
getWebData()
}
}
My app has one main Activity with a FrameLayout to load some Fragments, most of them managing http data requests.
When the connection is lost, I start a specific Fragment "NoConnectionFragment" with a text "No internet connection" and a Button "Retry".
When clicking on "Retry" I want to reload the previous Fragment, that failed to load the data, with some data to specify the state of the Fragment.
I can pass the state data in a Bundle, but how can I pass to the NoConnectionFragment data on what Fragment to reload? Is there any way to pass the Fragment directly?
How about just storing the name of the previous fragment.
ex: If FragmentA is active before NoConnectionFragment is launched, keep a static variable int the parent activity that stores this state.
static int PREV_FRAGMENT_INDEX; //index can be 0 for FragmentA, 1 for FragmentB etc
When retry button is clicked, just check this variable to launch the appropriate fragment:
onClick(View v)
{
switch(getActivity().PREV_FRAGMENT_INDEX)
{
case 0: //launch Fragment A
case 1: //launch Fragment B etc
}
}
You can't pass a fragment to another Fragment because fragments are not supposed to work that way and also fragment are managed by FragmentManagers. What you could do is to pass data from a Fragment to another.
I'm trying to create a ViewPager with six fragments but only 2nd fragment to 5th fragment contain data that I want to show and the first fragment and the last fragment I want to be used to reload the data and set the position to the 2nd fragment again. The overall flow is like this :
1st (reload and go back to 2nd) <- 2nd fragment <-> 5th fragment -> 6th fragment (same with 1st)
what I've tried is I create a callback from the 1st fragment and 6th fragment like this
public static class callbackFragmentLoading implements callbackFragmentLoad {
#Override
public void onLoading() {
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(2,false);
}
}
and I passed the callback to the fragment constructor so I can called the onLoading function in the onActivityCreated. But I everytime I do it the application will be force closed and the logcat shows
recursive entry to executependingtransactions
is there any way to do this? or my method for doing it is wrong?
Thank You
is there any way to do this? or my method for doing it is wrong?
Messing with callbacks between Fragments of a ViewPager isn't probably such a good idea. Instead I would do it like this:
Don't load any data(like with a Loader) in the Fragments from the ViewPager, instead let the FragmentActivity do it(and the Fragments will get it through methods from the Activity).
Your two loading fragments(position 0 and 5) will call in their onResume method a reload action on the parent Activity(like a Loader restart)
At this moment the Activity will load/reload the data and when that finishes it will set the ViewPager to the correct items(either 1 or 4)
in the onResume method of the data fragments you'll refresh the fragment's data(here you may need to use some sort of signaling system because you'll need to duplicate the refresh code in the onCreateView(some fragments may have their view destroyed if they are far apart from the current visible position)).
As I don't know many things about the inner data fragment I've written a basic skeleton sample(without the data loading in the activity).
I have a main TabActivity which has two tabs, A and B (for now). Tab A loads a FragmentActivity (code given below) which just conatains a FrameLayout, so I can load my Fragments for that specific Tab in it.
The first Fragment has some TextViews and one ListView. Data is pulled from a web service. When I click on an ListView's item, I load that item's detail in another Fragment (this also comes from a web service) and replace the current Fragment (with ListView and other controls) with another detail fragment.
To achieve this, I am using android-support-v4.jar library to use Fragments as they were preferred.
Tab A's FragmentActivity's XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/updates_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/background"/>
</LinearLayout>
Tab A's FragmentActivity Java code:
public class UpdatesFragmentActivity extends FragmentActivity implements
IUpdateNotifier {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.updates);
//Load Initial Fragment into FrameLayout
//I am adding this Fragment to BackStack
Fragment newFragment = new UpdatesFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.addToBackStack(null);
ft.add(R.id.updates_frame, newFragment);
ft.commit();
}
//This is an Interface method which I call with the clicked "FEED" object to load its detail in another Fragment
#Override
public void onFeedSelected(Feed feed) {
// Instantiate a new fragment.
Fragment newFragment = new FeedDetailFragment(feed);
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.updates_frame, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
//This is another Interface Method which I call when the user presses "BACK".
//I am trying to load the previously loaded Fragment, which I added to BackStack.
//But this causes reconstruction of the previously loaded fragment. LIST in this case
//which call the web service. I DONT WANT TO CALL SERVICE AGAIN.
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
}
}
}
I have created an interface IUpdateNotifier, which contains two methods:
public void onFeedSelected(Feed feed);
public void onBackPressed();
Parent UpdatesFragmentActivity implements these methods. I call these methods from children Fragments upon following actions.
I call onFeedSelected(Feed feed) from the Fragment which has a ListView. I send the clicked feed item to parent FragmentActivity, so it loads another Fragment which would contain that feed detail.
I call onBackPressed() from the second feed detail Fragment when the user presses a button that is supposed to bring back the first fragment which contained ListView with other controls. As you can see, I try to call FragmentManager's popBackStack() method to bring back that first Fragment...
But the first Fragment gets refreshed and loads all the data from web service.
Actually I cannot get and store data only once nor the updates are frequent on some time intervals. The user can update the list when he wants. Initially, the list loads the top 10 items from the service, and then user can click the "More" button at the end of list if he wants to load more items.
It will load the next 10 items and so on. But I think I can store the retrieved ArrayList in some variable in UpdatesFragmentActivity and then just reassign that ArrayList to the list's adapter instead of loading the data from service, but I don't know how to make Fragment not to call service again.
I want it to behave like when I click on tab 2 and then on tab 1 again. It simply shows the loaded data as if was hidden and does not call the service.
How can I achieve this?
Your design pattern is flawed due to a poor separation of concerns. The updating of data should be decoupled from the UI, therfore when a user goes back to the previous Fragment it should have nothing to do with loading data from a web service.
There are a couple of easy fixes but I do not know what will work best as you have given little context to the problem.
First option would be to introduce a Splash Screen on start up. This Activity would make use of an AsyncTask to download the data you need from the web service. This works well if you only want the data to be downloaded once during the runtime of the app. You would make sure not to add this Activity to the history so when back is pressed from the next activity, the app would then exit.
Another option, which I have used in many apps and the one I prefer, is the use of Alarms via the AlarmManager. You can set a periodic updates at specific time intervals, the AlarmManager even helps you to the point where it contains enumerations of time. The Alarm will trigger a broadcast receiver which will execute your custom code, that will download the data you need from the web service and store it.
There is a tutorial on this approach, which can be found here http://android.arnodenhond.com/tutorials/alarm-notification.
Finally; you should not need to pop the back stack to get around this problem, although you might be doing this for entirely different reasons but it is hard to tell without more info.
Your question is not clear enough, ask more simple and precise questions... And as you say above
popBackStack does not load the last fragment, it's commonly used to pop the entire stack :
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
before loading another fragment
beginTransaction()
replace() Or add()
commit()
That's all i can think about with that question
Good luck