On rare occasion, I'm getting this mysterious RuntimeException in one of my AsyncTasks. I have multiple places where I implement AsyncTasks in my app, but no matter how much I dig into these errors I can't seem to get any info about why this RuntimeException is being thrown or what thread it is happening in. Based upon the "completedAbruptly=true" I'm guessing that there's an uncaught exception in the async task, but I don't even know where to begin to try to figure out where... ideas? Thanks!
completedAbruptly=true happens when the executed task throws an exception. And the task of an AsyncTask is executing the doInBackground method.
I suggest you wrap your doInBackground code into a try/catch block and let it print exceptions that occur.
protected Void doInBackground(Void... params) {
try {
// ----------
// do stuff
return null;
// ----------
} catch (Throwable t) {
Log.e("AsyncTask", "OMGCrash", t);
// maybe throw it again
throw new RuntimeException(t);
}
}
That should show you the reason all this happens.
According to the source code, completedAbruptly is a sign that the thread finished due to user interaction. I would guess that the exception happens when an activity is finished before the async task completes. It should be trivial to discard this possibility: just replace one of your AsyncTasks with an infinite loop and press "back" on the emulator.
Related
val parentScope = CoroutineScope(Dispatchers.Main)
parentScope.launch {
try{
launch{ // child scope
//code ....
throw CustomError("error", null)
}
} catch(cause: CustomError){
// It did not get executed
}
}
In the above code snippet the app got crash. The exception thrown from it is not caught into the parentScope catch block.
But if we replace the above childScope with
supervisorScope or
coroutineScope or
withContext or
runBlocking
it catught the exception.
parentScope.launch {
try{
supervisorScope {
//code
throw CustomError("error", null)
}
} catch(cause: CustomError){
// It get execute when withContext/supervisorScope
}
}
Why exception thrown from child scope(launch) is not caught by parent catch block?
Exception:
FATAL EXCEPTION: DefaultDispatcher-worker-1
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Disclaimer: this question has been edited which greatly affected the answer. Original answer is below.
launch() is used to run the code asynchronously, in a separate coroutine or in the background. CustomError is not really thrown from within try...catch. Code which invokes launch() doesn't even wait for it to start executing - it only schedules the code to be executed and then immediately progress further.
This is similar to starting a new thread. If the thread throws, you can't catch this in the code that created or started the thread. Code that started the thread and the code inside the thread are running in two separate execution contexts.
All other functions you mentioned (coroutineScope(), runBlocking(), etc.) run synchronously - they wait for the block of code to be executed, they wait for its result. Inner block of code runs inside the same execution context as the outer one. For this reason exceptions could be propagated as usual.
Original answer:
In your first example there is really no parent-child relationship. Both parentScope and childScope are created separately and they run independently of each other. Simply because you put one code block inside another doesn't mean they are in any way related.
withContext() is different, it uses the current scope (parentScope) to execute the code.
In other words: whenever you use someScope.launch() this is like explicitly asking to switch to entirely different execution context.
When, for example, a NullPointerException occurs after calling the RxJava map operator, the app doesn't crash. I want the app to crash when this happens so it can submit reports to crashlytics etc.
I tried using Exceptions.propagate() in a try/catch block but that didn't work.
The only solution that I found was throwing a RuntimeException in my error handler.
override fun getCategories(): Single<List<Category>> {
return ApiManager
.getCategoriesService()
.getCategories()
.map { categoriesResponse ->
throw KotlinNullPointerException
categoriesResponse.categories?.map { categoryResponse ->
CategoryMapper().mapFromRemote(categoryResponse)
}
}
}
The NullPointerException thrown inside the map operator does not crash the app.
If I call it before the return statement it crashes the app.
If I call it before the return statement it crashes the app.
It crashes because getCategories method is running on Android's main thread to build the rx chain.
The NullPointerException thrown inside the map operator does not crash the app.
It doesn't crash the app because this chain is being subscribed to a thread that is not Android's main thread. E.g. your chain has .subscribeOn(Schedulers.io()).
The only solution that I found was throwing a RuntimeException in my error handler.
That's the expected design of your chain as per this document:
An Observable typically does not throw exceptions. Instead it notifies any observers that an unrecoverable error has occurred by terminating the Observable sequence with an onError notification.
So rather than catch exceptions, your observer or operator should more typically respond to onError notifications of exceptions.
Ok so I think the closest to what I want to achieve is by calling Exceptions.propagate(throwable) in the error handler called in onError.
Thanks for pointing me in the right direction #Gustavo #TooManyEduardos2
I have an AsyncTask, and in its doInBackground method I call a method in another class:
#Override
protected ArrayList<CustomClass> doInBackground(ArrayList<CustomClass>... array) {
ArrayList<CustomClass> retorno= DataNetwork.GetCustomClassArrayList(array[0],(...more parameters...));
return retorno;
}
In DataNetwork I have that method, which does a REST call, and returns a result. I am forced to use a library that makes the REST call (I think it uses Volley, but I am not sure. To call this library, I have to make an Intent, which is passed to the method makeRESTCall):
public static ArrayList<CustomClass> GetCustomClassArrayList(various params goes here){
ArrayList<CustomClass> toReturn;
//some parameters processing
library.makeRESTCall(Intent intent){
//processing the answer
toReturn=processAnswerJSONResponse();
}
return toReturn;
}
This way, I get to the return toReturn line, before answer from REST is processed. So, I tried to make a Thread, and use the join statement. The GetCustomClassArrayList method (well, most of it, until the t.start()) is now inside a Thread. The end of the method is now:
(...)
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return toReturn;
The execution calls t.join() immediately after t.start(); and toReturn is null.
Maybe is a noob question, but using the method join() always worked for me, and waited for the thread to finish before entering the return statement. No exception, no error. It just doesn't wait for the thread to finish.
Why is not working now? What can I do to wait for the toReturn variable to be fulfilled before entering the return statement?
Thank you.
The problem likely stems from using a library which is already returning the response asynchronously, so your AsyncTask is not blocking. Check the library documentation.
AsyncTask is not like a normal thread. It is specialized to execute one time, blocking if necessary in the doInBackground method, then returning results to be handled in the main thread. If your 3rd party REST library has a synchronous version of it's calls, you could use that in your AsyncTask, but it will likely be less efficient than the library's built in functionality.
With reference to the following code.
for (Future<Long> future : list) {
try {
sum += future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
Now when i call future.get will this be blocking call? So if i am executing this on the Main Thread of and android application will this cause an ANR exception ? I notice the Interrupted exception is also thrown, so does this mean their is a sleep called on the thread in the get function ?
Yes, documentation of Future.get() says:
Waits if necessary for the computation to complete, and then retrieves its result.
so, it will block until results of computation are available, or the computation was interrupted (cancelled or resulting in exception).
It may cause ANR if your computations take long time to finish.
Again, from documentation of Future.get():
#throws InterruptedException if the current thread was interrupted while waiting
Now, since you call Future.get() from main thread, I suspect that it is the Android system which interrupts your main thread in an attempt to make it responsive again. But it may also be caused by another thread of your application - it's hard to tell, since you haven't specified what your application does, what threads does it create, when, do you use ExecutorService (and if so, which implementation), and so on.
No, FutureTask.get() (which I believe is the implementation of Future you're using) does not call Thread.sleep(). Instead, putting the thread in waiting mode is done via thread parking which causes it to not be scheduled for execution until a signal is given. This may cause in ANR error if done in the main thread. For details of parking mechanism consider reading documentation and this question
You can simply check if future "is done" by calling future.isDone(). Code example:
String result = "";
if (myFuture.isDone()) result = (String) myFuture.get();
You will probably want to check it in an endless loop.
Beware of deadlock with future.get(). If both the MainThread, that call future.get(), and the WorkerThread is synchronized (on the same object) then you get a deadlock.
I am implementing a testcase in Android Juint. I am facing problem in
handling threads. After the successful running of a test case, it will
not wait for child thread to be finished. e.g. If one testcase call
some services in server. testcase will successfully send request to a
server, but it will not wait for a response. Because testcase will
start this request in a different Thread. Currently I am using
following code,
currentThread = Thread.currentThread();
synchronized (Thread.currentThread()) {
try {
Thread.currentThread().wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
After getting response I am using the following code to start the
current thread again.
currentThread.interrupt();
I think this is not the good way to do it. There must be a some other
technique to handle this problem properly. Please let me know as soon
as possible if any one knows solution for this.
Thanks,
Vashishta
In your code the synchronized block never blocks (wait for another thread), because you synchronize on Thread.currentThread() which is a different object in different threads.
You have so synchronize on an object common to all threads: typically an object that contains shared data. Then you synchronize{..} a block od code that manipulates this data.