For context, I am an Android developer who is familiar with using AsyncTask's but has recently started working on a project which is heavily using Future's. The Futures do not have a callback and require checks on isDone() to determine progress.
I am having trouble understanding what the purpose and use case of Future is in Android. AsyncTask's provide what seems like the same functionality but with in my opinion a better interface which has callbacks built in that enable the client to clearly determine when the async operation is complete without having to constantly check isDone().
What is the use and purpose of a Future in Android, and why would I use Future or FutureTask over an AsyncTask?
The Future is part of the Java API, whereas the AsyncTask is Android specific. In fact, if you take a look at the source code of AsyncTask, you will see that it actually uses a FutureTask for its implementation:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
#Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
The AsyncTask is thus just a helper class for short threading jobs, which also handles some thread pooling. My guess is that the original writers of your project were familiar with Futures, but not with AsyncTask, or generally disliked AsyncTask.
Since I dislike the original AsyncTask implementation due to its Exception handling, I went on a search for a better alternative, and found RoboGuice's SafeAsyncTask. In this implementation, an onException(Exception) callback is available, but RuntimeExceptions get propagated to that callback as well.
I think a NullPointerException should make the app just crash, and I modified this SafeAsyncTask a little while back to do exactly this. The result can be found here.
Related
I am executing tasks parallelly on threads using threadPoolExecuter and i want to wait for all the tasks to complete without blocking the main ui. I don't want to use async task here. and methods like service.awaitTermination() is blocking the main ui.I have checked similar questions but didn't find answer to my particular problem. I am using a for loop to pass runnables to threads like this :
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info));
}
MyTask() function execute the same opertaion for all the ApplicationInfo type objects here.
Please help.....
Well, I can see you are using java, so probably you aren't allowed for some reason to use coroutines. With coroutines, it would be easier to achieve such a result.
Consider using them, especially have a look at their way to solve your problem.
What I would use in your case is - CountDownLatch.
Your code will look similar to this one:
CountDownLatch latch = new CountDownLatch(applicationInfoList.size);
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info, latch));
}
latch.await();
MyTask under the hood should call latch.countDown() when your work is done.
latch.await() throws InterruptedException so it should be handled.
Note: Anyway, it blocks the thread you are currently on.
The easiest way would be to migrate this logic to Runnable and provide a callback:
class YourButchTask implements Runnable {
private WorkDoneCallback callback;
public YourButchTask(WorkDoneCallback callback) {
this.callback = callback;
}
#Override
public void run() {
CountDownLatch latch = new CountDownLatch(applicationInfoList.size);
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info, latch));
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
//handle it
}
callback.workWasDone();
}
}
Afterward, you can submit your task to your service.
Note: your callback will be invoked from the executor thread, so you aren't allowed to access UI from it.
Here is a nice and simple tutorial, hopefully, that will help.
Update:
To be clear - Callback is your custom interface that will notify you when the work is done. Go ahead and use SAM, example:
interface WorkDoneCallback{
void workWasDone();
}
P.S. To redirect calls on main thread just use Handler with mainLooper under the hood, or runOnUiThread().
I have a situation where a long running process is wrapped in an Observable.fromCallable(). This process is an OkHttp call and, if terminated, will throw an IOException. If the observable is subscribed to, then the disposable is stored in a CompositeDisposable and the exception is handled as expected. However, my code will clear the CompositeDisposable in some cases, triggering the OkHttp thread termination with no error handling, causing the app to crash with an unhandled exception. Here's a simple unit test example of this problem:
#Test
public void test(){
CompositeDisposable compositeDisposable = new CompositeDisposable();
Observable<Object> o = Observable.fromCallable(new Callable<Object>() {
#Override
public Object call() throws Exception {
System.out.println("sleeping - this sleep will be interrupted when compositeDisposable gets cleared");
Thread.sleep(3000);
return null;
}
});
compositeDisposable.add(o.subscribeOn(new IoScheduler()).subscribe());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
compositeDisposable.clear();
}
Is there any way to work around this problem?
Unlike RxJava1, RxJava2 will not deliver this Exception to the Subscriber onError(), as you called cancel() to unsubscribe and don't wan't to get notifications anymore, so this kind of Exceptions which happens with the unsubscription code go by default now to Thread.currentThread().getUncaughtExceptionHandler().uncaughtException().
You can either wrap with try catch this kind of exceptions that may happens with cancel, or override the default behavior with:
RxJavaPlugins.setErrorHandler(Functions.<Throwable>emptyConsumer());
or any other handling you would like.
You should also read the full explanation by akarnokd at RxJava github.
Also refer to this discussion for the above mentioned solutions.
I am new to threading and i went through many post in stack overflow and find many solution for my problem but i am not sure which one is best for which condition.
First thing first, my problem is that i want to update one JSON file
when all threads are done with the bitmap generation at a specific path so
that i can get that all those image and update JSON file. So in
simple word my i want to run some code when all thread are done with it
execution and major requirement is that i don't want my main to be blocked because of this.
What i have found out
thread. join
excutorServive
android-priority-jobQueue (link)
Mutex in threadpool ( also let me know if any other is there)
I am confused which one is the best way to tackle my problem. if any
android expert out there can summarise that for following the two
scenerio what is the best available in android.
wait till when all thread completes
don't wait and get informed when all completes
You can have counter for your threads, after each thread is complete check how many have already completed, if not all completed, increment the number of completed threads and the last thread to complete will then run the piece of code.
You can do it like this.
In your thread:
private Runnable runnableThread= new Runnable() {
#Override
public void run() {
try {
if (lastThreadDone){
handler.sendEmptyMessage("SUCCESS");
}
}
catch (Exception ex) {
throws ex;
}
}
};
lastThreadDone is boolean which will become true if the process is done, this is base on how you implement it.
then in you handler:
#SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
switch (msg.what) {
case "SUCCESS": {
// your code here
break;
}
case "FAIL":
break;
default:
break;
}
}
catch (Exception ex) {
throw ex;
}
super.handleMessage(msg);
}
};
I would use a completion service and then poll until all tasks are finished. When they are done, the json file gets updated. The problem is that you need to do this async or you risk to block the ui. Therefore I would encapsulate the work with the completion service inside an intent service. If you need to update the ui you then can post local broadcasts from the intent service.
Furthermore for you cases
wait till when all thread completes
only do this when you are already on a background thread like intent service or async task
don't wait and get informed when all completes
implies the case above. Do the work async and notify the ui or some listening component with broadcasts, content observers, handlers or the 'onPostExecute' if you are using async task.
I am trying to implement an asynchronous task using RxJava in Android.
I tried the following code and it didn't work. It executes on the UI thread. I am using the following version of RxAndroid 0.24.0.
try {
Observable.just(someMethodWhichThrowsException())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> onMergeComplete());
}
catch (IOException e) {
e.printStackTrace();
}
However, the following works asynchronously for me.
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
try {
someMethodWhichThrowsException();
} catch (IOException e) {
e.printStackTrace();
}
subscriber.onCompleted();
}
});
observable.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe();
I am trying to understand the following:
What is the difference between them?
What is the best practice while creating async tasks?
What is the difference between them?
Observable.just(someMethodWhichThrowsException())
.subscribeOn(Schedulers.newThread())
This is equivalent to the following:
Object someResult = someMethodWhichThrowsException();
Observable.just(someResult)
.subscribeOn(Schedulers.newThread())
As you can see this makes the synchronous method call first, then passes it to Observable.just to become an Observable.
Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
...
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
This method, however, will run the code in the call block on subscription. You've told it you want to subscribe on a new thread (subscribeOn(Schedulers.newThread())), so the subscription happens on a new thread, and the code which gets run on subscription (the call block) gets run on that thread too. This is similar behaviour to calling Observable.defer.
What is the best practice while creating async tasks?
Well, that's up to you and your desired behaviour. Sometimes you want the async code to begin running immediately (in which case you may want to cache it using one of the operators for that purpose). I'd definitely consider using the Async Utils library for this.
Other times, you'll want it to run only on subscription (which is the behaviour in the examples here) - for example if there are side-effects, or if you don't care when it's run and just want to use the built-ins to get something off the UI thread. Dan Lew mentions that Observable.defer is very handy for taking old code and getting it off the UI thread, during a conversion to Rx.
Use Async.start() from RxJava Async Utils library. This will call the function you provide on another thread.
Example:
Observable<String> observable = Async.start(new Func0<String>() {
#Override
public String call() {
try {
return someMethodWhichThrowsException();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
As you note, checked exceptions must be wrapped into RuntimeExceptions.
See also https://github.com/ReactiveX/RxJava/wiki/Async-Operators#start
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I have a problem with using Java Serialization mechanism in Android. It works well when invoked from the UI thread, but when I try to use it from some background thread I get:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Because of project nature I cannot deserialize everything in UI thread (also it should be possible to do it in background, so the UI will not stop responding).
BTW. Same thing happens when I try to deserialize something in background using SimpleXML.
So now we do deserialization (both XML and Java serialization) from UI thread which cannot be used everywhere.
Can anyone shed some light on this issue?
EDIT:
I'm using the following code to deserialize an object, it works well when called from UI thread.
public Object getObject(String key) throws InvalidClassException {
Object result;
try {
FileInputStream fileIn = context.openFileInput(getPath(key));
ObjectInputStream in = new ObjectInputStream(fileIn);
result = in.readObject();
in.close();
fileIn.close();
} catch (InvalidClassException e) {
throw new InvalidClassException(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return result;
}
EDIT 2
As mentioned in EJP comment below, I'm deserializing an Activity object. So I'm changing my questuion to: How to deserialize Activity object in a background thread?
Not deserializing this object is an option that I'd rather avoid, because of performance issues (XML deserializes in about 4s while binary deserialization is less then 0.5s). I know that it would be possible to redesign our application, but due to project constraints, and it's extreme and unnecessary complexity, that's not really an option. Every bigger change is extremely painful.
So when issue is little clearer - does anyone have some ideas?
Thanks for any suggestions.
Try and call Loooper.Prepare(); before your code and
Looper.Loop(); after, workd for me.
Something like :
Looper.Prepare();
//your code
Looper.Loop();
you cannot do ui operations in any other thread
all ui operations should be on mainthread
you can use this
runOnUiThread(new Runnable() {
#Override
public void run() {
code here
}
});