Подтвердить что ты не робот

Более эффективный способ обновления пользовательского интерфейса от службы, чем намерения?

В настоящее время у меня есть Служба на Android, которая является образцом VOIP-клиента, поэтому она прослушивает сообщения SIP и, если она ее получает, запускает экран Activity с компонентами пользовательского интерфейса.

Затем следующие сообщения SIP определяют, что должно отображаться на экране. Например, если в его входящем вызове появится ответ "Ответ" или "Отклонить" или исходящий вызов, он отобразит экран набора номера.

В тот момент, когда я использую Intents, чтобы сообщить Activity, какое состояние оно должно отображать.

Пример следующий:


        Intent i = new Intent();
        i.setAction(SIPEngine.SIP_TRYING_INTENT);
        i.putExtra("com.net.INCOMING", true);
        sendBroadcast(i);

        Intent x = new Intent();
        x.setAction(CallManager.SIP_INCOMING_CALL_INTENT);
        sendBroadcast(x);
        Log.d("INTENT SENT", "INTENT SENT INCOMING CALL AFTER PROCESSINVITE");

Таким образом, у этого мероприятия будет зарегистрирован радиоприемник, зарегистрированный для этих целей, и переключит его состояние в соответствии с последним намерением, которое он получил.

Пример кода следующим образом:


       SipCallListener = new BroadcastReceiver(){

            @Override
            public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction(); 

                    if(SIPEngine.SIP_RINGING_INTENT.equals(action)){
                        Log.d("cda ", "Got RINGING action SIPENGINE");
                        ringingSetup();
                    }         

                    if(CallManager.SIP_INCOMING_CALL_INTENT.equals(action)){
                        Log.d("cda ", "Got PHONE RINGING action");
                        incomingCallSetup();
                    }  
            }
        };
        IntentFilter filter = new IntentFilter(CallManager.SIP_INCOMING_CALL_INTENT);
        filter.addAction(CallManager.SIP_RINGING_CALL_INTENT);
        registerReceiver(SipCallListener, filter);

Это работает, однако кажется, что он не очень эффективен, Intents получат широковещательную систему, и намерения, которые должны срабатывать для разных состояний, похоже, что это может стать неэффективным, тем больше я должен включать, а также добавить сложность.

Итак, мне было интересно, есть ли другой более эффективный и чистый способ сделать это?

Есть ли способ поддерживать Intents вещание только внутри приложения?

Будет ли обратная связь лучшей идеей? Если да, то почему и каким образом они должны быть реализованы?

4b9b3361

Ответ 1

UPDATE 2015:

Этот вопрос/ответ по-прежнему получает немного активности, но он старше 5 лет, и все изменилось совсем немного. 5 лет назад, ниже был ответ, как бы я справился с этим. Позже я написал очень легкое решение для инъекций зависимостей, которое я использовал некоторое время (что я упомянул в комментариях). В настоящее время я бы ответил на этот вопрос, используя Dagger и RxAndroid. Кинжал, чтобы ввести класс "посредника" и в Службу, и во все действия, которые необходимо уведомить, Служба переместит обновление статуса в класс посредника, а класс посредника будет подвергать наблюдаемые действия для использования обновления состояния ( вместо приемника вещания OP).

Оригинальный ответ

Я обычно использую подкласс Application и позволяю моей связи через приложение проходить через этот класс (или иметь посредника, принадлежащего Приложению, выполнять работу... независимо от того, что приложение является точкой входа для связи службы). У меня есть связанная служба, которая также нуждается в обновлении интерфейса (гораздо проще, чем ваша, но та же идея), и в основном он сообщает приложению о своем новом состоянии, и приложение может затем передать эту информацию так или иначе в активная деятельность. Вы также можете сохранить указатель на текущую активную деятельность (если ее несколько) и принять решение о том, нужно ли просто обновлять текущую деятельность, транслировать намерение запуска другого действия, игнорировать сообщение и т.д. Я бы также подкласс Activity и ваш новый базовый класс активности скажите Приложению, что он в настоящее время является активным в onResume и что он приостановлен в onPause (для случаев, когда ваша служба работает в фоновом режиме и все действия приостановлены).

EDIT:

В ответ на комментарий, здесь более подробно.

В настоящее время ваша заявка состоит из классов, производных от производных и служб, по большей части. По сути, вы получаете функциональность из экземпляра класса android.app.Application. Это объявлено в вашем манифесте (по умолчанию) со следующей строкой:

<application android:icon="@drawable/icon" android:label="@string/app_name">

Элемент приложения в манифесте не использует атрибут android: name, поэтому он просто создает экземпляр класса android.app.Application по умолчанию для представления вашего глобального контекста приложения.

В моих приложениях я создаю подкласс приложения (ApplicationEx, например), и я расскажу в своем приложении через манифест, что это класс для создания экземпляра в качестве глобального контекста приложения. Например:

<application
    android:name="com.mycompany.myapp.app.ApplicationEx"
    android:icon="@drawable/app_icon"
    android:label="@string/app_name">

Теперь я могу добавлять методы в ApplicationEx для действий и сервисов для связи. Всегда есть один экземпляр вашего глобального контекста приложения, так что это ваша отправная точка, если что-то должно быть глобальным для вашего приложения.

Вторая часть этого заключается в том, что вместо того, чтобы выводить мои сервисы и действия из Сервиса и Действия, я создаю подкласс каждого из них с методом getAppContext, который возвращает возвращаемое значение getApplicationContext (которое существует уже в обоих этих классах, потому что они выводятся из контекста) в класс ApplicationEx.

Итак,........

Все сказанное добавляет свойство CurrentActivity к классу ApplicationEx типа Activity (или ActivityBase, если вы подклассифицируете его так же, как и я). В методе ActivityBase onResume вы переходите к ApplicationEx, чтобы установить CurrentActivity для этой активности. Теперь вы можете выставить методы на ApplicationEx для передачи информации непосредственно в текущую деятельность вместо того, чтобы полагаться на механизмы Intent.

Это так же ясно, как я могу это сделать

Ответ 2

Вы можете отправлять трансляции намерения только к своему собственному приложению, а не по всей системе с LocalBroadcastManager:

Помощник для регистрации и отправки трансляций намерений на локальные объекты в рамках вашего процесса. Это имеет ряд преимуществ перед отправкой глобальных передач с помощью sendBroadcast (Intent):

Вы знаете, что данные, которые вы передаете, не покидают ваше приложение, поэтому вам не нужно беспокоиться о утечке конфиденциальных данных.

Невозможно, чтобы другие приложения отправляли эти трансляции в ваше приложение, поэтому вам не нужно беспокоиться о наличии дыр в безопасности, которые они могут использовать.

Это более эффективно, чем отправка глобальной трансляции через систему.

Тем не менее, я по-прежнему рекомендую использовать подход "Служба" и локально привязывать и говорить через обработчика, когда это необходимо, для повышения эффективности компонентов пользовательского интерфейса.