In the App i am developing, I have to connect to a server/broker to send and receive some messages to and from the broker, and also I have to provide a callback synchronous and an asynchronous listener. As far as I understand, such operation should be better placed in onResume(). am I right? please guide me and confirm whether onResume is the best place to connect to servers/brokers with callbacks or they woud better be inside other lifecycle callback?
As you probably will do something with your UI as soon as you have the answer from the server, you'll want to contact it only when your UI has been created and set up.
OnCreate is fine in an Activity (after setContentView and assigning your Views), OnViewCreated for a Fragment. As long as you're 'prepared' to receive the server's answer instantaniously, it doesn't really matter.
Remember that most 'startup' lifecycle callbacks will be called again if the screen rotates, so don't do the server call twice if you don't have to.
Related
My app makes frequent use of the following pattern:
User clicks button
API request is fired
response is parsed
Callback returns data Data is updated in view.
However, due to the nature of the API these callbacks can take some time and I find that I can easily crash the app if I navigate around the app at a high pace. Mostly this is caused by NullPointerExceptions related to the fact that the activity and/or fragment no longer exists. My question is what the best practice is when dealing with these issues. Should I just check for null values everywhere? I've read somewhere that you should just avoid using callbacks to update the UI at all but I'm not sure what the alternative is.
Thank you all!
for Fragment you can check by isAdded()
public void onResponse(){
if(isAdded()){
// Do your stuff here
}
}
In activity isFinishing()
public void onResponse(){
if(!isFinishing()){
// Do your stuff here
}
}
Let me share how I did in one of my apps.
I created a class which extends Application and that class is responsible to initiate a database. It is Singleton Static database and everytime I need to do something, I call db.getInstance().doSomething()
When any API method is called, I start an AssyncTask which store the data on database after completed (in case of failure, nothing is saved).
When Database is updated, it sends a LocalBroadcast. You can send broadcasts to notify the error (which stops the Refresh animation and show a error message, for example).
Each activity has a BroadcastReceiver which register to receive the local broadcast sent by Database. I register during onStart() and de-register during onStop(). Each activity register to proper event (since you can create multiples intents and actions... This way, your activity receives only the desired intent and not every single broadcast of your app.
This way, when the activity is opened, it checks the data from database and if any content change, it receives a broadcast notification and take proper actions.
When the activity is closed, it no longer receive broadcast.. However, the updated data will be there on database after download is completed.
You must handle situations where some API call was already started to avoid calling twice (at least, until first call of same method finishes etc)..
You can also use ContentObserver to monitor some database etc.
This is one way to handle. It may work or not for you case etc... Just sharing since it may help you
This topic has so many different SO questions linked to it, I know, but I think most people ask their questions while still confused about why things happen when.
I've read Alex Lockwood's article on Fragment Transactions & Activity State Loss, and although he provides clear arguments for all things (read the article - it's really informative and easy to understand), he doesn't provide a full proof work around for my situation - using AsyncTasks.
Here's what we do in our app:
User presses a button which initiates an AsycTask doing a call to our server.
A phone call is initiated from within the app using Intent.ACTION_CALL.
Phone call is ended and user returns to the app.
AsyncTask responds with server call response.
App code processes the response and displays output to user.
So obviously, when the user goes to the phone call, our app is stopped. So when the AsyncTask gets to onPostExecute() and provides the server call response, we might not be in a live activity, and it's probably after onSaveInstanceState() has been called.
So how do I solve this?
I have to communicate the results of the server call response to the user through an AlertDialogFragment, but when I want to show that alert, I get IllegalStateException.
Alex Lockwood suggests that I make sure that no fragment transactions occur after onSaveInstanceSate() has been called - i.e. (I figure) don't trigger anything in the app (like displaying an alert), from the onPostExecute() of an AsycTask.
So when then?
Should I do something in onResume() like check there whether I've received a response from that AsyncTask server call, which I should probably save to shared prefs rather than process and present results to the user, and if so, display that alert to the user?
Please advise?
An AsyncTask will still run after an Activity is navigated away from. This means that onPostExecute() may be called when an Activity is no longer visible and any UI changes that should be done in onPostExecute() will result in an Exception, most likely a NullPointerException or an IllegalStateException.
To remedy this, you will have to either manage the AsyncTask yourself by stopping it in your activity's onPause() and restarting it in your activity's onResume() or place the task in a retained non-UI Fragment. In my opinion, these solutions are a little hacky. I would highly recommend using an AsyncTaskLoader in place of an AsyncTask when the UI will be modified after the task executes. AsyncTaskLoaders use a LoaderManager which handles the Activity/Fragment lifecycle for you.
There are many resources that demonstrate the correct implementation of AsyncTaskLoaders, I have listed some of them below:
Android developer documentation
Alex Lockwood's blog post
Wolfram Rittmeyer's blog post
I used the AsyncTaskLoader class in one of my open source applications, CrimeTalk Reader, to load web data using Jsoup and put the resuts in a ListView. The class that uses it can be found on Github.
In instances where you want to run a long-running task without UI interaction, you may want to check out the IntentService class.
What is the best place in fragment lifecycle to call REST service for example to fill ListView with received data ? There are onCreateView, onActivityCreated and onResume. My first thought was to call network service as soon as possible, so on the end onCreateView, but i'm confused about this.
Just don't bind REST calls to your UI. You should split up UI and business logic responsible for getting and updating data. UI is just a facade so you shouldn't try to call any network services from UI. You can implement any of the patterns described by Virgil Dobjanshi in IO Talk
I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!
Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.
Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.
I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.
Is it good practice to use Otto event bus bi-directionally?
I mean, send events from controller to view, and view to controller?
Or is it just meant to publish results meaning its purpose is only events from controller to view?
Thanks
Good question. Here is my thoughts on this. I use Otto for a while and use it bi-directionally. From my experience there is nothing against doing this. I have just defined couple of rules helping me keep everything under control.
One-to-many pattern must be confirmed. I mean here, that one producer should normally notify multiple subscribers. Of course, at different point in time there can be zero or more subscribers. But if you have a case, where by-design maximum number of subscribers is just one, then you trying to dispatch rather a "command", than an "event". For such cases I would use a direct call instead of posting a event.
Another thing to avoid should be a situation, when one event triggers another event, which, in turn, triggers first event again. You can run in infinite event chain here. This might happen when same class has the both subscriber and producer methods. If I have such classes, I try to keep those methods as independent as possible.
And of course I always use Android components' lifecycle to register and unregister publishers and subscribers dynamically. I start with onResume() and onPause() methods and, if needed, I'm going up to onStart() or even onCreate().