我们如何在 Android 中使用 runOnUiThread?

Posted

技术标签:

【中文标题】我们如何在 Android 中使用 runOnUiThread?【英文标题】:How do we use runOnUiThread in Android? 【发布时间】:2012-06-23 19:31:01 【问题描述】:

我是 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();
                    
                
             
        ));
    

【问题讨论】:

【参考方案1】:

下面是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:垃圾收集器也监视堆栈,即当线程运行时,它不会被 GC'ed。 @Vipul,我有一个关于手机旋转的问题:我希望一旦我旋转手机,这个线程就会运行并且不会创建新线程。您能否提供一些有关如何防止手机旋转后创建新线程的提示?【参考方案2】:

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

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

【讨论】:

赞成展示如何访问外部范围内的数据 (final)【参考方案3】:

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

相反,只需直接从您的点击处理程序启动后台线程。然后,将对btn.setText() 的调用封装在对runOnUiThread() 的调用中。

【讨论】:

虽然点击处理程序确实已经在 UI 线程中,但调用 runOnUiThread() 是不必要的,但它应该是无害的。该方法的 Javadoc 说“在 UI 线程上运行指定的操作。如果当前线程是 UI 线程,则立即执行该操作。如果当前线程不是 UI 线程,则将该操作发布到事件队列UI 线程。”【参考方案4】:
runOnUiThread(new Runnable() 
                public void run() 
                //Do something on UiThread
            
        );

【讨论】:

【参考方案5】:

runOnUiThread()有几种使用技巧,让我们看看全部

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

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,而是提到了所有可能的调用方式.. 谢谢.. 您没有重复关于活动的runOnUIThread,而是提到了所有可能的调用方式..【参考方案6】:

如果在片段中使用,那么只需编写

getActivity().runOnUiThread(new Runnable() 
    @Override
    public void run() 
        // Do something on UiThread
    
);

【讨论】:

【参考方案7】:

我们使用 Worker Thread 使应用程序更流畅并避免 ANR。在 worker Tread 繁重的过程之后,我们可能需要更新 UI。 UI 只能从 UI Thread 更新。在这种情况下,我们使用 Handler 或 runOnUiThread 都有一个在 UI Thread 中执行的 Runnable run 方法。 onClick 方法在 UI 线程中运行,所以这里不需要使用 runOnUiThread。

使用 Kotlin

在活动中,

this.runOnUiThread 
      // Do stuff

从片段,

activity?.runOnUiThread 
      // Do stuff

使用 Java

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

【讨论】:

【参考方案8】:

你的这个:

@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");


            
        );
    

【讨论】:

【参考方案9】:

对于fragment,请使用:

requireActivity().runOnUiThread(() -> 
//your code logic
);

对于activity,请使用:

runOnUiThread(() -> 
//your code logic
);

runOnUiThread 用于通过我们的后台线程更新 UI。更多信息:https://www.tutorialspoint.com/how-do-we-use-runonuithread-in-android

【讨论】:

【参考方案10】:

您可以从此示例中使用:

在以下示例中,我们将使用此工具从 由后台线程处理的同义词搜索。

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

当用户点击 Search 按钮时,我们将创建一个 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";
    

来源

asynchronous android programming Helder Vasconcelos

【讨论】:

【参考方案11】:

我就是这样使用它的:

runOnUiThread(new Runnable() 
                @Override
                public void run() 
                //Do something on UiThread
            
        );

【讨论】:

【参考方案12】:
  @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();

    

【讨论】:

【参考方案13】:

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

因为:

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

2) 片段没有 runOnUiThread。

但是,Activity 可以。

请注意,如果您已经在主线程上,Activity 只会执行 Runnable,否则它会使用 Handler。如果你不想担心上下文,你可以在你的片段中实现一个处理程序,这实际上很容易:

// 一个类实例

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

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

mHandler.post(<your runnable>);

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

【讨论】:

以上是关于我们如何在 Android 中使用 runOnUiThread?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在 android 的 RecyclerView 片段中使用 bottomSheet?

我们如何在 Scala 中使用 android JobIntentService?

如何在我们的 Android 应用程序中使用默认密码锁屏?

如果我们在 Android 中使用位置 API 给出纬度和经度,如何获取地址

如何使用具有分辨率切换能力的原生 Android 制作视频播放器,就像我们在 YouTube 中看到的那样?

我们如何在 firebase(android、kotlin)中记录错误?