我们如何在Android中使用runOnUiThread?


157

我是Android的新手,正在尝试使用UI-Thread,因此我编写了一个简单的测试活动。但是我想我误会了一些东西,因为单击按钮后,该应用程序不再响应

public class TestActivity extends Activity {

    Button btn;
    int i = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runThread();
            }
        });
    }

    private void runThread(){
        runOnUiThread (new Thread(new Runnable() {  
            public void run() {
                while(i++ < 1000){
                    btn.setText("#"+i);
                    try {
                        Thread.sleep(300);
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
             }
        }));
    }
}

Answers:


204

以下是更正的runThread功能片段。

private void runThread() {

    new Thread() {
        public void run() {
            while (i++ < 1000) {
                try {
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            btn.setText("#" + i);
                        }
                    });
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}

难道这几乎不是垃圾吗?可能您需要保留对Thread()的一些引用
Nick

14
@Nick:垃圾收集器还会监视堆栈,即当线程运行时,它不会被GC处理。
Miro Kropacek '16

@Vipul,我有一个关于电话旋转的问题:我希望一旦旋转电话,该线程就会运行,并且不会创建新线程。您能否提供一些提示,以防止手机旋转后如何创建新线程?
user1836957

89

只需将其包装为一个函数,然后从后台线程调用此函数即可。

public void debugMsg(String msg) {
    final String str = msg;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mInfo.setText(str);
        }
    });
}

3
因展示如何访问外部范围的数据而被final
赞扬

27

您拥有从头到尾的功能。您的按钮单击导致对的调用runOnUiThread(),但这不是必需的,因为单击处理程序已在UI线程上运行。然后,您的代码runOnUiThread()将启动一个新的后台线程,您尝试在其中执行UI操作,然后该操作将失败。

而是直接从点击处理程序中启动后台线程。然后,将调用包装到btn.setText()的调用中runOnUiThread()


虽然确实确实单击处理程序已经在UI线程中,但是对的调用runOnUiThread()是不必要的,但它应该是无害的。该方法的Javadoc说“在UI线程上运行指定的操作。如果当前线程是UI线程,则立即执行该操作。如果当前线程不是UI线程,则将该操作发布到事件队列中。 UI线程。”
k2col

15
runOnUiThread(new Runnable() {
                public void run() {
                //Do something on UiThread
            }
        });

10

有几种使用runOnUiThread()的技术,让我们看看

这是我的名为AndroidBasicThreadActivity的主线程(UI线程),我将以各种方式从工作线程中进行更新-

public class AndroidBasicThreadActivity extends AppCompatActivity
{
    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_basic_thread);

        textView = (TextView) findViewById(R.id.textview);

        MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
        Thread t1 = new Thread(myTask, "Bajrang");
        t1.start();
    }
}

1.)通过将Activity的实例作为工作线程上的参数传递

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {

        //perform heavy task here and finally update the UI with result this way - 
        activity.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
            }
        });
    }
}

2.)通过在工作线程中使用View的post(Runnable runnable)方法

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {
     //perform heavy task here and finally update the UI with result this way - 
       AndroidBasicThreadActivity.textView.post(new Runnable()
      { 
        @Override
        public void run()
        {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });

    }
}

3.)使用android.os包中的Handler类 如果我们没有上下文(this / getApplicationContext())或Activity的实例(AndroidBasicThreadActivity.this),则必须使用以下Handler类-

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
   public void run()
  {
  //perform heavy task here and finally update the UI with result this way - 
  new Handler(Looper.getMainLooper()).post(new Runnable() {
        public void run() {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });
  }
}

谢谢。.您不仅提到了活动的runOnUIThread,还提到了调用该事件的所有可能方式。.–
arun

谢谢。.您不仅提到了活动的runOnUIThread,还提到了调用该事件的所有可能方式。.–
arun


1

你的这个:

@UiThread
    public void logMsg(final String msg) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                Log.d("UI thread", "I am the UI thread");


            }
        });
    }

1

我们使用Worker Thread使应用程序更流畅并避免ANR。在工作程序Tread中进行了繁重的工作后,我们可能需要更新UI。只能从UI线程更新UI。在这种情况下,我们使用Handler或runOnUiThread都具有在UI Thread中执行的Runnable运行方法。onClick方法在UI线程中运行,因此无需在此处使用runOnUiThread。

使用Kotlin

在活动期间,

this.runOnUiThread {
      // Do stuff
}

从片段,

activity?.runOnUiThread {
      // Do stuff
}

使用Java

this.runOnUiThread(new Runnable() {
     void run() {
         // Do stuff
     }
});

0

您可以从以下示例中使用:

在以下示例中,我们将使用此功能来发布由后台线程处理的同义词搜索的结果。

为了在OnCreate活动回调期间实现目标,我们将设置onClickListener以便在创建的线程上运行searchTask。

当用户单击“搜索”按钮时,我们将创建一个Runnable匿名类,该匿名类搜索R.id.wordEt EditText中键入的单词,并启动执行Runnable的线程。

搜索完成后,我们将创建Runnable SetSynonymResult实例,以通过UI线程将结果发布回同义词TextView上。

有时,这种技术不是最方便的一种,尤其是当我们无法访问Activity实例时;因此,在接下来的章节中,我们将讨论更简单,更干净的技术来从后台计算任务更新UI。

public class MainActivity extends AppCompatActivity {

    class SetSynonymResult implements Runnable {
        String synonym;

        SetSynonymResult(String synonym) {
            this.synonym = synonym;
        }

        public void run() {
            Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
                    synonym, Thread.currentThread().getId()) + " !");
            TextView tv = (TextView) findViewById(R.id.synonymTv);
            tv.setText(this.synonym);
        }
    }

    ;

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

        Button search = (Button) findViewById(R.id.searchBut);
        final EditText word = (EditText) findViewById(R.id.wordEt);
        search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Runnable searchTask = new Runnable() {
                    @Override
                    public void run() {
                        String result = searchSynomim(word.getText().toString());
                        Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
                                word.getText(), Thread.currentThread().getName()));
                        runOnUiThread(new SetSynonymResult(result));
                    }
                };
                Thread thread = new Thread(searchTask);
                thread.start();
            }
        });

    }

    static int i = 0;

    String searchSynomim(String word) {
        return ++i % 2 == 0 ? "fake" : "mock";
    }
}

资料来源

异步android编程Helder Vasconcelos



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

        gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.success1);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //dummy delay for 2 second
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //update ui on UI thread
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        gifImageView.setGifImageResource(R.drawable.success);
                    }
                });

            }
        }).start();

    }

0

试试这个: getActivity().runOnUiThread(new Runnable...

这是因为:

1)在对runOnUiThread的调用中隐式this 是指AsyncTask,而不是您的片段。

2)片段没有runOnUiThread。

但是,活动可以。

请注意,如果您已经在主线程上,那么Activity仅执行Runnable,否则将使用Handler。如果您不想担心它的上下文,则可以在片段中实现Handler,这实际上非常简单:

//一个类实例

private Handler mHandler = new Handler(Looper.getMainLooper());

//代码中的其他任何地方

mHandler.post(<your runnable>);

// ^这将始终在主线程的下一个运行循环上运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.