a_dzik
a_dzik

Reputation: 977

BroadcastReceiver in IntentService in WakefulBroadcastReceiver does not always work

So, I have this problem. I'm using a dependency project that is some kind of GCM notification parser. It's a bit poorly written, however I'm forced to use it, becase of work related reasons. Anyways:

The main service (that extends IntentService) is launched with WakefulBroadcastReceiver. After it receives message from GCM I does some magic and sends it to the main App using broadcast. In main app I'm constantly running service with another BroadcastReceiver that catches messages and saves everything in database etc.

Why is it so complicated? Firstly - originally it was someone else's project and now I'm trying to fix bugs. Secondly - I have no access from dependency to the main application project so I pass messages with broadcasts.

And now, the fun part. I need to filter whether I want to show notification or not. While sending a message to my main AppService I check it with the history of previous messages and then I decide if I need to show this message to User or not. However, no matter what my decision is, my dependency still shows my notification. So I added yet another broadcast, when after successful validation I launch in my dependency notification building method.

Here is the code:

My WakefulBroadcastReceiver:

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    ComponentName comp = new ComponentName(context.getPackageName(), PushService.class.getName());
    startWakefulService(context, (intent.setComponent(comp)));
    setResultCode(Activity.RESULT_OK);
}
}

Here is my Depencency service

        public NotificationCheckerReceiver notificationCheckerReceiver;

        ...

        @Override
        protected void onHandleIntent(Intent intent) {
            Bundle extras = intent.getExtras();
            GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
            String messageType = gcm.getMessageType(intent);

            if (!extras.isEmpty()) {

                if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {

                    //Launch my "approval" receiving broadcast
                    launchBroadcastReceiver(extras, intent);

                    //send broadcast to main app with the message we will parse etc.
                    sendSmsBroadcast(...));


                }
            }

        }


        @Override
        public void onDestroy() {
            unregisterReceiver(notificationCheckerReceiver);
            super.onDestroy();
        }

        //Launch to build notification
        public void showNotification(Bundle extras){
            ...
            //Basic notification builder
        }

        //Receive broadcast from DB if notification was already in the DB
        private void launchBroadcastReceiver(Bundle extras, Intent intent){
            Log.d(TAG, "Broadcast receiver loaded");

            notificationCheckerReceiver = new NotificationCheckerReceiver(new NotiFlag() {
                @Override
                public void onReceiveApproval(Boolean flag, Intent intent, Bundle extras) {
                    Log.d(TAG, "Approved notification show");
                    showNotification(extras);
                    JustPushGcmBroadcastReceiver.completeWakefulIntent(intent);
                }
            }, intent, extras);

            registerReceiver(notificationCheckerReceiver, new IntentFilter(notificationCheckerReceiver.INTENT_EVENT_NAME));
        }

        public void sendSmsBroadcast(String message, boolean isAppOnScreen){
            ...
            //This works
        }

    }

and my "faulty" receiver: public class NotificationCheckerReceiver extends BroadcastReceiver{

    private  final String TAG = getClass().getSimpleName();

    public static final String INTENT_EVENT_NAME = "NOTIFLAG";
    public static final String INTENT_FLAG_KEY = "FLAG";

    Intent intent;
    Bundle extras;

    NotiFlag nofiFlag;

    public NotificationCheckerReceiver(NotiFlag nofiFlag, Intent intent, Bundle extras){
        Log.d(TAG, "Launched constructor NotificationChecker");
        this.nofiFlag = nofiFlag;
        this.intent = intent;
        this.extras = extras;

    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "Launched onReceive");
        Boolean bool = intent.getExtras().getBoolean(INTENT_FLAG_KEY);
        Log.d(TAG, "___________Broadcast receiver got something and it is intent: "+bool);

        if (bool != false) {
            nofiFlag.onReceiveApproval(bool, this.intent, this.extras);
        }

    }
}

and lastly, what I'm sending from my main service:

    public void sendNotificationCheckerBroadcast(Boolean message){
        Intent flag = new Intent(NotificationCheckerReceiver.INTENT_EVENT_NAME);
        flag.putExtra(NotificationCheckerReceiver.INTENT_FLAG_KEY, message);
        DvLogs.d(TAG, "__________Sending intent: "+message);
        sendBroadcast(flag);
    }

What happens is that eveything to the point where I launch "sendNotificationCheckerBroadcast()". I get that I'm sending some kind of boolean... and that's it.

The funny part is: it SOMETIMES works. I don't know why, but when for some reason it launches - everything is awesome.

EDIT: When it works, because sometimes it does, I have this error:

    01-15 11:20:22.204    3234-3234/pl.digitalvirgo.lafarge E/ActivityThread﹕ Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver@43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
        android.app.IntentReceiverLeaked: Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver@43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
                at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:814)
                at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:610)
                at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1772)
                at android.app.ContextImpl.registerReceiver(ContextImpl.java:1752)
                at android.app.ContextImpl.registerReceiver(ContextImpl.java:1746)
                at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:479)
                at com.example.name.PushService.launchBroadcastReceiver(Unknown Source)
                at com.example.name.PushService.onHandleIntent(Unknown Source)
                at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:157)
                at android.os.HandlerThread.run(HandlerThread.java:61)

Maybe it's somehow related? I know that I should unRegister this Receiver ... somewhere. Tried onStop, but as we can see - no success.

Edit2: Weird. I believe, that the problem is in onStop() method. Probably it's called too early (?) so my Receiver has no chance to work. When I launch app without unRegister everything works. Of course I get bug above, but still... it's something. Any ideas guys?

Upvotes: 2

Views: 1143

Answers (1)

a_dzik
a_dzik

Reputation: 977

Well. The problem was inside the idea of IntentService.

intentService kills itself after onHandleIntent() method. So the solution for this problem is to change IntentService into Service remembering to handle stopping this thing.

Upvotes: 2

Related Questions