I have an android application where I need to repeatedly get a JSON from a server (which may fail), display the information, and allow the user the change the address of the server. It seemed like the example here would do the trick since I could asynchronously attempt to get my JSON in the doInBackground and just call runAgain() in onProgressUpdate based on a timer, and if the user changes the server address, I can call terminateTask() and start a new GetDataFromServerTask. However, when I call runAgain() in onProgressUpdate, I always get IllegalMonitorStateException. And if check isHeldByCurrentThread() in onProgressUpdate, the result is false. So can anyone expand the example to identify why I don't seem to get a lock? Or if there is a better method to accomplish my task feel free to propose that instead. Thanks!
EDIT: Added complete code using the above reference. (This version is only for testing and does not do everything described above.)
package com.testing.asynctest;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
new GetDataFromServerTask().execute();
}
class GetDataFromServerTask extends AsyncTask<Void, Void, Void> {
private final ReentrantLock lock = new ReentrantLock();
private final Condition tryAgain = lock.newCondition();
private volatile boolean finished = false;
@Override
protected Void doInBackground(Void... params) {
try {
lock.lockInterruptibly();
try {
do {
// This is the bulk of our task, request the data, and put in "result"
Log.d("MyActivity", "Perform Main Task");
// Return it to the activity thread using publishProgress()
publishProgress();
// At the end, we acquire a lock that will delay
// the next execution until runAgain() is called..
Log.d("MyActivity", "Acquiring Lock");
tryAgain.await();
Log.d("MyActivity", "Lock was released");
} while(!finished);
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Void... result)
{
// Treat this like onPostExecute(), do something with result
// This is an example...
runAgain();
}
public void runAgain() {
// Call this to request data from the server again
if ( lock.isHeldByCurrentThread() ) {
Log.d("MyActivity", "Releasing Lock");
tryAgain.signal();
} else {
Log.d("MyActivity", "Lock Not Held by Thread");
}
}
public void terminateTask() {
// The task will only finish when we call this method
finished = true;
lock.unlock();
}
@Override
protected void onCancelled() {
// Make sure we clean up if the task is killed
terminateTask();
}
}
}
The LOG output shows that I do not have the Lock that I expect to have.
com.testing.asynctest D/MyActivity﹕ Perform Main Task
com.testing.asynctest D/MyActivity﹕ Acquiring Lock
com.testing.asynctest D/MyActivity﹕ Lock Not Held by Thread
I understand the meaning of IllegalMonitorStateException, and have tested with isHeldByCurrentThread to verify that I don't hold the lock. I just don't understand what is wrong with this example resulting in me not having the lock. Thanks!