从Android中的后台线程更新UI

时间:2016-11-06 03:38:51

标签: android

编辑:有人建议添加我的代码会很有帮助,我的AsyncTask代码现在粘贴在下面......

我刚刚学习Android,而且我有一个带有几个按钮的用户界面。我想按顺序为UI设置动画,更改按钮的颜色。

当然,我不应该从主线程中做到这一点,而且无论如何它都不起作用。操作UI的代码会运行,但UI不会更新,直到序列结束。

所以我创建了一个线程并尝试从后台线程运行序列,但是,我会在尝试从后台线程中操作UI组件时出错。只有主线程可以触摸UI组件。

然后我发现了AsyncTask。我想的是,我可以在doInBackground()中运行序列。每次我需要更新UI时,我都会调用publishProgress(),这会导致从主线程调用onProgressUpdate(),这样我就可以毫无错误地访问UI组件。

每当我调用publishProgress()时,我都会使用SystemClock.sleep(500)跟随它,让时间过去,直到下一个动画UI更新。

我发现doInBackground()会在大约2秒内(每个500毫秒)运行4个UI状态更改,但每次调用publishProgress()时UI都不会更新。而是doInBackground()完成,然后连续4次调用onProgressUpdate()。

从描述中可以看出,发布进度和出版物onProgressUpdate旨在更新进度条,因为doInBackground通过一些长时间运行的任务进行曲柄处理,因此,显然onProgressUpdate必须在doInBackground完成之前执行多次,对吧?

我错过了什么吗?

公共类MainActivity扩展了AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void startGame(View view) {
    MyTask task = new MyTask();
    task.doInBackground();
}


class MyTask extends AsyncTask<Void,Void,Void> {

    private int current_int;


    @Override
    protected Void doInBackground(Void... voids) {
        this.current_int = 1;
        Log.e("doInBackground","light up button "+this.current_int);
        publishProgress();
        SystemClock.sleep(500);
        this.current_int = 2;
        Log.e("doInBackground","light up button "+this.current_int);
        publishProgress();
        SystemClock.sleep(500);
        this.current_int = 1;
        Log.e("doInBackground","light up button "+this.current_int);
        publishProgress();
        SystemClock.sleep(500);
        this.current_int = 2;
        Log.e("doInBackground","light up button "+this.current_int);
        publishProgress();
        SystemClock.sleep(500);

        return null;
    }

    @Override
    protected void onProgressUpdate(Void... voids) {
        super.onProgressUpdate(voids);
        Log.e("onProgressUpdate","Updating button "+this.current_int);

        Button btn1 = (Button) findViewById(R.id.button1);
        Button btn2 = (Button) findViewById(R.id.button2);

        if (this.current_int==1){
            btn1.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
            btn2.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_dark));
        } else {
            btn2.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
            btn1.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_dark));
        }
    }
}

}

3 个答案:

答案 0 :(得分:1)

仅供参考:Asynctask提供了一种从主线程(调用线程)转换到新线程(称为线程)的系统方法。 onPreExecute() onPostExecute()方法在调用线程上执行, doInBackground()是实际的在新线程上执行的方法。因此,如果从 doInBackground()方法完成,则在主线程上执行UI更新将导致异常。

因此,您的核心背景逻辑应放在 doInBackground()方法中。

如果要从后台线程(Asynctask或其他)更新UI,可以使用以下命令来执行:

YourActivity.this.runOnUiThread(new Runnable(){
    @Override
    public void run()
    {
          //UI update operations here
    }
});

答案 1 :(得分:0)

您可以使用Handler

public class TestClass extends AsyncTask<Void,Void,Void> {
    boolean isRunning = true; //set false after executing UI logic.
    Handler mHandler = new Handler();
    @Override
    protected Void doInBackground(Void... params) {
        YourFunctionToUpdateUI();
        return null;
    }
    public void YourFunctionToUpdateUI()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                // your code to update the UI.
                            }
                        });
                    } catch (Exception e) {
                        //handle exception
                    }
                }
            }
        }).start();
    }
}

答案 2 :(得分:0)

我是个白痴。问题是,我正在创建一个AsyncTask然后直接从我的主线程调用doInBackground()而不是调用execute()来创建后台线程