I'm using an app that uses async tasks to do short term background calculation jobs. These seem to end OK (go through onPostExecute() etc), but in the Eclipse debugger, one or more still hangs around.
Then I found this link - AsyncTask threads never die - so OK, it's about a thread pool and in theory not an issue.
Problems is however, I am also trying to use Google in-app billing code V3, and that appears to throw an exception whenever you carry out a purchase and there's already an AsyncTask thread hanging around. Catching the exception won't help - it still won't do anything.
How can I get around this? What do I need to do to guarantee the old calculation thread(s) have gone?
Found out what is going on here, and it wasn't what I thought. I'll detail it here as it may be useful to somebody. Has nothing to do with other AsyncTask threads and thread pooling.
In the IabHelper class are two functions flagStartAsync() and flagEndAsync(). The aim of these is to produce a single pass gate (bit like wait() and signal() in traditional multi-threading) so only one async operation (that is, communications with Google Play and the server) can occur at a time. If flagStartAsync() get called while something is already going on, it produces an exception. Not terribly graceful, but effective I guess.
The flagStartAsync() 'test and set' gets called at the start of launchPurchaseFlow() among other places, and flagEndAsync gets called in handleActivityResult() - again - among other places. So providing the purchase flow does something that always produces a result, no problem. The problem is - it doesn't always.
If you look at launchPurchaseFlow() there are several paths out that will not kick off the async operation, and if one of those get taken, mAsyncInProgress (the relevant flag) gets left set.
What blew it in my case was that I hadn't checked that the item was already purchased, and 'already purchased' is one of the paths out. Mea culpa, but the problem is that I cannot convince myself that there aren't several other paths that you just cannot avoid at times. What if operation is slow and the 'purchase' button gets pressed twice, for instance? I bet there are others as well. One could catch the exception, and that would stop a crash, but it wouldn't really help if nothing came along to clear the flag in the end. I guess the exception handler could call flagEndAsync() but it has an uncomfortable 'sledgehammer to crack a nut' feel.
It strikes me that this is probably a non-robust piece of code. What I've done for now is call flagEndAsync() in the various ways out of launchPurchaseFlow(), but that is just a temporary fix. I don't know enough about the IabHelper code, but I think it needs more careful thought and I need to analyse it to see everything it does.
Related
I'm familiar with both what an interrupt is used for (to put it roughly: asking the interrupted thread kindly to terminate or at least stop its work as soon as conveniently possible, instead of killing it immediately) as well as how to handle it properly (in most common cases, maybe not the tricky ones).
But I'm having a hard time to understand who (if not my own code) could even call Thread.interrupt() in the first place, and when this "third party interrupt" could occur.
I'm finding lots of information on why anybody would want to interrupt a thread, but hardly anything about who would do that for "my" threads unless I coded it myself.
So on Android, if my own app code does not contain any calls to Thread.interrupt() or something similar like AsyncTask<,,>.cancel(), will any thread I start ever be interrupted at all?
I'm trying to determine whether or not I download data in my android application. I can do this by making the method return true when it does download data, but the listener doesn't seem to be invoked until all other code is finished running (meaning it waits until a pause in your code). So I'm wondering if there is a way to sort of "forcibly" invoke these listeners? Perhaps by creating the listener in a different thread? Would this work or would it be a waste of time? I've already tried to sleep on the main thread for a few seconds, but that doesn't seem to do it either. If it wouldn't work, could you explain when exactly these listeners are invoked? Thanks in advance.
To add onto my question, I am NOT using the realtime database. I understand how realtime triggers work, but I am using the Firestore, so I am only getting data once, not getting realtime updates :)
As you have already noticed with the API calls that deal with reading and writing data are fully asynchronous. This means that the call always returns immediately, without blocking the code to wait for a result. The results come some time later, whenever they’re ready, since it may take some time for this. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available. So Firebase, already is using another thread (other than the main thread) to get the work done.
Calling a synchronous function on your app’s main thread could freeze the app indefinitely, which is a terrible UX. On Android, it could also soft-crash with an Application Not Responding (ANR) dialog.
Doug Stevenson, has explained in his post everything that you need to know about Fireabse asynchronous behaviour and what you need to do/avoid when dealing with Firebase.
In the app I have an activity which has launch mode as singleTask. There are number of use cases which pass through this activity and hence it's called number of times. On stress testing the app by running monkeyrunner script and calling this activity every few seconds causes ANR's.
I guess, the way it's designed where most of the use cases pass through this activity is not correct but I am not in a position to change this design.
Is there anyway ANR's can be suppressed? I mean, adding UI operations to event queue so that it doesn't block main UI thread and doesn't give ANR.
It is unclear from the question what your activity is (or should be) doing. Probably you need a service instead.
It is common to perform time-consuming operations in background threads and deliver the results to the UI thread.
You may use the classes Handler/Looper (it it easir to send Runnables rather than messages), or use an AsyncTask. The AsyncTask is nevertheless tricky, this is discussed here: Is AsyncTask really conceptually flawed or am I just missing something? . AFAIK Google tried to fix the typical bugs and made the new behavior incompatible with the old one (namely, I have seen some misbehavior on the newer Androids that may be explained by the assumption that since some version threads doing asynctask jobs get killed after the activity that started them goes out of the screen).
I can guess that singleTask is your way to fight the fact that an activity dies when the screen turns, and a new one comes. I suggest you use singletons (they survive screen rotation but do not survive a process restart, one more thing that sometimes happens in Android). (The user switches to an app like Camera, takes a big photo, returns back -- and the activity is restarted because Camera needed memory. Have seen this in practice, but that time I did not try to find out if the whole process was restarted.)
Anyway, please add logging telling you when your activity in entered and left, including onNewIntent() and other lifecycle functions (to be on the safe side, I recommend to print the thread names as well). Then you will probably see what is going on.
I have strictly separated the layers between different parts of my Android application.
At some point of execution I am updating my data from xml service on Internet. That updating takes up about 10 seconds and is done completely in the background - meaning the user interface of an application works fine. However further calls to my class (later - DataManager) which is responsible for data updating (after update has been started but not yet finished) makes my application crash. NullPointerException is thrown with objects which NEVER are null.
So I assume that only one Thread can use my DataManager at one time and calls to DataManager from other threads ends up in exceptions.
I tried various combinations of putting 'synchronized' keywords near sensitive methods but it seems that when update is executing - NOTHING can use ANYTHING from my DataManager.
BTW other classes which are related to DataManager during the execution also seem to hold null objects.
I guess I am just missing some kind of design pattern which is used to deal with concurrency problems and maybe anyone can suggest me something?
I had trouble dealing with using the Apache http client because of threading issues and I think your issue could be similar in that respect. What I ended up doing was setting up a callback scheme. This may or may not work for you, of course.
This may seem a bit Rube Goldberg-like to you, but it worked for me.
I would have my UI thread call my data manager object with a method that spawned a thread to go and acquire the data. The method's return value is an object that would EVENTUALLY have the data in it. I would have my activity extend an interface, something like "DataCallbackInterface", with a method that the thread would call after it acquired the data (i.e. the last line in run()). Since that call will inherently be within another thread, you'll need to use a Handler to run anything useful in your implementation of the DataCallbackInterface method. When that method is called, you will know for a fact that the data is there and not rely on any strange synchronization flags to get it right.
I'm looking to find the "correct" way to get a fix on the user's location as a one-time task. At the moment, my execution flow is roughly:
The user presses a button.
The handler (contained in the main Activity code) registers a GPS location listener with the system, set to update as fast as possible, launches an ASyncTask, and finishes.
Pre-execution, the ASyncTask generates a ProgressDialog, effectively blocking any other UI usage.
For it's background task the ASyncTask waits for either a timeout or for a location fix for the GPS.
Post-execution, the ASyncTask either displays some relevant data to the user if a location was found, or displays an error in a toast if it was not. It also de-registers the listener of course.
Now, while this works, there are numerous downsides. Firstly, and quite obviously, all other UI interaction with the app is blocked while a request is being made. This isn't too bad currently, as the app's main function is to perform this task, and there isn't much else to do while it's working - it also stops the user from spamming the button. Additionally, I'm not sure if the post-execution phase of the ASyncTask is really the place to put my location-found logic (it makes an internet call, which is something that itself might be better off inside an ASyncTask?). However, I'm not sure how else to pass back the fact that a location has been found and that the main thread should do something.
I was hoping that someone could inform me as to the "right" way to do this - i.e. is using an ASyncTask like this correct, should there be a Service involved, and how should I deal with the internet-call post-location-found), and perhaps even give some wise words on how in general to deal with the control flow of an app which has to make somewhat "blocking" calls.
I can provide code if needed, might take a bit to get it cut down to a minimum solution.
Blocking calls and blocking UIs are generally to be avoided. See Reto Meier's take on the subject.
Hence, I'd dump the AsyncTask entirely. Disable the Button that the user uses to kick off the fix request. Use a postDelayed() Runnable for your timeout mechanism. And, allow the user to do something (read help, etc.). Use the progress indicator in the title bar to indicate that you're working on getting the location, dismissing the indicator when you get a fix or when your timeout occurs.
(it makes an internet call, which is something that itself might be better off inside an ASyncTask?)
It certainly should not be done on the main application thread. When the location fix comes in, kick off the AsyncTask to fetch the data.