Java Android在单独线程中更新按钮背景

Java Android在单独线程中更新按钮背景,java,android,multithreading,asynchronous,Java,Android,Multithreading,Asynchronous,我有一堆按钮(自定义,使用一些额外的方法应用其他背景,并还原为原始),可以指定一个背景。但由于我不知道这些背景会有多大,我决定在一个单独的线程中设置背景。首先,我有以下代码: public void updateButton(final Button b, final String d, final String s) { b.nullify(); //Recycles previous background, else OOM error b.setText(s); i

我有一堆按钮(自定义,使用一些额外的方法应用其他背景,并还原为原始),可以指定一个背景。但由于我不知道这些背景会有多大,我决定在一个单独的线程中设置背景。首先,我有以下代码:

public void updateButton(final Button b, final String d, final String s) {
    b.nullify(); //Recycles previous background, else OOM error
    b.setText(s);
    if (d != null) {
        new Thread() {
            @Override
            public void run() {
                b.setBackgroundFromBase64(d);
            }
        }.run();
    }
    else b.setBackgroundToDefault(); //Sets standard android background
}
但我很快就发现这不是我要走的路。慢慢地,当我调用这个方法几千次时,内存被淹没了。当我删除
new Thread()
部分时,内存没有被淹没,因此线程是导致此问题的原因(内存分析器工具告诉我同样的情况)

然后我尝试了
AsyncTask

private class UpdateButtonTask extends AsyncTask<Object, Void, Void> {
    @Override 
    protected Void doInBackground(Object... objs) {
        String s = (String)objs[0];
        Button b = (Button)objs[1];
        String d = (String) objs[2];
        b.nullify(); //Recycles previous background, else OOM error
        b.setText(s);
        if (d != null) b.setBackgroundFromBase64(d);
        else b.setBackgroundToDefault();
        return null;
     }
     @Override
     protected void onProgressUpdate(Void v) {
         //As far as I know, I don't need this method
     }
     @Override
     protected void onPostExecute(Void v) {
         //Neither this one
     }
 }
在按钮更新方法中。但这也不起作用(按钮根本没有更新。没有文本,没有自定义背景)。我读了一些关于线程的文章和问题(,等等),但我似乎无法让它工作。目前,没有线程,希望手机速度足够快,不会在UI线程上造成麻烦似乎是最好的选择,但我宁愿有更可靠的东西,比如线程。
我做错了什么?或者可能只是一个完整的问题如何更新背景线程上的按钮背景(这样在应用较大背景时UI不会停止工作)

我猜问题在于您试图在非UI线程上更新UI。这会引发异常并终止您的
AsyncTask

您应该将处理密集型任务与
AsyncTask
分开,然后在主线程上应用UI更改(使用
runOnUiThread(Runnable)

由于您使用的是自定义按钮,我真的不知道在非UI线程上不允许做什么。如果您没有重写它,我猜
setText
函数会导致问题


您应该首先将
doInBackground
方法的整个主体包装在
try/catch
块中,并记录异常以隔离问题。

这段代码可能会对您有所帮助

new Thread(new Runnable() {

public void run() {

context.runOnUiThread(new Runnable() {

public void run() {
      b.setBackgroundFromBase64(d);
}

});

}

}).start();

首先,使用
Thread
的解决方案没有生成单独的线程,您只是在匿名类的同一线程上运行
run()
方法。您应该使用
Thread.start()
在单独的线程中运行它。但是无论如何,你不应该使用
线程
,所以别担心。其次,请您详细说明
AsyncTask
的解决方案如何不起作用?预期会发生什么?请参见补充。按钮根本没有更新。没有自定义背景,没有按钮上的文本。这段代码不会影响我不希望UI线程等待它的想法?或者它仍然是一条不同的线?抱歉,有点混乱。此代码将运行一个独立于UI线程的线程,该线程将排队
b.setBackgroundFromBase64(d)
返回到UI线程,有效地执行与只调用
b.setBackgroundFromBase64(d)相同的操作首先从UI线程开始。我使用相同的代码在每个单元格的ListView中设置图像。以避免列表视图中的抖动效应。您还可以使用onPostExecute(),它保证位于启动异步任务的处理程序上。我假设您在UI线程上启动了异步任务。通常最好在UI线程上更新视图组件,以避免此类问题。大多数时候,它们并没有那么密集,因为实际的抽签是在一个单独的步骤中进行的。
new Thread(new Runnable() {

public void run() {

context.runOnUiThread(new Runnable() {

public void run() {
      b.setBackgroundFromBase64(d);
}

});

}

}).start();