onPostExecute() of AsyncTask never get called in AndroidTestCase - java

I am writing a very simple unit test case for my Android project, the test case simplely execute a AsyncTask which does network operation in background. I am extending AndroidTestCase class for my test case:
public class MyTest extends AndroidTestCase{
//use CountDownLatch to perform wait-notify behavior
private CountDownLatch signal;
#Override
public void setUp() throws Exception{
super.setUp();
//I use CountDownLatch to perform wait-notify behaviour
signal = new CountDownLatch(1);
}
#Override
public void runTest() throws Exception{
String params = "some params";
//MyAsyncTask does the networking tasks
new MyAsyncTask().execute(params);
//wait until MyAsyncTask is done
try {
signal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class MyAsyncTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
//Do networking task e.g. access a remote database
}
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
//this never get called when run this test case, why?
Log.i("Debug","post execute");
signal.countDown();
}
}
}
As you see above, I am using CountDownLatch to perform wait-notify behavior.
After MyAsicTask starts, I invoke signal.await() to wait for MyAsyncTask to finish.
In onPostExecute() callback of MyAsyncTask, I call signal.countDown() to notify that the task is done.
But when I run this test case, the onPostExecute is never called, why & how to fix it?
========Update==========
After I added Thread.sleep(30*1000) as the last line in runTest(), I can see more logs from network operations. It proves that the teardown() is invoked before my network operation finished. I did nothing in tearDown(), android test framework. invokes it automatically.
Seems my wait-notify by using CountDownLatch is not working... Why?

Since I had the same problem... here's what solvede it for me.
Instead of letting the class extend AndroidTestCase I let it extend InstrumentationTestCase.
Then i start the asyncTask like this:
runTestOnUiThread(new Runnable()
{
#Override
public void run()
{
startAsyncTask();
}
});

Be sure that your doInBackground method is not the reason this problem. Try this sample task. And share the log result please.
private class MyAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.i("Debug", "onPreExecute");
}
#Override
protected String doInBackground(String... params) {
Log.i("Debug", "doInBackground");
return "operation finished";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.i("Debug", "onPostExecute");
signal.countDown();
}
#Override
protected void onCancelled() {
super.onCancelled();
Log.i("Debug", "onCancelled");
}
}
Edit: I wondered that there may be a problem while working with AndroidTestCases and AsyncTasks. I just copied your code to my project and tested it with an AsyncTask(see my task above). On every launch after doInBackground, onPostExecute method is called successfully. I simulated a long running task with sleep 2 minutes, and that also entered to onPostExecute method. And tearDown method invoked after onPostExecute.
So, your problem here is probably a loop inside your doInBackground method. Or it is cancelled somehow and task's onCancelled method invoked.

I think your network operation is very time consuming process so it takes so long time that why its can not called onPostExecute() method.

The onPostExecute() is supposed to be run in the caller thread of execute(). If that thread becomes suspended by calling something like signal.await(), the onPostExecute() won't be able to run. So you cannot have signal.await() after calling execute().

Related

AsyncTask executes at the end of the function

I am using AsyncTask so that the function I want executes immediately and does not wait till the end to be executed..
but for some reason I don't why it executes in at the end of all process!
I looked at other solutions and found that Thread should be executed at the end but for AsyncTask it should be executed whenever it is called..
here is my code
private void LogMeIn()
{
string CheckValue;
// Here I call the AsyncTask
new GCM().execute(null,null,null);
//gcmRegID is a public variable and should has GCM value assigned to it by now, but I it is empty as GCM() has not been executed yet
//This is always return empty string
CheckValue = gcmRegID;
}
This is the AsyncTask that wait till the end to be executed
//This is the AsyncTask
private class GCM extends AsyncTask<String, String, String> {
private String resp;
private Context context;
#Override
protected String doInBackground(String... params) {
GCMHelper gcmRegistrationHelper = new GCMHelper (
getApplicationContext());
try {
gcmRegID = gcmRegistrationHelper.GCMRegister("123456789");
} catch (Exception e) {
e.printStackTrace();
}
return gcmRegID;
}
}
I tried to put the call for GCMRegister in onPreExecute but i get an error that it has to be in the main thread
it is like i am going in circles....
the call has to be in the main thread and the main thread will be executed at the end of the function...
it is like no way to get the GCM code in the middle!!!!
How can I make this AsyncTask executes when it called??
Thanks
Without seeing more of your code it's hard for me to tell but I would take a look at where you are calling LogMeIn(). Because your AsyncTask and call to execute are nested in the LogMeIn() function, it won't be called until LogMeIn() is first called.
AsyncTask goes through the following 4 steps in order after calling execute():
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
These can be added to your GCM class and used however you like. Note that you don't call them directly. AsyncTask does it automatically after calling .execute().
Only the tasks specified in doInBackground(Params...) are executed on a background thread. The rest are all done on the UI(or main) thread. I would suggest putting either a toast or a log inside onPreExecute() and in onPostExecute() to debug where/when GCM().execute is actually being called and then to tell you when the background task is complete. This will give you a better idea of what is going on.
Make sure you aren't trying to update the UI in doInBackground().
Would love to help more but we would need to see more of your code.
#Override
public void onPreExecute() {
super.onPreExecute();
Log.d("GCM", "onPreExecute: called");
}
#Override
public void onPostExecute(String resultOfDoInBackground) {
super.onPostExecute(resultOfDoInBackground);
Log.d("GCM", "onPostExecute: called");
}
AsyncTask keeps a queue of tasks and a thread pool,the thread pool execute the tasks one by one,so if you have too more tasks ,you will find it not execute your tasks immediately.
And in one process ,all your AsyncTask share one thread pool.In this case,you should make one task queue by yourself,you can just use HandleThread to execute a timely task.
Try placing your new GCM().execute(null,null,null); in the protected void onCreate(Bundle savedInstanceState) method. this way it will be called once the app is ran. This way you will have your GCM id before you get to the LogMEIn method.
Try this -
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new GCM().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
} else {
new GCM().execute();
}

Wait for thread, get its result, show progressbar in the process and do not block UI Thread

So as the title probably suggests - I've done a lot of research on the topic, but I am still confused and unable of achieving what I want.
In very simplified scenario, I have a LoginActivity in which is method boolean validateUserInput(String mail, String password) and I want to do the check input in the separate thread. I suppose I will extend it in the future to do the log-in itself as well (http request). Naturally I would like to get boolean value if the operation was successful or not - and in the process of operation I want to show progressbar dialog.
Make a thread, run the code, return its result, show the progress bar in a meantime, piece of cake right?
Should I use asynctask or runnable? How do I do this so I do not block the UI thread?
This is code I tried to use in LoginActivity:
new Thread(new Runnable() {
#Override
public void run() {
mUserInputValidated = validateUserInput(inputEmail.getText().toString(), inputPassword.getText().toString());
}
}).start();
if(mUserInputValidated)
{
attemptUserLogin(inputEmail.getText().toString(), inputPassword.getText().toString());
}
I also tried asynctask approach, but ended up with various errors since I started progress dialog in onPreExecute() and ended it in onPostExecute(), using reference like LoginActivity.this where was the problem with memory leak which I was also unable to fix?
I assume this is pretty usual scenarios, since almost every app use it, so - what are common approaches? How do I fix my code?
You have to use asynctask this will take the work off from main-thread and place it on background thread once the work is done
This is a sample that shows how to do it
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed"); // txt.setText(result);
// might want to change "executed" for the returned string passed
// into onPostExecute() but that is upto you
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
Reference

Java AsyncTask passing variable to main thread

I have been trying to change textView after I'm done networking in an another thread with AsyncTask. I've tried countless solutions, but none have worked so far.
The only way I was able to achieve my goal was to use .get(), but it stops the UI thread for a while, and that's something I don't want.
I've also tried using the AsyncTask as an outer class, and using a wrapper class in the middle.
So my question here is, what is the easiest way to get hold of a variable used in doInBackground() and onPostExecute(), without freezing the main thread?
Here is a way to do it. You can give a callback in parameter of your async task, do whatever you want and them get the value back from the async task.
Callback interface :
public interface AsyncTaskCompleteListener<T> {
public void onTaskComplete(T result, int number);
}
AsyncTask :
public class LoadURL extends AsyncTask<String, Process, String> {
private AsyncTaskCompleteListener<String> callback;
public LoadURL(AsyncTaskCompleteListener<String> cb) {
this.callback = cb;
}
protected void onPreExecute() {}
protected String doInBackground(String... arg0) {
// do something
return content;
}
protected void onPostExecute(String content) {
if (callback != null)
callback.onTaskComplete(content,number);
}
}
Activity :
public class LoginActivity extends Activity implements AsyncTaskCompleteListener<String> {
#Override
protected void onCreate(Bundle savedInstanceState) {
LoadURL loadUrl = new LoadURL(LoginActivity.this);
loadUrl.execute(...);
}
#Override
public void onTaskComplete(String result, int number) {...}
}
in onTaskComplete, you can easily modify your TextView
Just update the UI in the following code inside the AsyncTask:
#Override
protected void onPostExecute(Int result) {
textView.setText(result.toString());
}
Check this link if you need extra help.
You should return the variable from doInBackground(). Framework will make sure you will get the returned value in onPostExecute().
onPostExecute runs on the UI thread so you should be able to refresh any UI element here.

how to know when asynctask is finished

public class Calculate extends AsyncTask<Void, Integer, Integer> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... arg0) {
int a = 1;
int b = 2
return a+b;
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
my app use asynctask class (below), and a function to call this class,
my question is how to know when this class is finished ? every time i check, its always Running !
In your onPostExecute(...) method, you could simply call a method in your caller Activity which would set a boolean terminated_activity to true. You can do this in several ways, most probably the easiest ones are Intents combined with a Handler, or a local BroadcastReceiver.
An example on Handlers and Intents is in an answer I posted today in other question, here.
A nice explaination on local BroadcastReceivers is here.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Directly from the docs

onPostExecute not called after completion AsyncTask

For some reason my onPostExecute() is not called after my AsyncTask finishes.
My class decleration:
public class setWallpaperForeground extends AsyncTask<String, Integer, Boolean>
My onPostExecute():
protected void onPostExecute(Boolean result)
Everything works fine, my doInBackground() completes successfully and returns a Boolean but then it just finishes.
Thanks
Did you start the task with execute() method? The onPostExecute wouldn't run if you just invoke the doInBackground.
Did you create your AsyncTask on the UI thread? Also add an #Override annotaiton on your onPostExecute() method to make sure you declared it correctly.
Found/Made another nasty mistake:
If your params of onPostExecute(Param param) don't match the one you defined with extends AsyncTask<...,...,Param> and you didn't use the #Override annotation, it will never be executed and you don't get a warning from Eclipse.
Note to myself:
Just always use the #Override annotation and Eclipse will help you.
Another easy way to avoid all named mistakes:
in Eclipse: Right-click in code > Source > Override/Implement Methods
After having the same problem and none of these answers helped me, I found out that my UI thread was blocked (I used a CountDownLatch.await()) and therefore the onPostExecute() method that is supposed to be called by the UI thread was never called.
Made another nasty mistake that can result in this same error. When defining the AsyncTask and calling it, I was not calling execute but was calling doInBackground
new AsyncTask<String,Void,Void>() {
....
}.doInBackground("parameter");
rather than
new AsyncTask<String,Void,Void>() {
....
}.execute("parameter");
I have faced the same problem. None of the above solutions worked for me. Then i figured out the problem maybe it helps someone else .
In UI thread i call the following codes:
public class XActivity ...{
onCreate(){
....
new SaveDrawingAsync(this).execute();
while(true)
{
if(MandalaActivity.saveOperationInProgress){
continue;
}
super.onBackPressed();
break;
}
...
}
}
My AsyncTask class definition :
public class SaveAsync extends AsyncTask<Object, Void, Void> {
#Override
public Void doInBackground(Object... params) {
saveThem(); // long running operation
return null;
}
#Override
public void onPostExecute(Void param) {
XActivity.saveOperationInProgress = false;
}
#Override
public void onPreExecute() {
XActivity.saveOperationInProgress = true;
}
}
in the above code onPostExecute is not called. It is because of an infinite loop after asynctask execution .
asynctask and inifinite loop both waits eachother to finish. Thus the code stucks!
The solution is changing the design!
I had the same behaviour, and the cause was that I have been posting a lot of messages as a progress inside doInBackground with following code:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// .. some UI updates
}
});
this must have overloaded main thrad message queue, and caused long delay before onPostExecute would get called. The solution was to post only once every second.
For me it was user error. I was ending the AsyncTask by invoking cancel(true) on it and not reading the documentation closely enough to know that onPostExecute is not called in this case, onCancelled is.

Categories