I have an AsyncTask in Android that runs an asynchronous task on a different thread (I don't have a hand on the Thread life but i can give a callback to the task). Is there a way to wait for the asynchronous task to finish to call the postExecute function of the Asynctask ?
Thanks,
I think what you should do here is define a Listener interface, pass a reference to an object implementing that listener to your AsyncTask, and call this object's method from your onPostExecute.
// this is your interface
// create it in its own file or as an inner class of your task
public interface OnTaskFinishListener {
public void onTaskFinish();
}
// add the following code to your task's class
private OnTaskFinishListener mOnTaskFinishListener;
public void setOnTaskFinishListener(OnTaskFinishListener listener) {
mOnTaskFinishListener = listener;
}
// in your onPostExecute method call this listener like this
// this will call the implemented method on the listener that you created
if (mOnTaskFinishListener != null) {
mOnTaskFinishListener.onTaskFinish();
}
// suppose this is where you start your task
MyBackgroundTask task = new MyBackgroundTask();
// set new listener to your task - this listener will be called
// when onPostExecutes completed -> that's what you need
task.setOnTaskFinishListener(new OnTaskFinishListener() {
#Override
public void onTaskFinish() {
// implement your code here
}
});
task.execute(); // and start the task
I'd rather not to implement a busy-waiting strategy. Both AsyncTask can share a Semaphore that keeps one stopped while the other finishes
Init your semaphore
private final Semaphore semaphore = new Semaphore(0);
Pass that object to both tasks
public AsyncTask1(Semaphore semaphore){
this.semaphore= semaphore;
}
doInBackground(){
//do something
semaphore.acquire(); // <- Waiting till the other task finises
}
And Task2
public AsyncTask2(Semaphore semaphore){
this.semaphore= semaphore;
}
onPostExecute(){
//do something
semaphore.release();
}
Task1
private final Callback callback;
public AsyncTask1(Callback callback){
this.callback = callback;
}
doInBackground(){
//do something
while(!callback.isFinished()){
Thread.sleep(WAIT_TIME);
}
}
Task2
private final Callback callback;
public AsyncTask2(Callback callback){
this.callback = callback;
}
onPostExecute(){
//do something
callback.setFinished(true);
}
class Callback{
private volatile boolean finished = false;
public void setFinished(boolean finished){
this.finished = finished;
}
}
Related
This is the code I used first but in latest Android version AsyncTask class is deprecated and
therefore it was not responding and then I used the Thread class but that class is also not working.
I want the same result as I was getting with the AsyncTask class.
I know that I have to use some executor class of java.util.concurrent package but don't know which and how to use it.
Please help me with this thing.
private static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2016-01-01&endtime=2016-05-02&minfelt=50&minmagnitude=5";
EarthquakeAsyncTask task = new EarthquakeAsyncTask();
task.execute(USGS_REQUEST_URL);
private class EarthquakeAsyncTask extends AsyncTask<String, Void, Event> {
#Override
protected Event doInBackground(String... urls) {
// Perform the HTTP request for earthquake data and process the response.
Event result = Utils.fetchEarthquakeData(urls[0]);
return result;
}
#Override
protected void onPostExecute(Event result) {
// Update the information displayed to the user.
updateUi(result);
}
}
private static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2016-01-01&endtime=2016-05-02&minfelt=50&minmagnitude=5";
earthquakeRunnable runnable = new earthquakeRunnable(USGS_REQUEST_URL);
runnable.start();
private class earthquakeRunnable extends Thread{
String urls;
earthquakeRunnable(String url){
this.urls = url;
}
#Override
public void run() {
// Perform the HTTP request for earthquake data and process the response.
Event result = Utils.fetchEarthquakeData(urls);
// Update the information displayed to the user
updateUi(result);
}
}
Here's an example of how you might use an ExecutorService within your Activity/Fragment:
// Create some member variables for the ExecutorService
// and for the Handler that will update the UI from the main thread
ExecutorService mExecutor = Executors.newSingleThreadExecutor();
Handler mHandler = new Handler(Looper.getMainLooper());
// Create an interface to respond with the result after processing
public interface OnProcessedListener {
public void onProcessed(Event result);
}
private void processInBg(final String url, final boolean finished){
final OnProcessedListener listener = new OnProcessedListener(){
#Override
public void onProcessed(Event result){
// Use the handler so we're not trying to update the UI from the bg thread
mHandler.post(new Runnable(){
#Override
public void run(){
// Update the UI here
updateUi(result);
// ...
// If we're done with the ExecutorService, shut it down.
// (If you want to re-use the ExecutorService,
// make sure to shut it down whenever everything's completed
// and you don't need it any more.)
if(finished){
mExecutor.shutdown();
}
}
});
}
};
Runnable backgroundRunnable = new Runnable(){
#Override
public void run(){
// Perform your background operation(s) and set the result(s)
Event result = Utils.fetchEarthquakeData(url);
// ...
// Use the interface to pass along the result
listener.onProcessed(result);
}
};
mExecutor.execute(backgroundRunnable);
}
Then, wherever you need to trigger your background processing:
processInBg("some_url", true);
Depending on your situation, you'll want to customize your implementation of ExecutorService to better suit your needs.
I'm trying to implement a function which makes a RPC call. (In this function I'd like to set up a thread and try to call remote service infinitely until it succeeds). I want the caller can be notified when it succeeds, also, it should stop trying when the caller decides to cancel the call.
what class should I return in this function?
If return a CompletableFuture, I can register a callback by future.thenRun(), but future.cancel(true) won't interrupt the working thread.
If return a Future/FutureTask, there isn't a straightforward method to register a callback.
To make it concret, I'm looking for something like this:
interface Service {
SomeFutureClass<T> request();
}
The client code may like:
SomeFutureClass<T> future = request();
// I can either register a callback
future.thenRun(() -> {
// someLogic
});
// or tell the service to stop trying
future.cancel(true);
If there isn't such a class, what is the best way to implement function like this?
You could use an Executor and wrap your call.
task is your RPC-Call, listener is your Notification.
With cancel() you can cancel the call, otherwise it reschedules itself until a result occurs.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class RPCCaller
{
ExecutorService service=Executors.newSingleThreadExecutor();
public <V> RepeatedCaller<V> callRepeatedly(Supplier<V> task, Consumer<V> listener) {
return new RepeatedCaller<V>(task, listener);
}
public class RepeatedCaller<V> implements Runnable, Supplier<V> {
private final Supplier<V> task;
private boolean cancel;
private V result;
private Consumer<V> listener;
public RepeatedCaller(Supplier<V> task, Consumer<V> listener) {
this.task = task;
this.listener = listener;
service.execute(this);
}
#Override
public void run() {
try {
result=task.get();
}
catch(Exception ex) {
System.err.println(ex);
}
if(result!=null)
listener.accept(result);
else if(!cancel)
service.execute(this);
}
public void cancel() {
this.cancel = true;
}
public V get() {
return result;
}
}
}
I'm implementing a layer to wrap a 3rd party communication layer.
The contract I need to implement is:
FutureTask<SomeData> send(Request request);
My layer has an onMessageReceived method, which is called by the 3rd party when a response arrives.
The approach I've taken to implement my layer is as follows:
I have a callable, which waits on a condition with a timeout:
interface MyCallable<T> extends Callable<T> {
void signal();
}
class CallableWithSignal<T> implements MyCallable<T> {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private long waitTime;
public CallableWithSignal(int waitTimeSeconds){
this.waitTime=waitTimeSeconds;
}
#Override
public T call() throws Exception {
lock.lock();
try {
boolean wasSignaled = condition.await(waitTime, TimeUnit.SECONDS);
if(wasSignaled)
return null;
System.out.println("throwing exeption");
throw new Exception("timeout");
} finally {
lock.unlock();
}
}
#Override
public void signal() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
I also have extended FutureTask to expose the set method, as follows:
class MyFutureTask<V> extends FutureTask<V> {
private MyCallable<V> myCallable;
public MyFutureTask(MyCallable<V> r) { super(r); myCallable = r;}
#Override
public void set(V x) { super.set(x); }
#Override
public void setException(Throwable t) { super.setException(t); }
#Override
protected void done() {
super.done();
myCallable.signal();
}
}
When the task is done, I signal the callable to stop it.
So every time a send is called, I create a new MyFutureTask, run it using an executor, save it in a map and return it.
When onMessageReceived is called I find the task in the map and set its result with the set method.
Is this a good approach?
And another question: is it a good approach to move the executor logic inside the task? I mean, to create a start method for it, which will run the task using the executor.
please advice.
I have two tasks: The first task (work) is reoccurring and the second task (cleanup) is releases some resources. The cleanup task should be run exactly once after the reoccurring work task has completed and will not be run again.
My first instinct was something like this:
ScheduledExecutorService service = ...;
ScheduledFuture<?> future = service.scheduleAtFixedRate(work, ...);
// other stuff happens
future.cancel(false);
cleanup.run();
The problem here is that cancel() returns immediately. So if work happens to be running, then cleanup will overlap it.
Ideally I would use something like Guava's Futures.addCallback(ListenableFuture future, FutureCallback callback). (Guava 15 may have something like that).
In the meantime, how can fire a callback when future is cancelled and work no longer running?
This is the solution that I've come up with. It seems to be pretty simple, but I still assume there's a more common and/or elegant solution out there. I'd really like to see one in a library like Guava...
First I create a wrapper to impose mutual exclusion on my Runnables:
private static final class SynchronizedRunnable implements Runnable {
private final Object monitor;
private final Runnable delegate;
private SynchronizedRunnable(Object monitor, Runnable delegate) {
this.monitor = monitor;
this.delegate = delegate;
}
#Override
public void run() {
synchronized (monitor) {
delegate.run();
}
}
}
Then I create a wrapper to fire my callback on successful invokations of cancel:
private static final class FutureWithCancelCallback<V> extends ForwardingFuture.SimpleForwardingFuture<V> {
private final Runnable callback;
private FutureWithCancelCallback(Future<V> delegate, Runnable callback) {
super(delegate);
this.callback = callback;
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled) {
callback.run();
}
return cancelled;
}
}
Then I roll it all together in my own method:
private Future<?> scheduleWithFixedDelayAndCallback(ScheduledExecutorService service, Runnable work, long initialDelay, long delay, TimeUnit unit, Runnable cleanup) {
Object monitor = new Object();
Runnable monitoredWork = new SynchronizedRunnable(monitor, work);
Runnable monitoredCleanup = new SynchronizedRunnable(monitor, cleanup);
Future<?> rawFuture = service.scheduleAtFixedRate(monitoredWork, initialDelay, delay, unit);
Future<?> wrappedFuture = new FutureWithCancelCallback(rawFuture, monitoredCleanup);
return wrappedFuture;
}
I'll give it another shot then. Either you may enhance the command or you may wrap the executed Runnable/Callable. Look at this:
public static class RunnableWrapper implements Runnable {
private final Runnable original;
private final Lock lock = new ReentrantLock();
public RunnableWrapper(Runnable original) {
this.original = original;
}
public void run() {
lock.lock();
try {
this.original.run();
} finally {
lock.unlock();
}
}
public void awaitTermination() {
lock.lock();
try {
} finally {
lock.unlock();
}
}
}
So you can change your code to
ScheduledExecutorService service = ...;
RunnableWrapper wrapper = new RunnableWrapper(work);
ScheduledFuture<?> future = service.scheduleAtFixedRate(wrapper, ...);
// other stuff happens
future.cancel(false);
wrapper.awaitTermination();
cleanup.run();
After calling cancel, either work is no longer running and awaitTermination() returns immediately, or it is running and awaitTermination() blocks until it's done.
Why don't you do
// other stuff happens
future.cancel(false);
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
cleanup.run();
This will tell your executor service to shutdown, thus allowing you to wait for the possibly running work to be finished.
I have a thread inside a class like this-
import java.util.Observable;
public class Download extends Observable {
private int state = 0;
private final Thread myThread = new Thread(() -> {
/*
some work to do here
*/
setChanged();
notifyObservers(state);
});
public void download(int state) {
if (!myThread.isAlive()) {
this.state = state;
myThread.start();
}
}
public Thread getThread() {
return myThread;
}
public static void MyMethod() throws InterruptedException {
Download down = new Download();
down.addObserver((Observable ob, Object dat) -> {
System.out.println(ob);
if ((int) dat == 1) {
down.download(2);
} else {
System.out.println("success");
}
});
down.download(1);
down.getThread().join();
}
public static void main() throws InterruptedException {
MyMethod();
}
}
The problem is I never get it to print the "success" message.
I assume, it is because all observers are being notified from inside of MyThread. So when down.download(2) is called from the observer inside MyMethod(), the previous thread is still running and the call is ignored.
How can I notify all observers from the main thread, not from the myThread?
You are calling down.download(2) from within the execution of MyThread, therefore the thread is still alive which means that your download method does nothing because of if(!myThread.isAlive()).
I would recommend you to use the Executor framework and Listenable Futures from Guava instead of creating threads manually. Example code from the Guava wiki:
ListeningExecutorService service =
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
public Explosion call() {
return pushBigRedButton();
}
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
// we want this handler to run immediately after we push the big red button!
public void onSuccess(Explosion explosion) {
walkAwayFrom(explosion);
}
public void onFailure(Throwable thrown) {
battleArchNemesis(); // escaped the explosion!
}
});
Note that Futures.addCallback(..) also has an overload which allows you to determine which executor should execute the callback, this seems to be what you want.