In my App I have:
DataManager class - a singleton which holds data
Activity which shows a 'loading' fragment until the data is ready, and then once it is ready, it replaces it with a 'content' fragment. (I do this with the replace() method, since I no longer have use for the 'loading' fragment)
The following flow causes (sometimes) a null pointer exception:
Open app and wait for the data to be loaded (meaning, until we get to the 'content' fragment)
leave the app using the home button
open the app after a while (after Android kills the app)
What happens is that the app resumes to the 'content' fragment, but the data from the DataManager is null.
This happens because Android kills my app, but when I resume, it saves the state, meaning it shows the 'content' fragment automatically.
Is there a way for me to tell the app not to create the 'content' fragment in this scenario? The solution I currently have in mind is to create a 'loading' Activity instead of a fragment, but i'd like to avoid that.
What I would suggest is either:
Persist your data to disk (e.g. SQLite DB), rather than retaining it as static data.
In your Activity onCreate(), check if you have data. If you do, continue on. If not, remove the content fragment and add back the loading fragment.
I would suggest that in the content fragment before loading other views and all, check if your data is ready. if not then start the loading fragment and resume content fragment when it's ready.
e.g in OnCreate
if(!dataLoaded){
replaceFragment(LoadingFragment)
}
Related
I have an android application where I have an activity with two fragments. One with a map view and the other with a listview. In the main activity I get the user's gps and results from the database based off the gps and send that data to the fragments. That made since instead of calling inside the fragment twice the same data. However, a lot of times the request for the backend data and the gps coordinates of the user are not completed before the fragments are created.
I set up an interface to pass the data back and forth but need to find a way to pause the fragment creation until all data is there.
Any ideas? I can post code if neccesary.
Don't "pause" the fragment. Have a "loading" state, a "loaded" state, and an "error" state. Then show the user what is going on between each state.
You should not block the fragment UI until the data is ready, but instead you should show the user that the page is loading (e.g. with a Progress Bar).
Once the data is ready, you should populate the fragments with data (through a callback) or show an error message.
Thanks for the responses. I found a better way to do it. So I was passing data from the activity to fragment via an Interface and in the onAttach method of the fragment. Instead I created a Local Broadcast Manager that listens for the data to be complete in the activity class and sends to the map fragment to populate.
Hope this helps someone else.
I have a Fragment in an Activity. When the Activity gets created, it triggers an asynchroneous load of the application state from a file. When this finishes, the Activity starts creating some paged Fragments, depending on the configuration state.
The problem is that when the OS kills the app, so that onCreate(bundle) has a stored state in the bundle because the OS took care of storing it prior to killing the app, the Fragments are also recreated immediately, but the application state is still getting read from the file, so they don't have access to the data they should be showing, which they need in their onCreateView(). This is because this time the Fragments are created by the OS, and not by the callback of the AsyncTask in the Activity's callback.
I'm hesitant towards making onCreateView() block/wait for the async result (even if it is avaliable in a fraction of second), so I'm thinking about moving the code which depends on the application state out of the Fragment's onCreateView(), and have some callback create it when the data is avaliable.
Ideally I'd work with deferreds/promises/futures, where I can "subscribe" to the async load result in the onCreateView() , but i'm too new to Java in order to know how to do this. I don't know which libraries exists or are suited for this.
Which suggestions do you have for me so I can deal in the best possible way with this issue?
Kind regards.
I am having an app which is retrieving data in the main activity and sending an event to all fragments as soon as it is available. So for the first start it looks like this:
App starts (fragments are initialising in the background) -> feed download -> notification sent to fragments -> fragments initialise UI
Everything's fine so far. BUT, what if I am resuming the app. The data will be still cached, so i will send the event immediately on app resume, and therefore it can happen that my fragments are not even ready for receiving the event -> no fragment UI update!
Or the event is triggered and received in the fragment, but the fragment is not ready for the UI update, cause it still hasn't inflated the layout -> NullpointerException
Or the fragment receives the event, but is not attached to the activity anymore -> another Exception.
There are ways to deal with single issues, but overall it is complicating the architecture a lot.
Somehow I tried a lot of things (playing around with Otto bus) but somehow I can't find any architecture which is working for making a central datasource available to all activities and fragments in the app.
How do you supply your fragments with data if you don't want to use bundles?
First of all a Fragment should be independent from other parts of an app. Moreover it shouldn't know parent activity: getActivity method should return just an Activity which could be casted to some interface.
an Activity shouldn't be a "data downloader". Basically activity is a View which receives various system and user events and displays particular state. For instance when the system creates activity it calls method 'onCreate' where activity should create/arrange fragments and views.
there is should be some manager or controller(call it as you wish) which knows where and how to get data for views. For instance if there is no internet connection it loads data from local database otherwise it makes network request.
So roughly speaking flow should look like this:
fragment(or activity) has reference to the DataManager. The fragment subscribes on FeedDataEvent in the onResume method. When fragment wants(onResume method for example) to show some data to the user it calls DataManager.loadFeed() and displays to the user "loading..."
DataManager checks if there is Task which is loading data from network. If there is no such fast it starts it.
When data is downloaded DataManager emits FeedDataEvent.
If the fragment is still visible it receives that event and shows data. If the user left the app fragment unsubscribed(in the onStop method) from FeedEventData and will not receive that event.
There is subtle thing with requests caching(making network request on every onResume is not very good idea) but it depends on particular app.
PS Almost all this things are implemented in RoboSpice and some other libraries.
I have this problem. I have an activity and a fragment inside it. I am downloading some data using async task in activity's onCreate and then using it in the fragment's onCreate (something like getActivity().getData()). I am putting the fragment into a view after the data is loaded so it runs without trouble. The problem is that when I'm relaunching the activity from background and this fragment is active it loads immediately and throws an NullPointerException because the data isnt loaded yet. My idea was to check for this in the fragment's onCreate and if I get null data I'll just destroy it and call some activity's method for reloading data and then lauch the fragment again - is it even possible?
Do you have any solution for this or maybe a better approach?
If it's possible to cache the data on the phone, I would consider it.
If you have to reload the data on every (re-)start (more like: every resume) of the app, take a look at the activity lifecycle in the android documentation:
http://developer.android.com/reference/android/app/Activity.html
Your problem should be solved, if you #Overwrite onResume() of your activity and load your data there, instead of onCreate()
I have an application that navigates to the same activity but each time the activity loads with different parameters. In my application it's a parsed data content retrieved from url. First thing I want to ask: When I push the backbutton of my device I get my earlier activity without being recreated. Is the objects in this activities alive and can I reference them?
Second question is if my first question doesn't make sense, what do you advice me to do?
If you look at the Activity life cycle, you'll notice that as long as your phone has enough memory, your first activity is kept in memory, and with it any member with the data it contains.
But if your phone needs to have some memory, it can kill any activity kept in background (any activity but the one being shown to the user), which means that you'll loose any data that was in your first activity.
To know which happened, keep in mind that the onResume() method will always be called when your activity is brought to foreground (either on creation, or when you navigate back to it), but onCreate() will be called only when your application is created from scratch (meaning you don't have any saved data).
You should use the bundle mechanism to save data when your activity is paused, and load it when you come back to it. Read the paragraph about Saving Activity state in Android doc to see how to use this.
You are not guaranteed that in memory data will be around once you leave an Activity. Read through this part of the dev guide thoroughly to understand the lifecycle of an Activity: http://developer.android.com/guide/topics/fundamentals/activities.html
If you need to persist information, you should override the onPause, onStop, and/or onDestroy methods of your Activity. You can then save your state using SharedPreferences, the SQLite database, or even a flat file.
In the manifest file add the following to the activity:
android:launchMode="singleTop"
In your example what is happening is when you navigate back to the activity using the back button you are bringing up the activity from the stack. When you navigate to the activity inside of the app what is happening is a NEW activity is being created, while the original is still on the stack. The singleTop launch mode will pop the activity out of the stack if it is there when you navigate to it in the app, and only create a new activity if it is not on the stack.
Without singleTop each time you launch the activity in the app it will create a new instance and you will find there are times you have to hit the back button on the same activity more than once due to multiple instances.