AsyncTask's doInBackground method blocking UI thread
I am loading some JSON data in an AsyncTask, as I want to show the download progress in the UI. The download is working fine and the publishProgress method gets called regularly (every 100 JSON objects), but onProgressUpdate and onPostExecute do not get actually executed, until all background operations are done (i.e. all calculations which require the doInBackground result).
Log looks roughly like this:
AsyncTaskCaller.downloadWithAsyncTask: executing AsyncTask
MyAsyncTask.onPreExecute: AsyncTask started
MyAsyncTask.doInBackground: Download 0%
MyAsyncTask.doInBackground: Download 10%
...
MyAsyncTask.doInBackground: Download 90%
MyAsyncTask.doInBackground: Download 100%
AsyncTaskCaller.processResult: Results processed
// all background calculations finished
MyAsyncTask.onProgressUpdate: Download 0%
MyAsyncTask.onProgressUpdate: Download 10%
...
MyAsyncTask.onProgressUpdate: Download 90%
MyAsyncTask.onProgressUpdate: Download 100%
MyAsyncTask.onPostExecute: AsyncTask ended
MyActivity.updateUiAfterDownload
This is how my code is calling the data:
MyActivity:
final Runnable mSynchroniseContacts = new Runnable() {
public void run() {
/** get oAuth tokens for synchronisation */
MyApp app = (MyApp) getApplication();
OpenAuthTokens myTokens = app.getAccessTokens();
// mockup code to load contacts
MyContact[] contacts = AsyncTaskCaller.loadContacts(myTokens, MyActivity.this);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.synchronisation_activity);
statusText = (TextView) findViewById(R.id.synchronisation_status_text);
mSynchroniseContacts.run();
}
AsyncTaskCaller:
private static JSONArray records = null;
public static MyContact[] loadContacts(OpenAuthTokens myTokens, Context context) {
MyAsyncTask contactDownloader = new MyAsyncTask(context, myTokens) {
@Override
protected void onPostExecute(JSONArray result) {
super.onPostExecute(result);
records = result;开发者_开发知识库 // assigning result to static class variable, to avoid calling contactDownloader.get(), which apparently blocks the UI thread according to http://stackoverflow.com/questions/5583137/asynctask-block-ui-threat-and-show-progressbar-with-delay
}
};
contactDownloader.execute(url);
// wait until contacts are downloaded
while(!SforceContactDownloadTask2.isFinished()) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Log.e(TAG, e.getCause() + " - " + e.getMessage());
e.printStackTrace();
}
}
// some code to convert JSONArray records into MyContact[] myContacts
return myContacts;
}
MyAsyncTask (code to log as above was not explicitly pasted):
@Override
protected void onPreExecute() {
finished = false;
}
@Override
protected void onPreExecute() {
finished = false;
}
@Override
protected JSONArray doInBackground(String... url) {
StringBuffer dataString = new StringBuffer();
try {
boolean isOnline = ConnectivtiyChecker.isInternetAvailable(context);
if (isOnline) {
/** send as http get request */
URL urlObject = new URL(url[0]);
HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection();
conn.addRequestProperty("Authorization", "OAuth " + myTokens.get_access_token());
/** prepare response reader */
JSONArray records = null;
byte data[] = new byte[MAX_BUFFER_SIZE];
int currentByteReadCount = 0;
InputStream stream = null;
BufferedInputStream input = null;
try {
/** get response input stream */
stream = conn.getInputStream();
input = new BufferedInputStream(stream);
/** read response from input stream */
while ((currentByteReadCount = input.read(data)) != -1) {
String readData = new String(data, 0, currentByteReadCount);
dataString.append(readData);
//code to figure progress out
// publishing the progress (every 5%)...
if (progress % (total / 20) == 0 ) {
publishProgress((int)(progress * 100 / total));
}
}
} catch (Exception e) {
Log.e(TAG, e.getCause() + " - " + e.getMessage());
e.printStackTrace();
} finally {
// close streams
if (input != null) {
input.close();
}
if (stream != null) {
stream.close();
}
}
/** transform response into JSONArray */
String result = dataString.toString();
JSONObject object = (JSONObject) new JSONTokener(result).nextValue();
records = object.getJSONArray("records");
return records;
} else {
return null;
}
} catch (Exception e) {
Log.e(TAG, e.getCause() + " - " + e.getMessage());
e.printStackTrace();
return null;
}
}
@Override
protected void onProgressUpdate(Integer... changed) {
Log.d(TAG, "Download " + changed[0] + "%");
}
@Override
protected void onPostExecute(JSONArray result) {
finished = true;
}
public static boolean isFinished() {
return finished;
}
Any ideas how to de-block the UI?
You appear to be calling Thread.sleep()
on the main application thread. Do not do this. Please write your application to be properly asynchronous.
精彩评论