I'm using an AsyncTask subclass for some background processing. The problem is that when I use the class with the .get() method, the ProgressDialog I specify in the onPreExecute() does not show.
I works fine if I use a callback withing the onPostExecute() method.
My first thought was that this was because the .get() waits for the process to complete but that can't be blocking the UI thread either so that's not the case.
Can anyone explain why this behavior is so and if there is a workaround for this ?? I'd really like to use the .get() method if I can.
I initially accepted the other answer but it seems to be wrong.
The .get() method will block the UI thread to wait for the result and any dialogs displayed will also be blocked. This is the expected behavior for this method.
The only alternative is to not use .get() if the background activity is for any noticable amount of time and instead use callback methods to the calling activity.
Calling AysncTask.get() on UI thread will block UI thread execution and make UI thread waiting for AysncTask.doInBackground() to finish. By doing this, you are actually sacrifice the benefit of AsycnTask, all code now are executed synchronously in UI thread and Background thread (still two thread, but UI thread now wait for background thread).
Also bear in mind that you will probably get ANR exception (blocked more than 5 seconds) by calling get() on UI thread.
If you really have to use it, call your showDialog() method before myAsyncTask.get():
showDialog();
myAsyncTask.execute();
myAsyncTask.get(); // <-- UI thread blocked and wait at this point.
dismissDialog();// <-- This line will be executed after doInBackground() finish.
Hope this helps.
Related
I am new in Kotlin, I have a first activity with login, and second activity with recycle view. The data of recicle view is taken from http3 method.
Sorry for my bad english.
How I can show a dialogPopUp when I have code 404, and return in previous one login activity?
OkHttp callbacks are executed on a background thread if you use enqueue and showing a dialog is a UI task therefor it needs to be run on the UI thread.
In your case you can easily do this by running your dialog code using runOnUiThread.
runOnUiThread {
dialogPopUp("Error parameters", mContext ).showDialog()
}
Just as you have done in your else block.
You can also achieve this by using a Handler which has been created on the UI thread.
Update: Taking a closer look at your code I realized you're running fetchJson in a background thread by using the doAsync function. When you use enqueue on a OkHttp.Call you're basically sending it to be executed on a background thread so no need to use doAsync.
If you remove the doAsync you don't need to use runOnUiThread anymore as the callback will be executed on the UI thread.
Can't create handler inside thread that has not called Looper.prepare()
This basically means that you need to use the UI thread when calling this code. The UI thread will need to be used for showing your dialog.
You can do:
runOnUiThread {
dialogPopUp("Error parameters", mContext ).showDialog()
}
I have a bunch of AsyncTasks and their callbacks (listener interfaces) that I dont want to have anything to do with the UI thread.
Reading the answer here: Android : can AsyncTask return in another thread than UI thread?
I am left with the impressin that I can only start AsyncTasks from the UI Thread which means the callbacks that I invoke from their onPostExecute methods will also be in the main thread.
How do I move all this logic away from the UI thread?
First, based on some issues I've had before when trying to run AsyncTasks in an IntentService, I think your assumption that you cannot run an AsyncTask from a non-UI thread is false.
The problem I've found with starting AsyncTasks off the UI thread is not that they don't run or that they cause crashes, but that onPostExecute() doesn't automatically run on the main UI thread after the other stuff finishes. I wouldn't recommend doing it, but you probably could if you wanted to.
But the whole reason AsyncTasks exist are basically to have an easy way to run some code off the UI thread and then be able to alter UI stuff after it's finished. So if you don't want to do anything at all with the UI thread, you shouldn't need to use an AsyncTask at all. If you don't need to run any code on the UI thread, you can just use something like:
new Thread(new Runnable() {
public void run() {
//Do your stuff
}
}).start();
my AsyncTask should wait till event in the UI-thread happen.
so, I started to have simple while loop. However, in some of the devices that caused the UI thread to freeze. so after reading the following answer:
Fatal Spin-On-Suspend/Stuck on ThreadID
[However, it is not quite the same - i put the while in the async-task not in main-activity]
I added Thread.sleep - and it seem to indeed solve the problem.
However, I feel like I'm doing something wrong here...I wonder what is the right way to do it.
Do not ever sleep or block the UI thread. Wait in the background thread of the AsyncTask.
One way is as suitianshi is pointing out with wait()/notifyAll(). Another one is to use a CountDownLatch:
In the UI thread create a latch: CountDownLatch latch = new CountDownLatch(1);
Subclass AsyncTask so that it takes a latch in the constructor and save it to a reference mLatch
in doInBackground(), when you need to wait call mLatch.await(). This will block the AsyncTask
in the UI, when the event you're waiting happens, call latch.countDown()
You should be good to go from here.
My opinion is going to be different...
my AsyncTask should wait till event in the UI-thread happen.
AsyncTask's are great for long running operations like http downloads, long i/o operations, image resizing, or any cpu intensive operation that would freeze the UI thread.
However, Android runs AsyncTasks sequentially and not in a pool by default. More details here.
So if you have an AsyncTask that runs indefinitely, such as waiting for a UI action, you could likely block other AsyncTasks from running. Leading to more deadlock and threading problems.
I would suggest any of the following:
Use a different Executor for your AsyncTask so it runs similarly as it does today, but not to conflict with other AsyncTask items. This is the easiest approach.
Split your AsyncTask up into multiple tasks. The first one does whatever your current AsyncTask does up until the wait. The second one does whatever your current one does after the UI event. The latter task gets queued by the UI that generated the event.
Use a dedicated Thread. Use the Handler class to marshall events back from the thread to the UI thread as appropriate.
AsyncTask is introduced for running things which takes long time. In earlier android OS, it can be done in main thread or UI thread. But now android forces us to do long running things in AsyncTask to make UI thread responsive. If you want during AsyncTask your android UI do nothing then you can simply add progress Dialog during it. Start progress Dialog in onPreExecute() & end it in onPostExecute(String[] result).
Sample code : in AsyncTask
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading, please wait...");
dialog.setIndeterminate(true);
dialog.show();
}
#Override
protected void onPostExecute(String[] result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
// do something with result
}
Thanks
So I am running some threads with a CountDownLatch.
My problem is that when I call latch.await() the UI seems to hang and even UI commands that were called beforehand have no effect. e.g.
btnShare.setVisibility(View.INVISIBLE);
prgSharing.setVisibility(View.VISIBILE);
latch.await()
The first two lines have no effect on the UI.
Any idea why this is and possibly a solution? Thanks.
This is most likely because you are blocking the UI-Thread before it can render the Views again. I think you should look at AsyncTask and maybe put your wait logic in the doInBackground() method, or somehow re-think your implementation.
if the UI hangs it is because you call:
latch.await()
on the UI Thread. You have to avoid blocking call on the UI Thread since those are the cause of ANR
This may have been hidden somewhere in the docs, but I don't remember seeing it:
Assuming everything is running on the same thread, would an activity callback, or any kind of callback for that matter, interrupt a runnable , or even some other callback, executing on the thread, or are they posted sequentially by time of occurance as messages similar to runnables?
It certainly doesn't interrupt execution, at least in the UI thread. For instance, say that you have a Button, and you place a Thread.sleep(10000) in its onClick callback. Well, as soon as you press the button the entire UI will freeze. This wouldn't happen if the onClick callback interrupted the UI thread's execution.
If you wanted to know all the answer of the question you need to use
http://developer.android.com/guide/developing/debugging/debugging-tracing.html
Depends on the Runnable.
All activity callbacks happen in the UI Thread. For example thread for onCreate is same as the thread which calls onTabSelected.
If you are started an AsyncTask, it runs in its own thread.
Try using following Log statement to check your scenario
Log.i("","Thread Id : "+Thread.currentThread().getId());