How to handle LifeCycle issues when using callbacks - android

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

Related

Is Firebase onDataChange Listener always automatically removed after application is closed?or,not and billing is also increasing?

I am adding ValueEventListener in my activity of android.I am worrying if my app crashes or anyhow, onDestroy isn't called then my listeners may not be
removed manually.I also used system.exit in somewhere,I didn't used them in service though .now I am worrying if they aren't removed and my application is closed,will they be still connected and increase my firebase billing?
This is a 'yes but no' answer, according to the documentation, all listeners are registered on the server which invokes a trigger to send the updated information.
Since the listener is not unregistered, it is therefore not 'removed'. Instead, the server will detect that the client has timed out after a few attempts and will stop sending requests.
Effectively they are the same thing, only delayed. relaunching the app will not reconnect to the listeners if the session ID does not match.
When you are using a ValueEventListener, which means that:
Classes implementing this interface can be used to receive events about data changes at a location.
If you are using addValueEventListener(ValueEventListener) method, it means that you are listening for changes in real-time. This also means, that if you don't remove the listener according to the life-cycle of the activity, the listener will remain active, until Android OS will eventually close it. This means that as long as the listener is active, the "onDataChange()" will always fire providing a snapshot of the data at the location the reference is pointing to.
It's true that there is no guarantee that "onDestroy()" will be called. So most likely you should consider using addListenerForSingleValueEvent():
Add a listener for a single change in the data at this location.
Case in which there is no lister that has to be removed.
According to your problem. You are passing a callback to get the data changes. So simply follow the Activity lifecycle, onResume() you can set the callback listener & onStop() remove the callback listener. If your app crash, there is no guarantee that your activity going to maintain the lifecycle, so you must handle the crash at your own. Simply use try catch

Where to call IntentService to populate data into SQLite for RecyclerView Adapters in Android

I have an Activity that has a fragment which is full screen RecyclerView. The fragment implements LoaderManager.LoaderCallbacks<Cursor>.
I have an IntentService that goes out and fetches data from an API, deletes any existing data in the local SQLite database, and then stores the new data all via a content provider.
The Loader then Loads whatever data was put into SQLite into the RecyclerView.
My question is:
Where would be the most efficient place to put my code to fire off the IntentService?
Just wondering if there are any conflicts that could arise if placed in an inappropriate place.
Currently, I have it as the last lines in OnCreate() in the Activity:
// Fire off service to get data
Intent i = new Intent(this, MyService.class);
startService(i);
Other places I was considering putting it:
In the OnCreate() in the fragment.
In the OnActivityCreated() in the fragment.
In my opinion, running it in onCreate of your activity is just fine, however in this case, your RecyclerView may present outdated contents to the user. So you should somehow notify your RecyclerView from inside that IntentService and make it to re-query the database.
Running that service in onCreate of that fragment or OnActivityCreated() wouldn't give you any performance gains.
To bring a better user experience to your users, I would suggest you that use pull-to-update libraries to fire off that service and update the list whenever the user drags it down. Just like Instagram app.
First, I would like you to take a look at this answer in SO that also has links to android documentations.
Also from the documentations, an IntentService has few limitations:
An IntentService has a few limitations:
It can't interact directly with your user interface. To put its results in the UI, you have to send them to an Activity.
Work requests run sequentially. If an operation is running in an IntentService, and you send it another request, the request waits until the first operation is finished.
An operation running on an IntentService can't be interrupted.
However, in most cases an IntentService is the preferred way to perform simple background operations.

Using AsyncTask to preload data for a new Activity

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.

Background job with data from background to foreground in Android

I have an application that needs to track my location, read a sensor while doing this and update a Activity with information (i.e. my current speed). The Activity also has a "stop" button, that allows the user to cancel the background job. The data collection should continue if the user navigates away and notification should allow the user to get back to the view showing the information.
So far I have:
a Service
that has a private static MyService instance field and a getter for it
it sets instance = this in onStartCommand(...)
it also has a getter for the current data (wrapped in an object)
it provides a goForeground() method that calls startForeground(...) and shows a notification (goBackground() does the inverse)
an Activity
that calls MyService.getInstance() in onCreate(...), if it returns null it creates the service with startService(someIntent)
an updateViews() method that pulls the data from the Service and uses a Handler to schedule calls to itself to update the Views every 500ms
This works.
However I'm pretty sure that this is not the recommended way to do this. It's ugly as hell and all calls to the return value of getInstance()are wrapped in a not null check. Additionally all the work is happening in the UI thread (which will certainly cause problems when I add more calculations to the Service). Also, I would like to get rid of the Activity polling the Service for data.
What is the recommended way to do this?
The Android documentation is not very clear at this point and everything I found with Google was either outdated or solved different problems. Please keep in mind:
my background job is essentially endless and will not be "finished" at some point in time. Only the user can decide this (this rules out an AsyncTask, or not?)
I need to pass some non primitive date from the background to the foreground
I need to control the background from the Activity
the Activity should be able to "reconnect" to the background if it is closed and reopened
As you said pulling the data from the service is not the best practice, fortunately there is such thing called a BroadcastReceiver, this class wake up when an intent sent and the receiver is configured to receive it (in the manifest).
This allows your service sending the data when ever its ready, or the other way, your activity can send a request for new data.
note that an intent can hold data, thus you don't need to hold any static instances to services, just pass you data to an intent

Using an intentService or are there better ways?

I'm creating an app that will do the following:
If a mail comes in with a messageword. It needs to start to locate the phone by GPS functionality. after that it must show the result to the user.
I already have it working with using a broadcastreceiver for fetch the message. After that is starts an Activity. If don the userinterface is updated.
I have here two problems:
1) if the screen rotates all variables are set to zero... well can solve that with saving variables at onPause() and read those values at onResume()
2) if the user use the backbutton... the thread is cancelled.
Actually I want that the user can't cancel the GPS-action.
Is it a good idea to use an Intentservice for this?!
-message comes in
-BroadcastReceiver fetch the message and start the intentService
-if the processing is done... I can start an activity with the results (and the service is closed automaticly after the processing is done?!
Is there maybe a better way to attack the problem?
You certainly can and should use an IntentService for long running operations in the background. However, if the user backed out of your activity, they most probably did this for a reason, and popping up an activity with results they might not care about anymore, might not be such a good strategy. You could cache the result instead, and show it next time the user opens your activity.

Categories

Resources