Активность Android не транслируется из локальной службы

#android #service #broadcastreceiver

#Android #Обслуживание #broadcastreceiver

Вопрос:

Из примеров это выглядело просто. Может быть, вы можете показать мне, что я сделал не так. Я не могу заставить activity получать широковещательную рассылку, отправленную из локальной службы.

У меня есть Activity1, который запускает Service1:

 startService(new Intent(Activity1.this, Service1.class));
  

Activity1 затем запускает Activity2:

 startActivity(new Intent(Activity1.this, Activity2.class));
  

Service1, локальная служба, прослушивает загрузки:

 protected final BroadcastReceiver service2DownloadBroadcastReceiver = new BroadcastReceiver()
{
    public void onReceive(final Context context, final Intent intent)
    {
        ...
        broadcastDownloadFinished(Uri.fromFile(downloadedFile));
  

Затем широковещательный приемник Service1 передает свое собственное сообщение:

 protected Intent broadcastDownloadFinished(final Uri uri)
{
    final Intent intent = new Intent(ACTION_DOWNLOAD_FINISHED).setData(checkNotNull(uri));
    sendBroadcast(intent);
  

Activity2, которая в данный момент находится на переднем плане, прослушивает намерение ACTION_DOWNLOAD_FINISHED, используя свой собственный широковещательный приемник:

 private final BroadcastReceiver activity2DownloadBroadcastReceiver = new BroadcastReceiver()
{
    public void onReceive(final Context context, final Intent intent)
    {
        Log.i(Activity2.class.getSimpleName(), "Received download event: "   intent.getAction()   " "   intent.getData());
  

Activity2, конечно, регистрирует получателя:

 protected void onResume()
{
    super.onResume();
    final IntentFilter downloadIntentFilter = new IntentFilter();
    downloadIntentFilter.addAction(ACTION_DOWNLOAD_FINISHED);
    registerReceiver(activity2DownloadBroadcastReceiver, downloadIntentFilter);
  

В случае, если это имеет значение, ACTION_DOWNLOAD_FINISHED это что-то вроде "com.example.intent.action.DOWNLOAD_FINISHED" .

Service1 получает событие диспетчера загрузки в своем приемнике и, по-видимому, транслирует свое собственное пользовательское событие, но Activity2, похоже, никогда его не получает. Что я сделал не так? Является ли проблемой трансляция намерения в процессе обработки другого? (Я бы так не подумал — это асинхронно, верно?)

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

     Log.i(getClass().getSimpleName(), "...ready to broadcast");     
    final Intent intent = new Intent(ACTION_DOWNLOAD_FINISHED).setData(checkNotNull(uri));
    mainThreadHandler.postDelayed(new Runnable()
    {
        public void run()
        {
            Log.i(getClass().getSimpleName(), "...broadcasting");
            sendBroadcast(intent);
            Log.i(getClass().getSimpleName(), "...broadcasted");                
        }
    }, 3000);
    Log.i(getClass().getSimpleName(), "...scheduled to broadcast");
  

Как и ожидалось, в журнале говорится:

 ...ready to broadcast
...scheduled to broadcast
...broadcasting
...broadcasted
  

Тем не менее, в активности ничего не получено. Пожалуйста, помогите.

Ответ №1:

Эврика! Я нашел это! Проблема в том, что я указал URI данных в своем широковещательном намерении. Правила сопоставления намерений Android немного усложняются. Если вы предоставляете URI данных, то ваш фильтр намерений должен указывать соответствующий тип MIME.

К сожалению, хотя в документации Android говорится, что тип данных может быть выведен из URI данных, по-видимому, Android не знает, что file://.../example.jpg это изображение. Итак, это не работает:

 intentFilter.addDataType("image/*");
  

Однако вместо указания типа я могу указать схему, которую я принимаю:

 intentFilter.addDataScheme("file");
  

Это работает! Это немного грубо — и немного искусственно — ограничивать мои трансляции file: URI, но поскольку это все, что я использую на данный момент, это работает.

Обратите внимание, что, по-видимому, я мог бы вручную указать тип MIME в intent при его трансляции, но пока это слишком сложно, поскольку я загружаю изображения из Picasa, поэтому я уже знаю, что это изображения (и мне все равно, какой конкретный тип MIME). И если это вызовет слишком много проблем, я мог бы вообще отказаться от всего setData() и установить дополнительный — но, конечно, я хочу все делать правильно.

Комментарии:

1. Ты опередил меня в этом. Я не заметил этого самостоятельного ответа и просто просматривал ваш код. Я собирался предложить исключить setData(...) из кода, просто чтобы посмотреть, что произошло — очевидно (из вашего ответа), это сработало бы. Извините, я не мог приступить к этому раньше — у меня сегодня была поздняя смена на работе. Рад, что у вас есть решение.

2. Большое спасибо, что нашли время взглянуть на это, MisterSquonk. Это сводило меня с ума. Я надеюсь, что это кому-то поможет. Спокойной ночи.

Ответ №2:

включили ли вы свой приемник в манифест вашей активности?

 <receiver
  android:name=".YourReceiver">
  <intent-filter>
    <action
      android:name="intent_name"></action>
  </intent-filter>
</receiver>
  

Комментарии:

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

2. уверен, что может. установите Android:name=». Родительский класс $ReceiverName»

3. Возможно, я здесь не прав, но 1) Я использую анонимный внутренний класс, поэтому вам придется угадывать сгенерированный ...$Name , 2) весь смысл <receiver> элемента в том, чтобы Android автоматически создавал экземпляр получателя по мере необходимости, а Android не может автоматически создавать экземпляр моего нестатического анонимного внутреннего класса, 3) мой класс receiver уже создан и зарегистрирован, поэтому <receiver> элемент не нужен. Пытаюсь вернуться к теме: <receiver> требуется для зарегистрированных вручную приемников или нет? Я считаю, что это не так.

4. Просто для продолжения: при ручной регистрации широковещательного приемника статическое определение в манифесте не требуется; см. developer.android.com/reference/android/content / … .