Как мы используем runOnUiThread в Android?

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();
                    }
                }
             }
        }));
    }
}
user1049280
источник

Ответы:

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

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

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

источник
3
проголосовал за то, как показать, как получить доступ к данным во внешней области видимости ( final)
mariotomo
27

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

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

Грэм Борланд
источник
Хотя это правда, что обработчик кликов уже находится в потоке пользовательского интерфейса, вызов к нему runOnUiThread()не нужен, но он должен быть безвредным. Javadoc для этого метода говорит: «Запускает указанное действие в потоке пользовательского интерфейса. Если текущий поток является потоком пользовательского интерфейса, то действие выполняется немедленно. Если текущий поток не является потоком пользовательского интерфейса, действие публикуется в очереди событий. пользовательского интерфейса. "
k2col
15
runOnUiThread(new Runnable() {
                public void run() {
                //Do something on UiThread
            }
        });
Terranology
источник
10

Существует несколько методов использования 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.) Передав экземпляр 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.) С помощью метода представления 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.) Используя класс Handler из пакета android.os. Если у нас нет контекста (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
    }
});
Шивам Ядав
источник
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");


            }
        });
    }
MrGuy
источник
1

Мы используем Worker Thread, чтобы сделать приложения более плавными и избегать ANR. Возможно, нам придется обновить пользовательский интерфейс после тяжелого процесса в рабочем Tread. Пользовательский интерфейс может быть обновлен только из потока пользовательского интерфейса. В таких случаях мы используем Handler или runOnUiThread, и оба имеют метод runnable run, который выполняется в потоке пользовательского интерфейса. Метод onClick выполняется в потоке пользовательского интерфейса, поэтому здесь не нужно использовать 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, чтобы опубликовать результат обратно в синониме 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";
    }
}

Источник :

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


источник
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();

    }
Кешав Гера
источник
0

Попробуй это: getActivity().runOnUiThread(new Runnable...

Это потому что:

1) неявное this в вашем вызове runOnUiThread относится к AsyncTask , а не к вашему фрагменту.

2) Фрагмент не имеет runOnUiThread.

Тем не менее, активность делает.

Обратите внимание, что Activity просто выполняет Runnable, если вы уже находитесь в главном потоке, в противном случае он использует обработчик. Вы можете реализовать обработчик в своем фрагменте, если вы не хотите беспокоиться о контексте этого, на самом деле это очень просто:

// Экземпляр класса

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

// где-нибудь еще в вашем коде

mHandler.post(<your runnable>);

// ^ это всегда будет выполняться при следующем цикле выполнения в главном потоке.

Прадип Кумар
источник