Может ли широковещательный приемник получать уведомление Mobile Data CONNECTIVITY_CHANGE при включенном Wi-Fi?

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

Я считаю, основываясь на экспериментах с одним из моих приложений, что ответом на этот вопрос является отчетливое НЕТ, что, хотя Wi-Fi включен, приемник широковещательной передачи, прослушивающий мобильные данные CONNECTIVITY_CHANGE, не получает широковещательное уведомление, когда это событие происходит. Если я ошибаюсь и что-то упустил, пожалуйста, дайте мне знать.

Мое приложение — это виджет домашнего экрана с двумя классами: ActiveMobileData — это AppWidgetProvider, а ConnectivityChangeReceiver — это BroadcastReceiver. Класс AppWidgetProvider — это мое первое приложение, которое я собрал в начале этого года, в основном из кода, широко доступного в книге, на StackOverflow, в различных блогах и т. д. Нет никакого приложения, только виджет на главном экране. Он просто переключает значок на главном экране между красным и зеленым, чтобы указать текущее состояние мобильных данных. Он отлично работал в течение нескольких месяцев с примерно 100 пользователями.

Я решил добавить BroadcastReceiver для сбора кликов из настроек. Этот код также прост — он определяет текущее состояние мобильных данных и использует глобальную логическую переменную, установленную AppWidgetProvider, чтобы определить, является ли значок на главном экране красным или зеленым. Затем он просто гарантирует, что цвет значка соответствует состоянию мобильных данных.

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

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

public class ActiveMobileData extends AppWidgetProvider {
static boolean iconEnabled;
@Override
public void onReceive(Context context, Intent intent) {
    if (intent.getAction() != null)
        super.onReceive(context, intent);
    else {
        context.startService(new Intent(context, ToggleService.class));
    }
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[]appWidgetIds) {
    context.startService(new Intent(context, ToggleService.class));
}
public static class ToggleService extends IntentService {
    public ToggleService() {
        super("ActiveMobileData$ToggleService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        ComponentName cn = new ComponentName(this, ActiveMobileData.class);
        AppWidgetManager mgr = AppWidgetManager.getInstance(this);
        mgr.updateAppWidget(cn, buildUpdate(this));
    }
    private RemoteViews buildUpdate(Context context) {
        RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
        if (!isMobileDataEnabled(getApplicationContext())) {
            updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
            enableMobileData(getApplicationContext(), true);
            iconEnabled = true;
        } else {
            updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
            enableMobileData(getApplicationContext(), false);
            iconEnabled = false;
        }
        Intent i = new Intent(this, ActiveMobileData.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
        updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
        return updateViews;
    }
    public boolean isMobileDataEnabled(Context context) {
        // ... the code here is the one that uses Java reflection
    }
    private void enableMobileData(Context context, boolean enabled) {
        // ... the code here is the one that uses Java reflection
    }

  } // public static class ToggleService
} // public class ActiveMobileData

Ниже приведен код для BroadcastReceiver...

public class ConnectivityChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive (Context context, Intent intent) {
        handleIntent(context);
    }
    protected void handleIntent(Context context) {
        ComponentName cn = new ComponentName(context, ActiveMobileData.class);
        AppWidgetManager mgr = AppWidgetManager.getInstance(context);
        mgr.updateAppWidget(cn, buildUpdate(context));
    }
    private RemoteViews buildUpdate(Context context) {
        RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
        if (!ActiveMobileData.iconEnabled && isMobileDataEnabled(context)) {
            ActiveMobileData.iconEnabled = true;
            updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
            Intent i = new Intent(context, ActiveMobileData.class);
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
            updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
        } else
        if (ActiveMobileData.iconEnabled && !isMobileDataEnabled(context)) {
            ActiveMobileData.iconEnabled = false;
            updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
            Intent i = new Intent(context, ActiveMobileData.class);
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
            updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
        }
        return updateViews;
    }
    private boolean isMobileDataEnabled(Context context) {
       // ... Identical code to that in the AppWidgetProvider
    }
} // class ConnectivityChangeReceiver

person Mick    schedule 24.12.2015    source источник


Ответы (1)


Я не знаю навскидку, но я могу указать вам 2 лучших места для поиска.

Лучше всего подробно изучить JavaDoc для ConnectivityManager.html#CONNECTIVITY_ACTION., а затем исходный код для ConnectivityManager, который находится в сети на GrepCode

В частности, комментарии в исходном коде часто содержат очень информативную информацию, которой нет больше нигде.


Обновлять:

После повторного прочтения javadoc для CONNECTIVITY_ACTION я считаю, что вы правы, потому что он говорит A change in network connectivity has occurred. A default connection has either been established or lost. ПРИМЕЧАНИЕ. Соединение по умолчанию. НЕ «Соединение». Таким образом, он запускается только при изменении «по умолчанию». Поэтому, если вы потеряете 3g/4g/и т. д. при подключении к WIFI, я не думаю, что это запустится.

Однако «есть» что-то, что вы «можете» сделать... (но только когда ваш виджет работает) (на самом деле я не на 100% уверен, что «виджет» МОЖЕТ это сделать... потому что я обычно работаю с преподавателем services/AIDL/ContentProviders/etc (также известные как «бэкэнд» на платформе). Но вы можете поместить кнопку «обновить» в свой виджет, который может запрашивать ПОЛУЧИТЬ ВСЕ СЕТИ, а затем проанализировать все эти данные и отобразить, какие сети «активны» и т. д.

Так же есть вариант. Вы можете сделать ожидающие намерения для своих широковещательных приемников (я бы рекомендовал только 1 BR и иметь разные полезные нагрузки, чтобы вы могли сортировать их по уведомляемым), а затем зарегистрировать каждое из этих ожидающих намерений как обратный вызов с помощью ConnectivityManager чтобы уведомить его всякий раз, когда существует «сеть», которая «соответствует» NetworkRequest. Это уведомит вас, по крайней мере, когда они «оживут»...

(следующая идея, вероятно, потребует от вас создания службы с отдельным потоком для предотвращения ANR)

теперь, когда они "умрут"... вы "можете" настроить TCP-соединение и посмотреть, когда оно умрет... (не "хорошо", но может быть только "жизнеспособным" вариантом) (и если вы "щедро" пытаетесь чтобы не разбудить телефон, влияние батареи может быть минимальным)

person mawalker    schedule 24.12.2015
comment
Я прочитал много интересной информации по этим ссылкам, но, к сожалению, я не нашел никаких комментариев и т. д., имеющих отношение к моему поиску. Я также исследовал идею использования ContentObserver с android.provider.Settings.System.CONTENT_URI, чтобы посмотреть, будет ли он получать мобильные данные или какие-либо изменения в настройках, но это также не сработало. Я не уверен, можно ли его получить с помощью ContentObserver, и если да, то каким будет URI. Если у кого-то есть другие предложения для меня, чтобы следовать, я был бы очень признателен. - person Mick; 30.12.2015
comment
Обновление, добавленное к ответу, так как оно было слишком длинным для комментариев - person mawalker; 30.12.2015