BroadcastReceiver dies with app

2019-01-15 23:09发布

问题:

If i let the phone sit for a long time like 15 minutes i lose my receiver but i thought it was to persist like a service after being killed for memory.

Manifest:

<receiver
    android:name=".WearableReceiver"
    android:enabled="false">
    <intent-filter>
        <action android:name="com.example.johnbravado.MESSAGE_PROCESSED"/>
    </intent-filter>
</receiver>

In Activity to start receiver

ComponentName component = new ComponentName(CounterActivity.this, WearableReceiver.class);
getPackageManager()
    .setComponentEnabledSetting(component,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

The receiver

@Override
public void onReceive(Context context, Intent intent) {
    // TODO: This method is called when the BroadcastReceiver is receiving
    // an Intent broadcast.
    //MyConstants.getInstance().showToast("Message Rcvd");
    PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
    PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
            "com.example.johnbravado");
    wakeLock.acquire();
    // Do Work
    MyConstants.getInstance().msgReqAction(intent.getIntExtra(MyConstants.BROADCAST_DATA_REQ, 0));

    wakeLock.release();
}

The broadcast sender

String BROADCAST_ACTION_RESP = "com.example.johnbravado.MESSAGE_PROCESSED"
@Override
public void onMessageReceived(final MessageEvent messageEvent) {
    nodeId = messageEvent.getSourceNodeId();
    String incomingPath = messageEvent.getPath();
    int incomingReq = Integer.parseInt(new String(messageEvent.getData()));

    if(incomingPath.equalsIgnoreCase(MyConstants.MSG_COUNTER_REQ_PATH)) {
        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction(BROADCAST_ACTION_RESP);
        broadcastIntent.putExtra(MyConstants.BROADCAST_DATA_REQ, incomingReq);
        sendBroadcast(broadcastIntent);

    }else if(incomingPath.equalsIgnoreCase(MyConstants.MSG_DEFAULT_PATH)){

    }
}

only way I get this to persist for long periods of time is to invoke a service

wearableReceiverIntent = new Intent(this, WearableReceiverService.class);
if(!WearableReceiverService.isRunning())
    startService(wearableReceiverIntent);

the service

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // Let it continue running until it is stopped.
    IntentFilter filter = new IntentFilter(MyConstants.BROADCAST_ACTION_RESP);
    filter.addCategory(Intent.CATEGORY_DEFAULT);
    receiver = new WearableReceiver();
    registerReceiver(receiver, filter);

Notification notification = new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.ic_notif_bible)
        .setContentText("Preaching").build();
startForeground(MyConstants.NOTIF_COUNTING_SERVICE, notification);

    isRunning = true;
    return START_STICKY;
}

If I run the service it persists for long periods of time but it drains the battery unnecessarily considering I interact only once every 10 minutes. I was under impression Broadcast receiver would work like service except for short bursts of work. invoke the service if you need to do long actions.

回答1:

Greenify was killing my app when the screen went off. I was battling something I had no hope of defending against with code. After I explicitly told Greenify to not kill my app, I never told it to kill my app to begin with, everything worked as intended.



回答2:

A BroadcastReceiver handles an intent and then stops again. This handling of an intent should be fast. If you want to do a lot of stuff, you should start an Service from the BroadcastReceiver and handle it from there.

A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.

A BroadcastReceiver is started using the sendBroadcast intent. So remove android:enabled="false" and use sendBroadcast, which will startup the Receiver by Android.

http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html



回答3:

If your BroadcastReceiver is setup in your manifest, there is no need to try and adjust the PackageManager component information for your package. As long as you remove the enabled="false" part.

Your BroadcastReceiver should be very short with what it does: typically update some internal data or start another component which can do the heavy lifting of your app's operation. You can use it to trigger a Service to do this type of thing in the background. But, note that "background" in this case means without user-interaction. It does not mean a background context of execution, such as a secondary thread. It is up to you do manage the thread(s) in your Service. Your BroadcastReceiver and Service callback entry points (onReceive() and onStartIntent()) run in the context of the main thread of your app.

Power management definitely plays a roll in all of this. Is your broadcast Intent actually being sent and done in a way which will wake the device? If it does wake the device and send the Intent, the device will only stay awake long enough for the BroadcastReceiver to run its onReceive(); after that returns there are no guarantees. The device will aggressively sleep, which is why wakelocks are a thing. However, use of wakelocks can cause excessive battery drain, unless used properly. If you are running on Marshmallow or newer, the Doze functionality can also wreck havoc on your plans. Wakelocks are ignored when in Doze mode and won't be considered until the user brings the device out of doze.



回答4:

I had the same problem due on my Asus ZenPad due to the Asus Mobile Manager app, specifically the "Auto start manager" was blocking the intent to my app.

Deactivating the app (uninstall is not possible) worth nothing, the solution has been to leave the app installed but whitelist my developing app so it can receive broadcast like PACKAGE_REPLACE. (Pay attention that the switches are confusing, you actually have to touch on "blocked" so it turns on into "allowed" to enable it.

I think another option is to update or change the ROM (choosing one without all that bloatware).



回答5:

I had the same issue and it was resolved by granting auto launch permission for the app.

Go to Settings->Permissions->Manage Auto Launch and allow auto launch for your app.