AsyncTask "Only the original thread that created a view hierarchy can touch its views."
I try to modify the Spinner content across the AsyncTaks but I can't and the Logcat is wrote "09-19 16:36:11.189: ERROR/ERROR THE(6078): Only the original thread that created a view hierarchy can touch its views.".
public class GetGroups extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
Spinner combo = (Spinner) findViewById(R.id.group_combo);
setGroups(combo);
return null;
}
@Override
protected void onPostExecute(Void unused)
{
super.onPostExecute(unused);
Spinner combo = (Spinner) findViewById(R.id.severity_combo);
combo.setSelection(1);
//updateGroups();
//if (!isFinishing())
//{
/*Spinner combo = (Spinner) findViewById(R.id.group_combo);
ProgressBar pg = (ProgressBar) findViewById(R.id.loading_group);
pg.setVisibility(ProgressBar.GONE);
combo.setVisibility(Spinner.VISIBLE);
combo.setSelection(0);*/
//}
}
}
}
And the function setGroups is:
public void setGroups(Spinner combo) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(this.object.url);
List<NameValuePair> parameters = new ArrayList<NameValuePair>(2);开发者_JAVA百科
parameters.add(new BasicNameValuePair("user", this.object.user));
parameters.add(new BasicNameValuePair("pass", this.object.password));
parameters.add(new BasicNameValuePair("op", "get"));
parameters.add(new BasicNameValuePair("op2", "groups"));
parameters.add(new BasicNameValuePair("other_mode", "url_encode_separator_|"));
parameters.add(new BasicNameValuePair("return_type", "csv"));
parameters.add(new BasicNameValuePair("other", ";"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entityResponse = response.getEntity();
String return_api = this.object.convertStreamToString(entityResponse.getContent());
String[] lines = return_api.split("\n");
ArrayList<String> array = new ArrayList<String>();
for (int i= 0; i < lines.length; i++) {
String[] groups = lines[i].split(";", 21);
this.pandoraGroups.put(new Integer(groups[0]), groups[1]);
array.add(groups[1]);
}
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
array);
combo.setAdapter(spinnerArrayAdapter);
}
catch (Exception e) {
Log.e("ERROR THE ", e.getMessage());
return;
}
}
What is wrong? Thanks.
As mentioned by Peter, you cannot access the views using doInBackground()
. You can do that inside onPostExecute()
however. That is where you are supposed to work with the results doInBackground()
return as far as I know.
I ran into this issue and fixed it by moving the view modification code to onPostExecute()
.
For those of you who are starting to pick up Android development:
- doInBackground()
: whatever insides happen in another thread (in the background) different from the main/ original thread your views/ fragment/ activity operates on (this is the whole point of AsyncTask
==> you cannot touch the views!
- onPostExecute()
: now background stuffs are done, here it's back on the main/ thread thread ==> you can touch the views now!
You are trying to access UI components (View) from a background thread in your case inside the doInBackground()
method. You are not allowed to do that.
If you want to show the progress during the background process, none of the previous answers give an hint: When OnPostExecute
is called everything is finished so there's no need to updated status of the loading.
So, you have to override onProgressUpdate
in your AsyncTask and be sure that the second object is not a Void but an Integer or a String that is read by onProgressUpdate
. For example using String:
public class MyAsyncTask extends AsyncTask<Void, String, Void> {
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if (values != null && values.length > 0) {
//Your View attribute object in the activity
// already initialized in the onCreate!
mStatusMessageView.setText(values[0]);
}
}
}
Than in the background method you call publishProgress(value as String)
which automatically calls onProgressUpdate
method which use main UI thread:
@Override
protected Boolean doInBackground(Void... params) {
your code...
publishProgress("My % status...");
your code...
publishProgress("Done!");
}
More in general, when you declare an AsyncTask you have to specify the <Params, Progress, Result>
classes that are passed to the main methods, these can be your own classes or just Java classes:
doInBackground(Params... params)
onProgressUpdate(Progress... value)
onPostExecute(Result... success)
A little more details
Problem:
- UI elements can be modified in the UI thread only. One exception is their
postInvalidate()
method (and its variants) that can be executed from outside the UI Thread - the error you receive is caused by an attempt to modify a UI element (a
View
) from outside the UI thread -doInBackground()
runs on a background thread
Solution:
- modify the views in the
onPostExecute()
method - it runs on the UI thread - obtain a reference to the an
Activity
and use itsrunOnUiThread(Runnable)
method - depending on the modification use one of the
View
'spost...()
methods
精彩评论