Доступ до обробника потоку інтерфейсу користувача зі служби


90

Я пробую щось нове на Android, для чого мені потрібно отримати доступ до обробника потоку інтерфейсу користувача.

Я знаю наступне:

  1. Потік інтерфейсу користувача має власний обробник та петлювач
  2. Будь-яке повідомлення буде поміщено в чергу повідомлень потоку інтерфейсу користувача
  3. Петель забирає подію та передає обробнику
  4. Обробник обробляє повідомлення та надсилає конкретну подію в інтерфейс користувача

Я хочу мати свою службу, яка повинна отримати обробник потоку інтерфейсу користувача та помістити повідомлення в цей обробник. Таким чином, це повідомлення буде оброблено та видано користувацькому інтерфейсу. Тут послуга буде звичайною службою, яку запускатиме якась програма.

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

З повагою Гіріш

Відповіді:


179

Цей фрагмент коду створює обробник, пов'язаний з основним потоком (UI):

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

Потім ви можете опублікувати матеріали для виконання в основному (UI) потоці так:

handler.post(runnable_to_call_from_main_thread);

Якщо сам обробник створений з основного потоку (UI), аргумент можна опустити для стислості:

Handler handler = new Handler();

Android Dev Керівництво по процесам і потокам має більше інформації.


2
Перевірив, і це чудово працює! Приклад варіанту використання: У мене є веб-інтерфейс, який обслуговується сервером, що працює безпосередньо на пристрої. Оскільки інтерфейс може використовуватися для безпосередньої взаємодії з інтерфейсом користувача, а оскільки сервер повинен працювати на власному потоці, мені потрібен був спосіб торкнутися потоку інтерфейсу ззовні активності. Описаний вами метод чудово спрацював.
mrPjer

1
Блискуче. Працює як шарм, і дуже корисний. ДЯКУЮ.
JRun,

perfect ^^ просто використовував його для оновлення мого інтерфейсу користувача з StreamingService. саме те, що мені потрібно було спасибі!
Ан-дроїд

чи знаєте ви, чи можу я створити односторонній екземпляр обробника і використовувати це кожен раз, коли мені потрібно щось запускати в потоці інтерфейсу користувача?
HelloWorld

Гадаю, ми ніколи не дізнаємось
Денні

28

Створіть Messengerоб’єкт, прикріплений до вашого, Handlerі передайте Messengerйого Service(наприклад, в Intentдодатковий для startService()). Потім Serviceможна надіслати a Messageна за Handlerдопомогою Messenger. Ось зразок програми, що демонструє це.


Дякую за цю пораду. Це було корисно. Будь ласка, перегляньте наступний стек для потоку подій дотику до моєї активності MyDemo.dispatchTouchEvent (MotionEvent) рядок: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) рядок: 1696 ViewRoot.handleMessage (повідомлення) рядок: 1658 ViewRoot (Handler) .dispatchMessage ) line: 99 Looper.loop () line: 123 // Обробка подій починається тут ActivityThread.main (String []) line: 4203 Тут ViewRoot є обробником. Я хочу отримати посилання на цей обробник ... чи можна це отримати з моєї програми?
iLikeAndroid

@iLikeAndroid: Якщо ви не створили файл Handler, ви не можете отримати до нього доступ, AFAIK.
CommonsWare

Дякую. Я намагався створити екземпляр ViewRoot. Це не що інше, як обробник. Тепер я можу видавати повідомлення на цьому обробнику. Обробник отримує повідомлення. Але ViewRoot не може обробити повідомлення, оскільки воно не ініціалізоване належним чином. Мені потрібно зателефонувати ViewRoot.setView (), щоб ініціалізувати відповідні дані у ViewRoot. Я хочу знати, чи існує перегляд за замовчуванням чи базовий вигляд тощо, який я можу використовувати для ініціалізації?
iLikeAndroid

@iLikeAndroid: В ViewRootAndroid SDK немає, AFAICT.
CommonsWare

1
@ hadez30: Особисто я не надто користуюся прив'язаними послугами. Ви все ще можете використовувати a Handler/ Messenger, хоча я б замінив все це на шину подій (наприклад, EventBus greenrobot).
CommonsWare

4

На даний момент я вважаю за краще використовувати бібліотеку шин подій, таку як Отто, для такого роду проблем. Просто підпишіться на бажані компоненти (діяльність):

protected void onResume() {
    super.onResume();
    bus.register(this);
}

Потім надайте метод зворотного виклику:

public void onTimeLeftEvent(TimeLeftEvent ev) {
    // process event..
}

а потім, коли ваша служба виконує таку заяву:

bus.post(new TimeLeftEvent(340));

Цей POJO буде передано вашій вищезазначеній діяльності та всім іншим компонентам, що підписуються. Просто і елегантно.


3

Я пропоную спробувати такий код:

    new Handler(Looper.getMainLooper()).post(() -> {

        //UI THREAD CODE HERE



    });

Для надання допомоги ОП потрібні додаткові пояснення.
Moog

2

Ви можете отримати значення через широкомовний приймач ...... наступним чином. Спочатку створіть власний IntentFilter як,

Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");

Потім створіть внутрішній клас BroadcastReceiver як,

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    /** Receives the broadcast that has been fired */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction()=="YOUR_INTENT_FILTER"){
           //HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
           String receivedValue=intent.getStringExtra("KEY");
        }
    }
};

Тепер зареєструйте свій широкомовний приймач у програмі onResume () як,

registerReceiver(broadcastReceiver, intentFilter);

І нарешті, скасуйте реєстрацію BroadcastReceiver у onDestroy () як,

unregisterReceiver(broadcastReceiver);

Тепер найголовніша частина ... Вам потрібно запускати трансляцію звідки вам потрібно надіслати значення ..... так що,

Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);

.... ура :)


1

В kotlinтой як ви можете це зробити

Скажіть, якщо ви хочете показати тост від служби

val handler = Handler(Looper.getMainLooper())
handler.post {
   Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}

0

Рішення:

  1. Створіть обробник за допомогою Looper з Main Thread: requestHandler
  2. Створіть за Handlerдопомогою LooperMain Thread: responseHandler і handleMessageметод override
  3. розмістити Runnable завдання на RequestHandler
  4. Усередині Runnableзавдання викличте sendMessage на responseHandler
  5. Цей sendMessageрезультат викликає handleMessage у responseHandler.
  6. Отримати атрибути з Messageі обробити його, оновити інтерфейс

Зразок коду:

    /* Handler from UI Thread to send request */

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

     /* Handler from UI Thread to process messages */

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {

            /* Processing handleMessage */

            Toast.makeText(MainActivity.this,
                    "Runnable completed with result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<10; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {
                   /* Send an Event to UI Thread through message. 
                      Add business logic and prepare message by 
                      replacing example code */

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.