CASE:我在活动中有一个按钮和列表视图。单击按钮后,我添加了一个单击侦听器,它启动一个新线程,我在其中更新进度条。作业完成后,即进度条100%完成,我想更新列表视图。
final OnClickListener mStartScan = new OnClickListener() {
@Override
public void onClick(View v) {
// prepare for a progress bar dialog
progressBar = new ProgressDialog(v.getContext());
progressBar.setCancelable(false);
progressBar.setMessage(getString(R.string.text_scanning_inbox));
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setProgress(0);
progressBar.setMax(totalSms);
progressBar.show();
progressBarStatus = 0;
Thread progressThread = new Thread(new Runnable() {
public void run() {
while (progressBarStatus < totalSms) {
// process some tasks
progressBarStatus = someStuff();
// Update the progress bar
progressBarHandler.post(new Runnable() {
public void run() {
progressBar.setProgress(progressBarStatus);
}
});
}
if (progressBarStatus >= done) {
// sleep 1 seconds, so that you can see the 100%
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// close the progress bar dialog
progressBar.dismiss();
// this method updates the list
populateList();
}
}
});
progressThread.start();
// try {
// progressThread.join();
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } finally {
// populateList();
// }
}
};
问题:当我在完成任务并解除进度条后更新列表视图时,我收到一个异常,说明视图只能从创建它的线程更新。
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
我做了什么:我试图等待正在运行进度条的线程完成,然后从主线程更新listview。
try {
progressThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
populateList();
}
然而,这不起作用。它根本不显示进度条。
答案 0 :(得分:1)
我用过这个:
private ProgressDialog progressBar;
class MyTask extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar = new ProgressDialog(getApplicationContext());
progressBar.setMessage("please, waiting ...");
progressBar.setCancelable(false);
progressBar.show();
}
@Override
protected String doInBackground(String... params) {
try {
// get info and set them in my model ...
} catch (Exception e) {
e.printStackTrace();
}
return params[0];
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (null != progressBar && progressBar.isShowing()) {
progressBar.dismiss();
}
// do work in UI and set info adapter and refresh list ...
populateList();
myListView.invalidateViews();
}
}
了解更多信息: http://developer.android.com/reference/android/widget/ArrayAdapter.html#notifyDataSetChanged%28%29
答案 1 :(得分:1)
只有创建视图层次结构的原始线程才能触及其视图。
这里原始线程指的是ui线程。您正试图在线程内更新ui,这是不可能的。
您无法从后台线程更新ui。您可以使用runOnUiThread。
runOnUiThread(new Runnable() //run on ui threa
{
public void run()
{
}
});
我建议你使用asynctask
为此目的使用asynctask。在ui线程上调用onPreExecute(),onPostExecute(),你可以使用它来更新ui。您可以在doInbackground()
中进行背景计算http://developer.android.com/reference/android/os/AsyncTask.html
检查标题“4个步骤”下的主题。
class TheTask extends AsyncTask<Void,Void,Void>
{
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
// background computation and publish progress
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
// update progress bar
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
// cancel the progress bar
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//display progress bar
}
}
在ui线程上加载asynctask
new TheTask().execute().
答案 2 :(得分:0)
您收到的错误是因为您尝试更改辅助线程上的UI组件。您应该阅读this以获取有关如何在Android上使用线程的更多信息。
您可以使用Activity
方法runOnUIThread()
来调用populateList()
方法或在UI(主)线程上进行更新的任何方法。如果您阅读上述文档,您会发现更多相关信息。