Як ми використовуємо 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();
                    }
                }
             }
        }));
    }
}

Відповіді:


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'ed.
Miro Kropacek

@Vipul, у мене виникло питання щодо обертання телефону: я хочу, щоб після повернення телефону цей потік запускався, і нова нитка не створюється. Чи можете ви надати підказки, як запобігти створенню нової нитки після повернення телефону?
користувач1836957

89

Просто оберніть його як функцію, а потім викликайте цю функцію з фонової нитки.

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 для цього методу говорить: "Виконує вказану дію на потоці користувальницького інтерфейсу. Якщо поточний потік є потоком UI, то дія виконується негайно. Якщо поточний потік не є потоком UI, дія надсилається до черги подій. потоку інтерфейсу користувача. "
k2col


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.) За допомогою методу публікації View (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 Якщо у нас немає контексту (це / getApplicationContext ()) або екземпляр діяльності (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

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


            }
        });
    }

1

Ми використовуємо Worker Thread, щоб зробити програми більш гладкими та уникнути ANR. Можливо, нам знадобиться оновити інтерфейс користувача після важкого процесу в робочому протекторі. Оновлення інтерфейсу користувача може бути оновлено лише з потоку інтерфейсу користувача. У таких випадках ми використовуємо Handler або runOnUiThread, у яких є метод Runnable run, який виконується в потоці UI. Метод onClick працює в потоці користувальницького інтерфейсу, тому тут не потрібно використовувати runOnUiThread.

Використання Котліна

Перебуваючи у діяльності,

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

Джерело :

асинхронне андроїдне програмування Хелдер Васкончелос


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) неявне це у вашому заклику до runOnUiThread посилається на AsyncTask , а не на ваш фрагмент.

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

Однак Діяльність робить.

Зауважте, що Activity просто виконує Runnable, якщо ви вже в основному потоці, інакше він використовує обробник. Ви можете реалізувати обробник у своєму фрагменті, якщо не хочете турбуватися про контекст цього, насправді це дуже просто:

// Екземпляр класу

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

// в іншому місці коду

mHandler.post(<your runnable>);

// ^ це завжди буде виконуватися у наступному циклі запуску на основній нитці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.