I am currently trying to figure out how to avoid a stall in my main thread when exiting ASyncTasks, and I'll try to explain with skeleton code where the problem is specifically. I'm sorry if this is a duplicate, I wasn't seeing anything other than posts about ASyncTasks stalling the main thread during execution. I have a hypothesis of what's causing the problem, but I have no idea if it's right. If it is right, or if it's wrong, I'd like to know the "proper" way to handle the situation.
public class AST extends ASyncTask<String, Integer, Void> {
private Activity mActivity;
private interfaceObject mInterface;
public AST(Activity activity, interfaceObject interface) {
mActivity = activity;
mInterface = interface;
}
@Override
protected void onPreExecute() {
//mInterface.setStatus("Starting...");
mInterface.setStatus("Doing Stuff...");
}
@Override
protected String doInBackground(Void... params) {
String string = doStuff();
//mInterface.setStatus("Did Stuff."); As mentioned this shouldn't be done.
return string;
}
@Override
protected void onProgressUpdate(Integer... progress) {
//mInterface.setStatus("Doing Stuff...");
mInterface.progressUpdate(progress[0], progress[1]);
}
@Override
protected void onPostExecute(String result) {
mInterface.setStatus("Finished.");
mInterface.astDone(result);
}
private String doStuff() {
StringBuilder string = "";
for(int i=0; i<10000; i++) {
string.append("A");
publishProgress(i, 10000);
}
return string.toString();
}
}
For specifics, setStatus(String status) edits the text of a textView on the main thread. progressUpdate(int progress, int max) does the same thing for a progressbar. At around 90% the progress bar freezes with the whole UI (despite a Log.d outputting the correct values). The message "Did Stuff." never appears, and there are ~200 skipped frames that get larger as the string gets larger. After the 200 skipped frames, "Finished." appears and astDone gets called (which starts another ASyncTask).
Now why would this hang?
My theory is that when the main thread has to read in the large string, it's stalling, but I don't know if I'm way off base on that? Is there a "proper" way to pass large data from one ASyncTask to another? I suppose I could write to a file in one and read from it in the other, but is that what's considered proper?
Thank you for your time!
Also, just as an aside question, if I slow down the doStuff() method, by adding in an additional loop, the progress bar will make it to 100% and "Finished." does appear. Shouldn't the main thread always receive these before stalling on my large string? Does the main thread not have an order handler, so it is ideal for me to make my publishProgress calls take as long or longer than the main thread takes to actually display the progress? I just don't understand how the main thread can stall at different points in my ASyncTask's calls to the main thread. Shouldn't the main thread execute the calls from ASyncTask as they are received, then hit the variable read and stall?
Edit1: I have changed the code to match Melquiades's suggestions, unfortunately I'm still skipping 200 frames.
Edit2: Since it's coming up I'll include the code for setStatus and progressUpdate:
@Override
public void progressUpdate(int cur, int max) {
progressBar.setMax(max);
progressBar.setProgress(cur);
}
@Override
public void setStatus(String status) {
statusBar.setText(status);
}
progressBar and statusBar are both member variables that are initialized onCreate(), although looking now there's probably no reason they need to be. Is this wrong?
private ProgressBar progressBar;
private TextView statusBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
statusBar = (TextView) findViewById(R.id.textView);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
}
Edit3: Moved setStatus() out of onProgressUpdate() as suggested.