从Thread更新UI

Fil*_*lly 53 user-interface multithreading android

我想从更新Progressbar的Thread更新我的UI.不幸的是,当从"runnable"更新进度条的drawable时,进度条消失了!改变进度onCreate()栏的绘图可用于其他工作!

有什么建议?

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)); 
            } 
        }); 
    }
}
Run Code Online (Sandbox Code Playgroud)

Pen*_*m10 62

你应该在AsyncTask(智能后台线程)和ProgressDialog的帮助下完成这项工作

AsyncTask可以正确,方便地使用UI线程.此类允许执行后台操作并在UI线程上发布结果,而无需操作线程和/或处理程序.

异步任务由在后台线程上运行的计算定义,其结果在UI线程上发布.异步任务由3种泛型类型定义,称为Params,Progress和Result,以及4个步骤,分别称为begin,doInBackground,processProgress和end.

这4个步骤

执行异步任务时,任务将执行4个步骤:

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

doInBackground(Params...),在onPreExecute()完成执行后立即在后台线程上调用.此步骤用于执行可能需要很长时间的后台计算.异步任务的参数将传递给此步骤.计算结果必须由此步骤返回,并将传递回最后一步.此步骤还可以使用publishProgress(Progress ...)发布一个或多个进度单元.这些值发布在UI线程的onProgressUpdate(Progress ...)步骤中.

onProgressUpdate(Progress...),在调用publishProgress(Progress ...)后在UI线程上调用.执行的时间是不确定的.此方法用于在后台计算仍在执行时显示用户界面中的任何形式的进度.例如,它可用于为进度条设置动画或在文本字段中显示日志.

onPostExecute(Result),在后台计算完成后在UI线程上调用.背景计算的结果作为参数传递给该步骤.线程规则

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

必须在UI线程上创建任务实例.必须在UI线程上调用execute(Params ...).不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params ...),onProgressUpdate(Progress ...).该任务只能执行一次(如果尝试第二次执行,则会抛出异常.)

示例代码
适配器在此示例中的作用并不重要,更重要的是要了解您需要使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • "理想情况下,AsyncTasks应该用于短时间操作(最多只需几秒钟.)[...]" - http://developer.android.com/reference/android/os/AsyncTask.html (5认同)

Tra*_*ers 25

我看到为UI线程提供简短执行的最简单的解决方案是通过视图的post()方法.这是必需的,因为UI方法不是可重入的.方法是:

package android.view;

public class View;

public boolean post(Runnable action);
Run Code Online (Sandbox Code Playgroud)

post()方法对应于SwingUtilities.invokeLater().不幸的是,我没有找到与SwingUtilities.invokeAndWait()相对应的简单内容,但是可以使用监视器和标志来构建后者.

所以你节省的是创建一个处理程序.您只需找到您的视图,然后在其上发布.如果您倾向于使用id-ed资源,可以通过findViewById()找到您的视图.结果代码非常简单:

/* inside your non-UI thread */

view.post(new Runnable() {
        public void run() {
            /* the desired UI update */
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

注意:与SwingUtilities.invokeLater()相比,方法View.post()确实返回一个布尔值,指示视图是否具有关联的事件队列.因为我使用了invokeLater()resp.post()无论如何只是为了火而忘记,我没有检查结果值.基本上你应该在视图上调用onAttachedToWindow()之后调用post().

最好的祝福


pab*_*han 11

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


Vit*_*nko 11

如果你使用Handler(我看到你做了,希望你在UI线程上创建了它的实例),那么就不要runOnUiThread()在你的内部使用runnable.runOnUiThread()当您从非UI线程执行smth时使用,但是Handler已经执行了您runnable的UI线程.

试着像这样做:

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
    }
};
Run Code Online (Sandbox Code Playgroud)


Nat*_*ann 9

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