从线程更新UI

我想从更新进度条的线程更新我的用户界面。 不幸的是,当从“runnable”更新进度条的drawable时,进度条消失了! 在其他人的作品中更改onCreate()的进度条绘图!

有什么build议么?

 public void onCreate(Bundle savedInstanceState) { res = getResources(); super.onCreate(savedInstanceState); setContentView(R.layout.gameone); pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/ handler.postDelayed(runnable, 1); } private Runnable runnable = new Runnable() { public void run() { runOnUiThread(new Runnable() { public void run() { //* The Complete ProgressBar does not appear**/ pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); } }); } } 

你应该在AsyncTask (一个智能的backround线程)和ProgressDialog的帮助下做到这一点

AsyncTask支持正确和简单地使用UI线程。 这个类允许执行后台操作并在UI线程上发布结果,而不必操作线程和/或处理程序。

asynchronous任务由在后台线程上运行的计算来定义,并且其结果在UI线程上发布。 asynchronous任务由3个genericstypes定义,称为Params,Progress和Result,以及4个步骤,分别称为begin,doInBackground,processProgress和end。

这4个步骤

当一个asynchronous任务被执行时,任务要经过4个步骤:

onPreExecute()在执行任务后立即在UI线程上调用。 此步骤通常用于设置任务,例如通过在用户界面中显示进度条。

doInBackground(Params...) ,在onPreExecute()完成执行后立即在后台线程上调用。 此步骤用于执行可能需要很长时间的后台计算。 asynchronous任务的parameter passing到这一步。 计算结果必须通过这一步返回,并返回到最后一步。 此步骤还可以使用publishProgress(Progress …)发布一个或多个进度单元。 这些值在onProgressUpdate(Progress …)步骤的UI线程上发布。

onProgressUpdate(Progress...) ,在调用publishProgress(Progress …)之后在UI线程上调用。 执行的时间是不确定的。 此方法用于在后台计算仍在执行时在用户界面中显示任何forms的进度。 例如,它可以用来animation进度条或在文本字段中显示日志。

onPostExecute(Result) ,在后台计算完成后在UI线程上调用。 后台计算的结果作为parameter passing到这一步。 线程规则

有一些线程规则必须遵循这个类才能正常工作:

任务实例必须在UI线程上创build。 必须在UI线程上调用execute(Params …)。 不要手动调用onExcute(),onPostExecute(Result),doInBackground(Params …),onProgressUpdate(Progress …)。 该任务只能执行一次(如果尝试执行第二次执行,则会引发exception)。

示例代码
这个例子中的适配器并不重要,理解你需要使用AsyncTask来显示进度的对话框。

 private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > { ProgressDialog dialog; @Override protected void onPreExecute() { dialog = new ProgressDialog(viewContacts.this); dialog.setMessage(getString(R.string.please_wait_while_loading)); dialog.setIndeterminate(true); dialog.setCancelable(false); dialog.show(); } /* (non-Javadoc) * @see android.os.AsyncTask#doInBackground(Params[]) */ @Override protected ContactsListCursorAdapter doInBackground(Void... params) { cur1 = objItem.getContacts(); startManagingCursor(cur1); adapter1 = new ContactsListCursorAdapter (viewContacts.this, R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {}); return adapter1; } protected void onPostExecute(ContactsListCursorAdapter result) { list.setAdapter(result); dialog.dismiss(); } } 

我所见过的最简单的解决scheme是通过视图的post()方法向UI线程提供短执行。 由于UI方法不可重入,因此这是必需的。 这个方法是:

 package android.view; public class View; public boolean post(Runnable action); 

post()方法对应于SwingUtilities.invokeLater()。 不幸的是,我没有find与SwingUtilities.invokeAndWait()相对应的简单东西,但是可以使用监视器和标志来构build基于前者的后者。

所以你保存的是创build一个处理程序。 你只需要find你的观点,然后发布。 如果您倾向于使用id资源,则可以通过findViewById()来查看您的视图。 由此产生的代码非常简单:

 /* inside your non-UI thread */ view.post(new Runnable() { public void run() { /* the desired UI update */ } }); } 

注意:与SwingUtilities.invokeLater()方法相比,View.post()方法返回一个布尔值,指示视图是否有关联的事件队列。 由于我使用了invokeLater()和 post()反正只是为了火而忘了,我没有检查结果值。 基本上你应该只在调用onAttachedToWindow()之后调用post()。

最好的祝福

如果你使用Handler (我看到你做了,希望你在UI线程上创build它的实例),那么不要在你的runnable使用runOnUiThread()runOnUiThread()用于从非UI线程中runOnUiThread() ,但是Handler已经在UI线程上执行了你的runnable

试着做这样的行为:

 private Handler mHandler = new Handler(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gameone); res = getResources(); // pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works** mHandler.postDelayed(runnable, 1); } private Runnable runnable = new Runnable() { public void run() { pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); pB.invalidate(); // maybe this will even not needed - try to comment out } }; 

使用AsyncTask类(而不是Runnable)。 它有一个名为onProgressUpdate的方法,它可以影响UI(它在UI线程中调用)。

您需要在UI线程中创build一个Handler ,然后使用它来发布或从其他线程发送消息来更新UI

如果你不喜欢AsyncTask,你可以使用观察者模式 。 在这个例子中,在你的活动中使用ResponseHandler作为内部类,然后有一个string消息来设置进度条百分比…你需要确保在ResponseHandler中执行对UI的任何更改以避免冻结UI,那么你的工作线程(例子中的EventSource)就可以执行所需的任务。

我会使用AsyncTask寿,但观察者模式可以很好的定制原因,加上它更容易理解。 也不知道这种方式是被广泛接受或将100%的工作。 我下载和android插件现在来testing它

按照官方文档的build议,您可以使用AsyncTask 处理短于5ms的工作项目 。 如果你的任务需要更多的时间,寻找其他的select。

HandlerThread是ThreadAsyncTask一个替代scheme。 如果您需要从HandlerThread更新UI,请在UI Thread Looper上发布消息,UI Thread Handler可以处理UI更新。

示例代码:

Android:在一个线程中吐司