Активирайте и деактивирайте Broadcast Receiver

Опитвам се да активирам и деактивирам приемник за излъчване, като използвам този метод на PackageManager:

setComponentEnabledSetting(componentName,
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);

Приемникът на излъчване е регистриран в манифеста. Приемникът работи добре, но когато се опитам да го деактивирам, той все още получава излъчваните съобщения. Когато деактивирам приемника в манифеста чрез "android:enabled="false"", приемникът не получава нищо, но не мога да го активирам.

Извиквам метода от вътрешна услуга.

    PackageManager pm  = getApplicationContext().getPackageManager();
    ComponentName componentName = new ComponentName("com.app",
             ".broadcast_receivers.OnNetworkChangedReceiver");
    pm.setComponentEnabledSetting(componentName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

Манифест на Android:

    <receiver android:name=".broadcast_receivers.OnNetworkChangedReceiver"
                android:enabled="true">
            <intent-filter>
                    <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
    </receiver>

Приемникът

public class OnNetworkChangedReceiver extends BroadcastReceiver {
private static final String TAG = "OnNetworkChangedReceiver";

@Override
public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "in OnNetworkChanged");
    }
}

Вчера извиках метода и от дейността. Мислех, че работи, но днес вече нищо не работи. Възможно ли е понякога да има голямо забавяне в намерението (android.net.conn.CONNECTIVITY_CHANGE), което погрешно изтълкувах вчера като деактивиране на приемника?

Правилната посока ли е подходът с PackageManager или има основна грешка в идеята?

Благодаря много, Свен


person Sven    schedule 11.04.2011    source източник
comment
Между другото @Sven, първоначалната ти грешка беше много често срещана. Необходимо е вашето ComponentName (com.app, com.app.broadcast_receivers.OnNetworkChangedReceiver); Осъзнавам, че това решение изглежда странно, защото името на пакета изглежда е посочено два пъти. И тъй като „Съветникът за нов Android...“ може да ви поиска само едно име на пакет, когато за първи път създавате проект, лесно е да си помислите, че има само едно, но под капаците той всъщност взема този низ, който му давате, и го присвоява към две различни имена на пакети, както името на пакета на приложението, така и името на пакета за дейност.   -  person Stephan Branczyk    schedule 21.12.2011
comment
Използването на 0 вместо PackageManager.DONT_KILL_APP също може да ви помогне да се отървете от дейността, ако чета документите правилно: developer.android.com/reference/android/content/pm/ в раздела SetComponentEnabledSetting.   -  person Ehtesh Choudhury    schedule 07.05.2013


Отговори (2)


Е, това, което основно имате, изглежда добре. Имам следния код в един от моите проекти:

boolean enabled=prefs.getBoolean(key, false);
int flag=(enabled ?
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component=new ComponentName(EditPreferences.this, OnBootReceiver.class);

getPackageManager()
    .setComponentEnabledSetting(component, flag,
                                PackageManager.DONT_KILL_APP);

Използвам това, за да деактивирам BOOT_COMPLETED приемник, когато нямам активни аларми, които трябва да бъдат планирани.

Предполагам, че вашият ComponentName не е настроен правилно (напр. вашият водещ .). Опитайте конструктора, който използвам, който приема Context и Class като параметри.

person CommonsWare    schedule 11.04.2011
comment
Благодаря много за бързия отговор. Използвах конструктора, който използвахте и сега работи. - person Sven; 11.04.2011
comment
Да кажем, че имам Boot Receiver - струва ли си да го деактивирам точно преди onReceive да се върне? След това ще работи ли при следващото рестартиране? - person Mr_and_Mrs_D; 18.03.2013
comment
@Mr_and_Mrs_D: Ако е деактивиран, когато устройството се рестартира, няма да бъде извикан. - person CommonsWare; 18.03.2013
comment
Благодаря ви, разбрах :( Мислех, че промените няма да продължат - как така? Пише ли setComponentEnabledSetting в манифеста? - person Mr_and_Mrs_D; 18.03.2013
comment
@Mr_and_Mrs_D: Мислех, че промените няма да продължат -- тогава нямаше да има смисъл да се опитвате да деактивирате приемника, тъй като зареждането вече щеше да се е случило. как така го правят? -- защото това е пълната и цялостна точка зад setComponentEnabledSetting(). - person CommonsWare; 18.03.2013
comment
тогава нямаше да има смисъл да се опитвате да деактивирате приемника, тъй като зареждането вече щеше да се е случило - няма ли да премахне някои допълнителни разходи? - Тъй като приемникът ще бъде съпоставен с всички имплицитни намерения, излъчвани, докато е регистриран [той всъщност няма да отговори (неговият onReceive() няма да се изпълнява), докато тествам за действието (за да избегна злонамерени изрични намерения) и имам филтъра BOOT_COMPLETED активно - така че имплицитните намерения няма да съвпадат, освен BOOT] - person Mr_and_Mrs_D; 18.03.2013
comment

Когато използвате on функция на обект, вие обвързвате callback с event на този обект и callback трябва да е функция, като тази:

this.on("add", function() { console.log("added"); });
- person CommonsWare; 18.03.2013
comment
Основно предупреждение: имайте предвид, че активирането или деактивирането на компонент с DONT_KILL_APP на API 14 или 15 ще изтрие всички известия, създадени от вашето приложение. Вижте code.google.com/p/android/issues/detail?id =21635 - person Andy Dennie; 13.11.2014
comment
уточнение: предишният ми коментар се отнася за текущи известия. - person Andy Dennie; 13.11.2014
comment
@CommonsWare Моля, не разбирам ясно за какво е полезен флагът DONT_KILL_APP. Не е ли вече гарантирано пълното изпълнение на onReceive() на получателя (с ограничение от 10 секунди)? - person GPack; 22.10.2016
comment
@GPack: Това е флаг за setComponentEnabledSetting(), който контролира дали процесът трябва да бъде прекратен, когато превключваме дали даден компонент е активиран или не. Няма нищо пряко общо с който и да е onReceive() метод. - person CommonsWare; 22.10.2016

Мисля, че използването на PackageManager е прекалено обмисляне на вашата ситуация. Имате BroadcastReceiver, който трябва понякога да игнорира предаванията, които слуша. Сещам се за два лесни начина да направя това:

1) Задайте флаг, който вашият приемник може да проверява, за да игнорира или приема излъчвания, и изобщо не се притеснявайте да го активирате/деактивирате.

2) Създайте BroadcastReceiver програмно (дори може да бъде просто вътрешен клас) и го регистрирайте и дерегистрирайте, както ви е необходимо, в дадени части от приложението ви.

Като цяло открих, че дефинирането на моите BroadcastReceivers в код вместо в XML е предоставило много повече гъвкавост и като цяло е по-лесно за мен.

person LeffelMania    schedule 11.04.2011
comment
Има някои типове излъчвания (напр. BOOT_COMPLETED), които не могат да бъдат ефективно регистрирани чрез registerReceiver(). Освен това прекомерното разчитане на registerReceiver() ви води до вечни услуги - услуги, които са там само за поддържане на приемник - което е лошо. Деактивирането на компонента е добра идея за ефективност, особено при популярни системни излъчвания, като BOOT_COMPLETED. - person CommonsWare; 11.04.2011
comment
Много добри точки. Programmatic BroadcastReceivers изискват отговорно регистриране/отписване, за да се избегнат вечни услуги. Както винаги зависи от ситуацията. - person LeffelMania; 11.04.2011
comment
@CommonsWare Има ли начин да активирате BroadCastReceiver само след събитие BOOT_COMPLETED? Бих искал да активирам приемника веднага след като устройството се рестартира, да настроя отново аларми от моята база данни SQLite, които задействат известия за краен срок и след това да деактивирам BroadCastReceiver. Мога ли да деактивирам приемника, ако алармите са настроени с PendingIntents, или трябва винаги да оставя активиран (което прави първия въпрос спорен)? - person AJW; 12.07.2018
comment
@AJW: Мога ли да деактивирам приемника, ако алармите са настроени с PendingIntents -- ако тези PendingIntents ще бъдат за излъчвания към приемника, приемникът трябва да е активиран да получава тези излъчвания. Този приемник не трябва да бъде експортиран, но трябва да бъде активиран. - person CommonsWare; 12.07.2018