Вопрос по android, ui-thread – Как мы используем runOnUiThread в Android?

132

Я новичок в 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();
                    }
                }
             }
        }));
    }
}

Ваш Ответ

10   ответов
10
runOnUiThread(new Runnable() {
                public void run() {
                //Do something on UiThread
            }
        });
0

Вы можете использовать из этого образца:

В следующем примере мы собираемся использовать эту возможность для публикации результата из поиск по синонимам, обработанный фоновым потоком.

Для достижения цели во время обратного вызова активности OnCreate мы настроим onClickListener для запуска searchTask в созданном потоке.

Когда пользователь нажимает кнопку «Поиск», мы создаем анонимный Runnable класс, который ищет слово, набранное в R.id.wordEt EditText и запускает поток для выполнения Runnable.

Когда поиск завершится, мы создадим экземпляр Runnable SetSynonymResult опубликовать результат обратно в синоним TextView через поток пользовательского интерфейса.

Этот метод иногда не самый удобный, особенно когда мы не иметь доступ к экземпляру Activity; поэтому в следующих главах мы собираюсь обсудить более простые и понятные методы для обновления пользовательского интерфейса из фона вычислительная задача.

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";
    }
}

Source :

Асинхронное программирование Android Helder Vasconcelos

6

Есть несколько методов, использующих runOnUiThread (), позволяет увидеть все

Это мой основной поток (поток пользовательского интерфейса) называется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.) By passing Activity's instance as an argument on worker thread

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.) By using View's post(Runnable runnable) method in worker thread

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.t,extView.setText("Hello!! Android Team :-) From child thread.");
        }
    });

    }
}

3.) By using Handler class from android.os package Если у нас нет контекста (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.");
        }
    });
  }
}
какое-то объяснение могло бы помочь ...
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");


            }
        });
    }
0

Вот как я это использую:

runOnUiThread(new Runnable() {
                @Override
                public void run() {
                //Do something on UiThread
            }
        });
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();

    }
74

Просто оберните его как функцию, затем вызовите эту функцию из фонового потока.

public void debugMsg(String msg) {
    final String str = msg;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mInfo.setText(str);
        }
    });
}
upvote для гораздо менее сложного кода
проголосовал за показ, как получить доступ к данным во внешней области (final)
25

У вас есть это задом наперед. Ваше нажатие кнопки приводит к звонкуrunOnUiThread(), но это не нужно, поскольку обработчик щелчков уже запущен в потоке пользовательского интерфейса. Затем ваш код вrunOnUiThread() запускает новый фоновый поток, в котором вы пытаетесь выполнить операции пользовательского интерфейса, которые затем терпят неудачу.

Вместо этого просто запустите фоновый поток прямо из вашего обработчика кликов. Затем оберните звонкиbtn.setText() внутри звонкаrunOnUiThread().

Спасибо, я понял user1049280
Хорошее объяснение
Хотя это правда, что обработчик кликов уже находится в потоке пользовательского интерфейса, вызовrunOnUiThread() не является необходимым, но это должно быть безвредным. В Javadoc для этого метода написано "Запускает указанное действие в потоке пользовательского интерфейса. Если текущий поток является потоком пользовательского интерфейса, то действие выполняется немедленно. Если текущий поток не является потоком пользовательского интерфейса, действие публикуется в очередь событий потока пользовательского интерфейса. & Quot;
0

Если вы используете фрагмент, просто напишите

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

Ниже приведен исправленный фрагмент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();
}
@Vipul, у меня возник вопрос о ротации телефона: я хочу, чтобы после поворота телефона этот поток запускался, и новый поток не создавался. Можете ли вы дать некоторые советы о том, как предотвратить создание нового потока после поворота телефона?
Разве это не мусор, собранный почти сразу? Вероятно, вам нужно сохранить некоторую ссылку на поток ()
@Nick: сборщик мусора также следит за стеком, то есть, когда поток работает, он не получит GC 'ed.

Похожие вопросы