I have an AsyncTask, and in its doInBackground method I call a method in another class:
#Override
protected ArrayList<CustomClass> doInBackground(ArrayList<CustomClass>... array) {
ArrayList<CustomClass> retorno= DataNetwork.GetCustomClassArrayList(array[0],(...more parameters...));
return retorno;
}
In DataNetwork I have that method, which does a REST call, and returns a result. I am forced to use a library that makes the REST call (I think it uses Volley, but I am not sure. To call this library, I have to make an Intent, which is passed to the method makeRESTCall):
public static ArrayList<CustomClass> GetCustomClassArrayList(various params goes here){
ArrayList<CustomClass> toReturn;
//some parameters processing
library.makeRESTCall(Intent intent){
//processing the answer
toReturn=processAnswerJSONResponse();
}
return toReturn;
}
This way, I get to the return toReturn line, before answer from REST is processed. So, I tried to make a Thread, and use the join statement. The GetCustomClassArrayList method (well, most of it, until the t.start()) is now inside a Thread. The end of the method is now:
(...)
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return toReturn;
The execution calls t.join() immediately after t.start(); and toReturn is null.
Maybe is a noob question, but using the method join() always worked for me, and waited for the thread to finish before entering the return statement. No exception, no error. It just doesn't wait for the thread to finish.
Why is not working now? What can I do to wait for the toReturn variable to be fulfilled before entering the return statement?
Thank you.
The problem likely stems from using a library which is already returning the response asynchronously, so your AsyncTask is not blocking. Check the library documentation.
AsyncTask is not like a normal thread. It is specialized to execute one time, blocking if necessary in the doInBackground method, then returning results to be handled in the main thread. If your 3rd party REST library has a synchronous version of it's calls, you could use that in your AsyncTask, but it will likely be less efficient than the library's built in functionality.
Related
I am reading data from local Android RoomDB and I need to do it in background because well reading from DB is not allowed on UI Thread. So I have this method:
#Override
public DBBackedRouteModel getDBBackedRouteModelByID(Long id) {
AsyncTask.execute(() -> {
this.dbBackedRouteModel = routesParser.getDBBackedRouteModel(id);
});
return dbBackedRouteModel;
}
Is there a way to know that the Async has finished and return the result only then?
You can use callbacks. I am not sure what you want to do exactly but you could, for example, do a console log when the Async is finished.
You can use EventBus. onPostExecute() method of async task you can post the event and pass the value which you want to read.
Hope this will solve your problem
I am using priority job queue , there are number of jobs running in parallel, so that their result populates on UI at same time which takes application to ANR, is there any way , so that i can run asynchronous calls and populate ui synchronously?
UI is always populated synchronously, if it is done in correct way. The correct way is to call activity.runOnUiThread(Runnable), directly or indirectly. Seems that your problem is that your jobs post to UI thread in a too high rate.
First, check if the Runnables to update UI does only UI work. Any calculations should be done outside the UI thread. If it is so, create an intermediate object which makes pauses between UI updates from the parallel jobs and so lets the UI thread to respond to updates from user. It can look as follows:
public class PauseMaker {
Semaphore sem = new Semaphore(1);
public void runOnUiThread(Runnable r) {
sem.aquire();
Thread.sleep(1);
activity.runOnUiThread(new Runnable(){
try {
r();
} finally {
sem.release();
}
});
}
}
You can use the zip operator of rxjava2 to merge the responses together and when the combined response comes you can populate the UI synchronously .. for reference you can check..
http://www.codexpedia.com/android/rxjava-2-zip-operator-example-in-android/
Note The zipper will the return merged response after all the responses are received
I get a error of NetworkOnMainThreadException in the line of AVObject brandObj = query.getFirst(); After did some searches about the error, I think I should use something like Asynctask. But couldn't figure out how to do it.
AVObject is same as ParseObject
public class Product {
Product(AVObject object) {
try {
AVObject brandObj = query.getFirst(); // this one is making network request
} catch (AVException e) {
e.printStackTrace();
}
}
}
Should I extends AsyncTask<AVObject, Void, AVObject>
Then
#Override
protected AVObject doInBackground(AVObject... objects) {
return null;
}
But not sure what should I write in doInBackground
Any suggestions?
NetworkOnMainThreadException is thrown when an application attempts to
perform a networking operation on its main thread. This is only thrown
for applications targeting the Honeycomb SDK or higher.
You cannot perform any networking on your main thread because it may block the UI. Hence, you should do everything in a separate thread.
AsyncTask is one of the easier solutions. Setup your AsyncTask (follow some tutorials/guides) and put your networking code into doInBackground() method, which runs on a separate thread.
Ideally, an object's constructor does not perform disk I/O or network I/O. In your case, it does.
So, every piece of code that is calling new Product(...) needs to be put into a background thread (plain thread, RxJava chain, JobIntentService, AsyncTask, etc.). Product itself would not change.
I also faced with the NetworkOnMainThreadException in my application but I don't see how to resolve it.
I have a class with a getter method. Like:
public ArrayList<News> get(int i){
// get the list of news from a HTML on the net. The news are split up into web pages on the site
// and i is the page number
return NewsParser(i);
}
Since Android throws the exception I come up with an idea of a downloader class which downloads the HTML content in a separate thread
pubic ArrayList<News> get(int i){
Downloader dl = new Downloader(i);
String HTMLcontent = dl.getContent(); <-- AsyncTask starts in getContent()
return NewsParser(HTMLcontent); <-- What happens here in the main thread???
}
Any ideas/best practices for this problem?
Just looking at your code and your question, it seems like you don't have a very solid understanding of how AsyncTask (or threads in general) works.
I would recommend reading this article.
Basically, your AsyncTask should query the web URL and download the data. Once the data is complete, your AsyncTask should send the HTMLContent to a handler object. The handler will be running on your main thread, so you can display the information to the user at that point.
You shouldn't be calling
dl.getContent();
to retrieve the content. AsyncTask runs on a separate thread, so you can't just call methods like this from your main thread. You need to create the Downloader object (like you did) and then call
dl.execute();
to start the AsyncTask.
run the get method inside a thread,
new Thread(new Runnable() {
#Override
public void run() {
// call get method here
}
}).start();
Since Honeycomb (Android 3.0) you can't use Networking Operations in the MainThread to avoid freezes on the Phone. This is important in order to make your app responsive.
More info:
NetworkOnMainThreadException
Responsiveness
I'm looking for a design pattern or approach for the following scenario. I wish to kick off two separate background threads for data retrieval from different sources. I then want one method (on the UI thread) to be called once both background threads have completed their work. As the data from the two sources must be combined to be useful, I must wait until both have finished retrieving before manipulating the data. How can I achieve this on the Android platform?
Edit: My first version has been bothering me, and I didn't like the necessary added boolean with it, so here's another version. Call it with this from onPostExecute of each added task.
ArrayList<AsyncTask> tasks;
public void doStuffWhenDone(AsyncTask finishedTask)
{
tasks.remove(finishedTask);
if(tasks.size() > 0)
return;
... do stuff
}
I'll keep the older one up also, since they both work, but I think the above is much cleaner. Now to go tidy up one of my earlier projects.
ArrayList<AsyncTask> tasks;
boolean hasBeenDone = false;
public void doStuffWhenDone()
{
for(int i=0;i<tasks.size();i++)
if(hasBeenDone || (tasks.get(i).getStatus() != AsyncTask.Status.FINISHED))
return;
hasBeenDone = true;
... do stuff
}
It's easily extendable to however many tasks you have, and there's no need for a thread to handle the threads. Just call the method at the end of each task. If it's not the last one done, nothing happens.
Edit: Good point, but I don't think it needs to be atomic. Since both AsyncTasks' onPostExecute methods run on the UI thread, they'll be called one after the other.
Use a CountDownLatch, like this:
CountDownLatch barrier = new CountDownLatch(2); // init with count=2
startWorkerThread1(barrier);
startWorkerThread2(barrier);
barrier.await(); // it will wait here until the count is zero
doStuffWithTheResult();
when a worker thread finishes, call barrier.countDown() from it.
You can use AsyncTask and an int to know if both jobs are finished...