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

в службе android я создал поток (ы) для выполнения некоторых фоновых задач.

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

есть ли способ сделать Handler основного потока и post Message/Runnable Это из моей другой теме ?

спасибо,

11 ответов


Примечание: этот ответ получил так много внимания, что мне нужно обновить его. Поскольку оригинальный ответ был опубликован, комментарий от @dzeikei получил почти столько же внимания, сколько и оригинальный ответ. Итак, вот 2 возможных решения:

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


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

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

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

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

Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

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


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

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

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

2). Реализовать интерфейс Runnable:

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

3). Опубликуйте свой Runnable в uiHandler:

uiHandler.post(runnable);

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


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

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

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

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

}

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

   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
    })

один метод, который я могу придумать, это:

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

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

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

mBinder.registerHandler(new Handler());

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

mHandler.post(runnable);

HandlerThread лучший вариант для обычных потоков java в Android .

  1. создать HandlerThread и запустить его
  2. создать проводник С петлителя из HandlerThread:requestHandler
  3. post a Runnable задачи requestHandler

связь с потоком пользовательского интерфейса от HandlerThread

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

пример: Update TextView С данными, полученными от веб-службы. Поскольку веб-служба должна вызываться в потоке, отличном от UI, created HandlerThread для работы в Сети. Как только вы получите содержимое из веб-службы, отправьте сообщение в обработчик основного потока (UI Thread) и это 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-and-why-you-should-be-using-them-in-your-android-apps

android-петлитель-обработчик-handlerthread-i


следуйте этому методу. Используя этот способ вы можете просто обновить UI из фонового потока. 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);
    }

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

Java (8):

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

Котлин:

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

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

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


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

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}