How do I check whether both parallel AsyncTask threads are finished [duplicate] - android

This question already has answers here:
Wait for multiple AsyncTask to complete
(5 answers)
Closed 5 years ago.
I'm calling two AsyncTasks in parallel via this snippet in onCreate:
if ((DictMode.equals("TATOEBA")) || (DictMode.equals("SENTENCE"))) {
dictAsyncTask = new DictAsyncTask(DictionaryLookUp.this, "Tatoeba");
// dictAsyncTask.execute();
dictAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
if ((DictMode.equals("JUKUU")) || (DictMode.equals("SENTENCE"))) {
dictAsyncTask = new DictAsyncTask(DictionaryLookUp.this, "Jukuu");
// dictAsyncTask.execute();
dictAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
during onPostExecute I check whether any data gets retrieved and return from the startActivityForResult call via finish:
if (alldictStuff.size() == 0) {
...
Toast.makeText(DictionaryLookUp.this,"NOTHING FOUND ...",Toast.LENGTH_SHORT).show();
if ((DictMode.equals("TATOEBA")) || (DictMode.equals("JUKUU")) || (DictMode.equals("SENTENCE"))) {
Intent intentCard = new Intent(getApplicationContext(), CardView.class);
setResult(Activity.RESULT_OK);
finish();
}
but that's obviously flawed since I'm not checking whether both threads return no results, so what's the best way to check whether both threads are finished and returned nothing ? Do I have to use my own variables to track it or is there something neat/built-in I can utilize ?

This is mainly how you want to manage your business logic.
From your onPostExecute() either send intent or send broadcast message to main thread or maintain async task status list and mark finished for each task from onPostExecute().

You will need to call AsyncTask.get() method for getting result back and make wait until doInBackground execution is not complete. but this will freeze Main UI thread if you not call get method inside a Thread.
To get result back in UI Thread start AsyncTask as :
String str_result= new RunInBackGround().execute().get();

Related

android while loop alternative

This is my first Android application and I am finding troubles with while loop, I am trying to use a while loop on my Android application but the application freezes.
What I'm trying to do is track the user location (using onlocationChanged) and keep querying on the location until the query returns a result. It's a GIS application so I am going to describe the application behavior:
the application keeps tracking the user position using a listener "onLocationChangedListener" and store it in a variable "myPosition". I am using a boolean"noResults=true". I will use a method "query(myPosition)" in the while loop, this method has a callback that when a result is found, and changes a boolean "noResults" to false. the loop will keep on until "noResults" is false (that means query's callback changed the boolean's value)
, here's what I did:
while(noResults)
{
//myPosition keeps changing
query(myPosition);
//query has a callback that when a result is found it changes noResults to false
}
I resolved the problem using a "Handler" that query the Feature Layer every 5 seconds, this stops the main thread from generating application not responding error:
Handler m_handler=new Handler();
Runnable m_runnable;
m_runnable = new Runnable(){
public void run() {
//query code here
m_handler.postDelayed(m_runnable, 5000);
}
};
m_handler.postDelayed(m_runnable, 0);
running while loop codes on the main thread freezes the UI, and makes all other processes pause making your app unresponsive use
Threads..
also note that the while loop you are running is running on a default Thread termed as the ui thread so in short run while loops on separate threads..
eg..
new Thread(new Runnable() {
#Override
public void run() {
// Your hard while loop here
//get whatever you want and update your ui with ui communication methods.
}
).start();
for ui communicating methods
View.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "updated ui", Toast.LENGTH_LONG).show();
}
});
the view could be any views you are updating..
also like #TehCoder said you could use asynctask but asynctask is not meant for long workaflow work there are 3 of them but i can't recall the last one
Maybe you should use an AsyncTask? I'm not quite sure what your problem is tho.
Loop is not a problem in android (or any language).
There are two scenario might be reason for your freezing,
If you run network call in api, android throw error and crashes. You have to do network related calls in Aysnc Task ot threading
Use try throw catch and exception cases to avoid app crashing and better coding skill.

How to get user feedback (e.g. from AlertDialog) inside AsyncTask/Background-Thread?

an Android 4+ app should perform a long running operation. This could be copying a million files from A to B for example. To not block the UI this operation runs in the background using an AsyncTask.
Assume that the operation needs some user feedback in the middle of the process to continue its work, e.g. "File XY already exists. Override, Irgnore or Rename?"
What is the best way to get this feedback from the user? Since the operation is running in a background thread one could not just present an AlertDialog (or something similar) since UI interaction is only possible in the main thread...
So for I came across these solution:
Ask for feeback before background threads starts, e.g. ask how to handle conflicts before starting to copy/move the files in the
background.
Do not handle conflicts but note them to ask the user
how to handle them after the operation is complete in a new
operation.
End the background operation on the first conflict, ask the user for feedback and continue a new background operation
I do not like any of these solutions. In the first case the user is asked for feedback even if there will be no conflict at all. The second solutions is not possible if the steps have to be processed in a specific order. The third solution would result in code that is very difficult to read/understand/maintain.
A good solution would be:
Stop the background thread
Marshal to the UI thread and get feedback from the user
Resume background thread and use feedback to continue the operation
Using GCD in Objectiv-C/iOS or async/await in C# this is not a big problem. But how can this be done in Android using AsyncTask?
Meanwhile I thought, that I found an answer here: Simply run myActivity.runOnUiThread(...) within doInBackground(...) and wait for it. Sounds good, but it does not work. The AsyncTask/background thread does NOT wait for the Runnable to finish:
private void copyFiles() {
CopyTask copyTask = new CopyTask (this);
copyTask.execute();
}
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
I would expect, that when a conflict is detected the Runnable is executed and and Pos 1 (code inside Runnable to resolve conflict) is executed BEVOR Pos 2 is reached. This is not the case. The Runnable is executed correctly but the AsyncTask does not wait for it to finish. The execution of doInBackground is continued without any interruption. It seems that doInBackground and the Runnable are executed in parallel (not suprising since they are executed on different threads) but why does doInBackground not wait?

Java - Android : Thread being called (run) twice

I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {

How can I keep UI elements responsive while my program is working?

The UI I am creating includes a button, which once pressed, is supposed to find and display values repetitively until the user presses the button again.
This is my button's initialization with the listener:
pollOn = false;
pollButton = (Button) findViewById( R.id.pollButton );
pollButton.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i( "POLL BUTTON", "onClick" );
if( !pollOn ) {
Log.i( "POLL BUTTON", "!pollOn" );
pollOn = true;
methodToReadAndDisplayData();
} else {
Log.i( "POLL BUTTON", "else pollOn" );
pollOn = false;
}
}
});
It is not shown here to make things easier to read, but the way I currently have it working is to call the methodToReadAndDisplayData() 5 times in a for loop and then stop.
So when I press the pollButton initially, the UI freezes and Log.i("POLL BUTTON", "onClick") is displayed at the top of LogCat. I then press the pollButton while it appears to be frozen, and after all of the work is done and the UI unfreezes, Log.i("POLL BUTTON", "onClick") is shown at the very end of my LogCat. The way I am interpretting this is that the button click is entered into a queue, and the onClick method is called after all 5 iterations of the for loop have been completed.
Another large part of this problem is that the work being done is mainly in a native library, and is called using the NDK. I am unsure if this has anything to do with the UI freezing, but it definitely increases the processing time needed.
If anything is unclear or confusing please let me know and I will try to clarify things.
Any information on this situation would be greatly appreciated.
Doing some stuff while keeping the UI responsive can achieved by many methods, two of them are very common. Async Task and threads.
AsyncTask:
It's a class which have a few methods which help you to do time consuming work while updating the UI at the same time. For Example: If you want to search a specific word in a big document, do the reading and searching stuff in doInBackground() (a method of AsyncTask class) and you can display a progress bar and notify the user with your progress with onProgressUpdate(). This gives your app more professional feel and at the same time helps you executing time consuming task in background.
Threads:
They are simple runnable threads. You can execute non UI stuff with these threads but you can't perform UI tasks in them (as UI is not thread safe). For dealing with UI in these threads, you will have to use Handlers, which is quite cumbersome for beginners to get a grip and understanding of them.
So depending on your needs and app you can choose the one best suits you.
Because you're running on the main thread the system UI freezes, you'd be better off running in a new thread which would leave your UI running as normal. Below is an example of how to run your method in a new thread.
new Thread(new Runnable() {
#Override
public void run() {
methodToReadAndDisplayData();
}
}).start();
Note that if your method interacts with the UI in any way, you need to do it via the following:
When you want to update your UI:
Handler threadHandler = new Handler();
threadHandler.post(updateRunnable);
Update your UI here:
Runnable updateRunnable = new Runnable() {
public void run() {
example.setText(newValue);
}
};
Try that and see if there's any improvement. I've not worked with the NDK, just the standard SDK so there may be difference I'm unaware of.
Do it on another thread. Use an AsyncTask to call methodToReadAndDisplayData.

Cancelling network call in AsyncTask

I'm trying to handle the situation where the user loses their data connection during an Http request in an AsyncTask. Currently the AsyncTask will never finish executing if this happens and the app just stalls. I can't even check isCancelled() because the Http request just stalls out on one function call, so I can't implement a loop or anything.
I'm using the following in the UI thread but I can't figure out how to check if the task has been cancelled from within the task:
task = new LoginTask();
task.execute(this, mUsername, mPassword);
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
if (task != null && task.getStatus() == AsyncTask.Status.RUNNING)
{
task.cancel(true);
}
}
}, 5000);
Since KSoap 2 is written in Java, an option for you would be to abstract one of the classes and manually set a timeout on the HttpConnection.
Based on our prior discussion, you will probably have to override the method that doesn't set a timeout on the connection and replace it with your own method and a connection that times out. Should be managable thanks to KSoap being open source! Good luck.
In order to stop processing, you would need to do a check on isCancelled() inside doInBackground(). If there are any reasonable places to do so in your doInBackground, you can add an if-statement. Otherwise you should consider setting a timeout on the http connection.

Categories

Resources