Finding Caller of ContentResolver.notifyChange - android

I have an activity for updating a table which holds configuration data for a service. I am using a SimpleCursorLoader and the SupportLoaderManager to update the listview in that Activity. I destroy the loader in In the activity's onDestroy. This may not be relevant, since the issue I'm seeing happens even without visiting this Activity.
I have a service as well, that registers a ContentObserver on the URI to the table that is modified in the Activity above. It reads its configuration, sets itself up and registers a ContentObserver on that table in the Service's onCreate. In the Service's onDestroy, that listener is unregistered.
This is only 1 of a few databases/tables that I have in my system. What I'm seeing is that when I make an update to a completely different table, the ContentObserver on this configuration URI is being triggered. The Authorities are completely different, they interact with different SqlLite databases, they're even running in different processes within the application. I removed all "notifyChange" calls that I could find which would trigger the ContentObservers, yet they still are firing.
My question is, is there any way to find out who is calling the notifyChange that is causing the ContentObserver to fire? Does the system outside of my application have any reason to notify observers of a URI? I'm trying to track it down, but without having any clue where the notify is coming from, I'm running into a wall.

Again, only a few hours away from the answer. I apparently didn't find all of the notifyChange calls in my code. The offender was:
getContentResolver.notifyChange(new Uri.Builder().build(), null);
which was calling notify on a blank Uri. It doesn't appear to be noted in the documentation, but the behavior I saw was that this triggered all of the registered ContentObservers to be fired in my application. I got that line out of there, and now everything is notifying as it should.
The answer to my original question, "Is there a way to find out who called notifyChange on a Uri?," I think the answer is "Look harder for calls to notifyChange in your code. Other than that, you're on your own."

Related

Android - Is it true that the onCreate() method of an app's android.app.Application subclass will not always be called?

I recently saw a presentation about common misconceptions about Android lifecycles. At one point, the presenter claims that the onCreate() method of the registered android.app.Application subclass may never be called if the backup manager is running, and instead only the base class will be used, as could be confirmed by type checking the return value of ContextWrapper#getApplicationContext().
I couldn't find any documentation about this anywhere, and I have never encountered this before. The presenter seems to claim that this is not a bug, however, saying that this behavior is "sort of documented, but very hidden."
I'd really like to know whether this is true, because the application I work on relies heavily on its registered android.app.Application subclass and I would expect this behavior to cause serious problems. Can I rely on the onCreate() method of my app's registered android.app.Application subclass always to be run before all of my other Android components are started?
The only way I've ever encountered onCreate() never being called is when:
The activity is a background service or receiver that has already been initialized
The activity has left foreground, but is still in recent / memory. E.g activity skips to onPause() then onResume()
This is from Android Dev documentation :
Restore the calling application from backup. The data will be restored from the current backup dataset if the application has stored data there, or from the dataset used during the last full device setup operation if the current backup dataset has no matching data. If no backup data exists for this application in either source, a non-zero value is returned.
If this method returns zero (meaning success), the OS attempts to retrieve a backed-up dataset from the remote transport, instantiate the application's backup agent, and pass the dataset to the agent's onRestore() method.
To me it doesn't make any sense that an application can restore its dataset without re-initializing an activity. More or less it definitely doesn't make sense that the onCreate() gets bypassed. An activity will always follow its lifecycle and I haven't encountered any time where it doesn't. If a backup or restore is occurring at the time, then it could make sense. Only way is to test it I guess.

How to handle LifeCycle issues when using callbacks

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

Prevent ContentObserver from getting a "specific" change on URI

I have an app that allow users to edit the ContractsContacts DB.
When a user edits the ContractsContacts DB using the functions of my app, I don't want that my ContentObserver is aware of that changes.
I want my ContentObserver to be aware only of changes generated from other apps. For example when users edit ContractsContacts DB by using the mobile apps.
So, my question is: is there a way to tell the ContentObserver "hey, don't listen to this change, because I'm aware of it, dont call your onChange() method":
The only solution I found is:
unregister the ContentObserver before starting the "edit function" of my app
register again the ContentObserver after my function did all its work.
Thank you
This is not your ContentProvider, and so you cannot prevent Android from updating registered observers. Your observer is nothing special to Android.
So, in addition to your unregister-modify-register flow, you could tell your observer to ignore the next update (have it track that in a boolean or something), then modify the data. The observer would skip whatever work it normally does when that boolean is set, just flipping it to false to pick up future changes.
Both of these suffer from race conditions (you and another app modifying the provider at the same time).
Ideally IMHO, you modify whatever logic is being triggered by the observer to live with triggers coming from your own updates, so that all changes of the data are treated equally, whether coming from your app or not.

Objects/components to close or delete on the onDestroy callback

I am still not clear about this point and I did not find really clear explanations: what are the objects/components that should be closed/deleted on the onDestroy callbacks?
From what I read, there would be at least:
listeners to remove
database handler to close
But are there other things to handle?
Thanks!
There is no reason to explicitly close something only because it's a database handler or a listener. .
You would want to kill the things that you do not need anymore but that can be mistakenly called after onDelete (or onStop) occured.
Those can be: services because thay are likely not to be killed by OS and thus run while no one needs them. Broadcast receivers because they can get a message from the system and try to process it while your activity is already invalid. Handlers because they can receive messages from other part of your app. Listeners and databases connections because other parts of your app can inadvertently use them while the activity that provides them is already in invalid state.
So, it's a matter of logic what to close in onStop / onDestroy and not a matter of classification.
Exactly what you typed. When that callback method occurs then you will want to close any database connections and anything you are listening to, like SMS messages.
You can also delete temp files during that event. Or maybe you want to send an email off as well. It is really whatever you want but the dev docs really recommend that you close DB xnets and Service xnets.
Lazy developers just leave this method empty.

(Reflective) Method call delivers same old results until app is force stopped and restarted (...is there something automatically cached somehow?)

I have a strange problem and hope that someone of you has an idea what happens here.
My app structure is as follows:
I have a main service which registers a broadcast receiver and listens to intents like screen on/off etc. So this service runs indefinitely.
When such an intent is received, I start another service which does the action
Inside this action service I launch an AsyncTask to fetch battery related stats via reflection. After the service is done, it calls stopSelf().
So everything works as expected, except that when the battery related infos have been fetched one time, each subsequent call of the AsyncTask/Reflection methods deliver exactly the same result which has been delivered before.
The battery stats have of course been updated in the meantime, but I do not get the new updated numbers, but always the stats from the first method call.
That is until I go to settings and force stop and restart my app, then I get updated battery statistics again, at least one time, because after that I'm stuck with these numbers again.
So my question:
Could it be that the results of the reflection call are automatically cached somewhere and that each subsequent call doesn't really fetch the new data but just delivers some cached results? What else could be the problem?
I'm thankful for any ideas, I you need some code lemme know :)
Ok, I've found a fix to this :))
The library of Better Battery Stats uses the singleton pattern for a needed class.
It also includes an invalidate() function, which sets the singleton instance to null, so that at the next getInstance() it gets reinitialized.
I'm using now invalidate after each statisitics fetch, and now I get the updated statistics on every call. Although I am still not sure why the Singleton pattern seems to be the root of this issue, it should also work with having one initialized singleton instance...
Well, one does not simply have to understand everything ;-)

Categories

Resources