Вопрос:

Запуск кода в главном потоке из другого потока

android multithreading kotlin android-handler

237425 просмотра

14 ответа

5546 Репутация автора

В сервисе Android я создал поток (ы) для выполнения некоторых фоновых задач.

У меня есть ситуация, когда поток должен опубликовать определенную задачу в очереди сообщений основного потока, например a Runnable.

Есть ли способ , чтобы получить Handlerиз главного потока и поста Message/ Runnableк нему из другого потока?

Спасибо,

Автор: Ahmed Источник Размещён: 20.06.2012 04:07

Ответы (14)


4 плюса

14332 Репутация автора

Один метод, который я могу придумать, заключается в следующем:

1) Пусть интерфейс привязывается к сервису.
2) Выставьте метод, подобный приведенному ниже, Binderкоторый регистрирует ваш Handler:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) В потоке пользовательского интерфейса вызовите вышеуказанный метод после привязки к сервису:

mBinder.registerHandler(new Handler());

4) Используйте обработчик в ветке Сервиса, чтобы опубликовать вашу задачу:

mHandler.post(runnable);
Автор: Dheeraj V.S. Размещён: 20.06.2012 04:41

562 плюса

71848 Репутация автора

Решение

ПРИМЕЧАНИЕ. Этот ответ привлек столько внимания, что мне нужно его обновить. Поскольку исходный ответ был опубликован, комментарий от @dzeikei привлек почти столько же внимания, как и оригинальный ответ. Итак, вот 2 возможных решения:

1. Если ваш фоновый поток имеет ссылку на Contextобъект:

Убедитесь, что фоновые рабочие потоки имеют доступ к объекту контекста (это может быть контекст приложения или контекст службы). Затем просто сделайте это в фоновом рабочем потоке:

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. Если ваш фоновый поток не имеет (или не нужен) Contextобъект

(предложено @dzeikei):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);
Автор: David Wasser Размещён: 20.06.2012 05:49

132 плюса

1879 Репутация автора

Как правильно указывал нижеприведенный комментарий, это не общее решение для сервисов, а только для потоков, запущенных из вашей деятельности (такой поток может быть сервисом, но не все из них). По сложной теме общения между службой и сервисом, пожалуйста, прочитайте весь раздел «Услуги» официального документа - он сложный, поэтому стоит разобраться с основами: http://developer.android.com/guide/components/services.html #Notifications

Метод ниже может работать в самых простых случаях.

Если я вас правильно понимаю, вам нужно, чтобы какой-то код выполнялся в потоке GUI приложения (не могу думать ни о чем другом, называемом «основным» потоком). Для этого есть метод Activity:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Документ: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Надеюсь, это то, что вы ищете.

Автор: Alexey Vassiliev Размещён: 20.06.2012 10:19

28 плюса

5256 Репутация автора

Если вы запускаете код в потоке, например, задерживаете какое-то действие, вам нужно вызвать его runOnUiThreadиз контекста. Например, если ваш код внутри MainActivityкласса, используйте это:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

Если ваш метод может быть вызван либо из основного (поток пользовательского интерфейса), либо из других потоков, вам нужна проверка, например:

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}
Автор: Alexander Volkov Размещён: 27.09.2013 09:27

28 плюса

393 Репутация автора

Есть еще один простой способ, если у вас нет доступа к контексту.

1). Создайте обработчик из основного петлителя:

Handler uiHandler = new Handler(Looper.getMainLooper());

2). Реализуем интерфейс Runnable:

Runnable runnable = new Runnable() { // your code here }

3). Отправьте свой Runnable на uiHandler:

uiHandler.post(runnable);

Вот и все ;-) Веселитесь с потоками, но не забудьте синхронизировать их.

Автор: tema_man Размещён: 03.07.2015 07:15

2 плюса

32019 Репутация автора

HandlerThread это лучший вариант для нормальных Java-потоков в Android.

  1. Создайте HandlerThread и запустите его
  2. Создайте обработчик с помощью Looper из HandlerThread:requestHandler
  3. postRunnableзадача поrequestHandler

Связь с UI Thread от HandlerThread

  1. Создайте метод Handlerс Looperдля основного потока: responseHandlerи handleMessageметод переопределения
  2. Внутри Runnableзадачи другого Thread ( HandlerThreadв данном случае), звоните sendMessageпоresponseHandler
  3. Этот sendMessageрезультат вызова handleMessageв responseHandler.
  4. Получить атрибуты из Messageи обработать его, обновить интерфейс

Пример : обновление TextViewс данными, полученными от веб-службы. Поскольку веб-служба должна вызываться в потоке, не связанном с пользовательским интерфейсом, созданным HandlerThreadдля работы в сети. Как только вы получите контент от веб-службы, отправьте сообщение обработчику основного потока (поток пользовательского интерфейса), Handlerкоторый обработает сообщение и обновит пользовательский интерфейс.

Образец кода:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

Полезные статьи:

handlerthreads-и-почему-вы-должны-быть, используя их-в-ваш-Android-приложений

Android-петлителя-обработчик-handlerthread-я

Автор: Ravindra babu Размещён: 09.05.2017 12:40

1 плюс

810 Репутация автора

Следуйте этому методу. Используя этот способ, вы можете просто обновить пользовательский интерфейс из фонового потока. runOnUiThread работает в основном потоке (UI). Я думаю, что этот фрагмент кода менее сложный и легкий, особенно для начинающих.

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

в случае услуги

создать обработчик в oncreate

 handler = new Handler();

затем используйте это так

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }
Автор: MarGin Размещён: 19.02.2018 01:42

17 плюса

1339 Репутация автора

Блок сокращенного кода выглядит следующим образом:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

Это не включает передачу ссылки на действие или ссылку на приложение.

Эквивалент Котлина:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })
Автор: david m lee Размещён: 20.02.2018 05:46

2 плюса

469 Репутация автора

Я знаю, что это старый вопрос, но я натолкнулся на одну строчку основного потока, которую я использую и в Kotlin, и в Java. Возможно, это не лучшее решение для службы, но для вызова чего-то, что изменит UI внутри фрагмента, это чрезвычайно просто и очевидно.

Java (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

Котлин:

this.runOnUiThread {
     //your main thread code
}
Автор: mevdev Размещён: 14.06.2018 10:05

0 плюса

1 Репутация автора

public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

Это также может работать в классе обслуживания без проблем.

Автор: Revelation A.F Размещён: 23.08.2018 12:24

0 плюса

1021 Репутация автора

для Kotlin вы можете использовать Anko corountines :

Обновить

doAsync {
   ...
}

осуждается

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}
Автор: Francis Размещён: 17.09.2018 08:00

4 плюса

1043 Репутация автора

Самый простой способ, особенно если у вас нет контекста, если вы используете RxAndroid, вы можете сделать:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}
Автор: Inn0vative1 Размещён: 30.10.2018 03:54

3 плюса

956 Репутация автора

Более точный код Kotlin с использованием обработчика:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }
Автор: Hamed Jaliliani Размещён: 14.01.2019 11:04

0 плюса

16833 Репутация автора

Котлин версии

Когда вы находитесь на деятельности , а затем используйте

runOnUiThread {
    //code that runs in main
}

Когда у вас есть контекст активности , mContext тогда используйте

mContext.runOnUiThread {
    //code that runs in main
}

Когда вы находитесь в месте, где нет контекста , используйте

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}
Автор: Sazzad Hissain Khan Размещён: 02.07.2019 12:14
Вопросы из категории :
32x32