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

Вот моя проблема: для упрощения я использую IntentService, который обрабатывает пару сообщений с использованием объекта Messenger, первое сообщение (msg.what==1) запускает 10-секундный процесс, второе (msg.what==2) запустить 5-секундный процесс. Эти сообщения отправляются сторонней активностью, которая привязана к моей службе и ожидает ответа на эти отправленные сообщения.

Все работает нормально, но если сообщение 1 запущено, при отправке сообщения 2 оно будет ждать, пока не будет выполнен первый процесс для обработки. Когда я прочитал это, ожидаемое поведение с Intent Service (сообщения ставятся в очередь и обрабатываются последовательно во внешнем потоке).

Но есть ли способ получить асинхронный ответ на новое отправленное сообщение, когда предыдущее все еще выполняется? (т.е. получить ответ на сообщение 2, когда сообщение 1 все еще выполняется) Я пытался использовать поток и asynctask для моей функции handleMessage безуспешно (я даже не получаю ответа на свой запрос в действии)

Класс обслуживания: обработчик

    class IncomingHanlder extends Handler {
    @Override
    public void handleMessage(Message msg)  {
        try {
            switch (msg.what) {

                case 1:
                    //Process taking 10 sec
                    //...

                    //Reply to client
                    Message resp = Message.obtain(null, msg.what);
                    Bundle bResp = new Bundle();
                    bResp.putBoolean("com.xxx.msg1", true);
                    resp.setData(bResp);
                    msg.replyTo.send(resp);
                    break;

                case 2:
                    //Process taking 5 sec
                    //...

                    //Reply to client
                    Message resp = Message.obtain(null, msg.what);
                    Bundle bResp = new Bundle();
                    bResp.putBoolean("com.xxx.msg2", true);
                    resp.setData(bResp);
                    msg.replyTo.send(resp);
                    break;

                default:
                    super.handleMessage(msg);
            }
        }
            catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

private Messenger msg = new Messenger(new IncomingHanlder ());

@Override
public IBinder onBind(Intent arg0) {return msg.getBinder();}

Класс клиента: активность (стороннее приложение)

ServiceConnection sConn = new ServiceConnection() {

            @Override
            public void onServiceDisconnected(ComponentName name) {
                messenger = null;
            }

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // We are connected to the service
                messenger = new Messenger(service);
            }
        };

        // We bind to the service
        Intent i = new Intent("com.xxx.myserviceboundpackage");
        try {
            //If service is always launched
            stopService(i);
        }
        catch (Exception e){}

        //Bind to service
        bindService(i, sConn,
                Context.BIND_AUTO_CREATE);

В клиенте: отправка сообщения нажатием кнопки (например, сообщение 1)

                try {
                Message msg = Message
                        .obtain(null, 1);

                msg.replyTo = new Messenger(new ResponseHandler());;

                try {
                    messenger.send(msg);
                } catch (RemoteException e) {

                }
            }
            catch (Exception e)
            {
                e.printstacktrace();
            }

В клиенте: обработка сообщения от ответа службы на

    class ResponseHanlder extends Handler {
    @Override
    public void handleMessage(Message msg)  {
        try {
            switch (msg.what) {

                //Response to each request
                case 1:
                    //Process which have taken 10 sec

                    Bundle bundle = msg.getData();
                    Boolean myResp = bundle.getBoolean("com.xxx.msg1");
                    if (myResp) {//do something}
                    break;

                case 2:
                    //Process which have taken 5 sec

                    Bundle bundle = msg.getData();
                    Boolean myResp = bundle.getBoolean("com.xxx.msg2");
                    if (myResp) {//do something}
                    break;

                default:
                    super.handleMessage(msg);
            }
        }
            catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

Спасибо за предложение.


person Valentin    schedule 02.12.2015    source источник
comment
чего собственно вы хотите добиться?   -  person pskink    schedule 02.12.2015
comment
Просто представьте, что я отправляю сообщение 1 и сразу же отправляю сообщение 2 из своей активности. Сообщение 2 обрабатывается не сразу, оно ставится в очередь. Итак, я получаю ответ через 10 секунд (обработка сообщения 1) + 5 секунд (обработка сообщения 2, поставленного в очередь). Я хотел бы получить свой ответ на сообщение 2 только через 5 секунд (не дожидаясь завершения процесса сообщения 1)   -  person Valentin    schedule 02.12.2015
comment
он поставлен в очередь, так как вы используете IntentService, который использует один фоновый поток для всех запросов, если вы хотите немедленно обрабатывать свои сообщения, используйте подход "one Message - one Thread"   -  person pskink    schedule 02.12.2015
comment
Можете ли вы привести примеры, если такой подход использует двусторонний диалог между действием и услугой?   -  person Valentin    schedule 02.12.2015
comment
см. pastebin.com/L1m3NJTT   -  person pskink    schedule 02.12.2015
comment
Спасибо, попробую и вернусь!   -  person Valentin    schedule 02.12.2015
comment
Хорошо, я прочитал пример кода, и если я правильно его понимаю, при привязке со стороны клиента вы получаете класс B (который должен быть известен клиенту), и вы можете запустить свой длительный процесс, используя что-то вроде: myBobject. запустить что-то (100); Есть ли способ добиться такой же логики, используя мессенджер с классом обслуживания? Я имею в виду сохранение формы моего кода: активность отправляет сообщение службе, которая обрабатывает его в пуле потоков, затем обрабатывает его и отвечает, как только оно будет завершено, позволяя обрабатывать другие сообщения в параллельной задаче?   -  person Valentin    schedule 02.12.2015
comment
обязательно: позвоните pool.submit внутрь handleMessage   -  person pskink    schedule 02.12.2015


Ответы (1)


Хорошо, учитывая ссылку pskink (http://pastebin.com/L1m3NJTT)

Вот что я пробовал: теперь я расширяю Service, а не IntentService. И мой Хендлер теперь

class IncomingHanlder extends Handler {
    @Override
    public void handleMessage(Message msg)  {
        pool.submit(new MyRunnable(msg));
        super.handleMessage(msg);
    }
}

Этот метод должен получить входящее сообщение (msg), чтобы его можно было использовать с помощью метода replyto в методе myRunnable, который

public class MyRunnable implements Runnable {
private final Message _message;
public MyRunnable(final Message message) {
    this._message = message;
}


@Override
public void run() {
try {
    switch (this._message.what) {

        case 1:
            //Process taking 10 sec
            //...

            //Reply to client
            Message resp = Message.obtain(null, this._message.what);
            Bundle bResp = new Bundle();
            bResp.putBoolean("com.xxx.msg1", true);
            resp.setData(bResp);
            this._message.replyTo.send(resp);
            break;

        case 2:
            //Process taking 5 sec
            //...

            //Reply to client
            Message resp = Message.obtain(null, this._message.what);
            Bundle bResp = new Bundle();
            bResp.putBoolean("com.xxx.msg2", true);
            resp.setData(bResp);
            this._message.replyTo.send(resp);
            break;

        default:

    }
}
    catch (RemoteException e) {
        e.printStackTrace();
    }
}

}

Обратите внимание, что я все еще использую для реализации Service Interface onBind:

private Messenger msg = new Messenger(new ConvertHanlder());

  @Override
public IBinder onBind(Intent arg0) {
    return msg.getBinder();
}

Дело в том, что я никогда не получаю ответа на отправку сообщений. Я что-то пропустил?

person Valentin    schedule 02.12.2015