1

AsFirebaseMessagingService does not use the Main Thread, I am just wondering as all my code in all of my activities or fragments run in UI thread(Main Thread). Now suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run in parallel, or will the push notification code wait in the queue until onCreate() method OR Activity's last life cycle method gets executed?

Edit- As you are saying code will run parallelly then suppose I have a variable in App.java

public class App extends Application {
    int ctr = 100;
}

StatusActivity.java

public class StatusActivity extends BaseActivity {
     public void onCreate() {
         fun();
     }
     public void fun() {
         int d = App.ctr - 1;//Step 1 Here d = 99

         int m = App.ctr - 1; // Step 3 Here m = 98

     }

}

FcmListener.java

 public class FcmListener extends FirebaseMessagingService {
     Override
     public void onMessageReceived(RemoteMessage mssg) {
         App.ctr = App.ctr - 1;//STEP 2 // Now App.ctr = 99

     }
 }

Now as you can see in the above code there will be problems if push notif code executes in parallel with fun(). I want push_notif and fun() to run serially, where order doesn't matter but not in parallel.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
Sudhanshu Gaur
  • 7,486
  • 9
  • 47
  • 94
  • Even if it runs on the UI thread it wouldn't wait until the last lifecycle method is called. It would post a message, and run in the order of messages posted to the handler on the UI thread. – Gabe Sechan Jun 16 '18 at 22:00
  • @GabeSechan So suppose in `oncreate` I am calling a function and after that push notif arrives then now push notif code will execute in parralely with the currently calling function or not ?? – Sudhanshu Gaur Jun 16 '18 at 22:03
  • It will run in parallel .it leverages on android NotificationManager to show notification .unless there is a blocking code in FirebaseMessagingService which is preventing to initiate notification, your main thread and code to show notification will run simultaneously . – Godfather Jun 16 '18 at 22:15
  • @Godfather Can you see my edited code. – Sudhanshu Gaur Jun 16 '18 at 22:34
  • @GabeSechan Can you please see my edited post. – Sudhanshu Gaur Jun 16 '18 at 22:34
  • This is multithreading,one possible solution would be instead of accessing variable directly create setter getter function and use synchronized block to avoid concurrent execution.Please note it will avoid other execution so you may have to make a queue . – Godfather Jun 16 '18 at 23:44
  • @Godfather Are you sure about running code parallely? Can you provide me with any source about it? – Sudhanshu Gaur Jun 17 '18 at 09:09
  • @GabeSechan Can you provide me with any source about it? – Sudhanshu Gaur Jun 17 '18 at 09:10
  • @Godfather are you there ? – Sudhanshu Gaur Jun 17 '18 at 17:37
  • @GabeSechan are you there? Can you provide me with any source about what you said? – Sudhanshu Gaur Jun 22 '18 at 14:55

4 Answers4

1

How about it?

class Sample {
private String message = null;
private final Object lock = new Object();

public void newMessage(String x) {
    synchronized (lock) {
        message = x;
    }
}

public String getMessage() {
    synchronized (lock) {
        String temp = message;
        message = null;
        return temp;
    }
}
}
kartik malik
  • 312
  • 1
  • 9
1

Here is my 2 cents. You say,

Suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run parallelly or will the push notification code wait in the queue until onCreate method OR Activity's last life cycle method gets executed?

From the official documentation of FirebaseMessagingService:

Extending this class is required to be able to handle downstream messages. It also provides functionality to automatically display notifications, and has methods that are invoked to give the status of upstream messages. Override base class methods to handle any events required by the application. Methods are invoked on a background thread.

So its possible both methods execute at the same time. If you want to do the operations on a shared variable in your Application class, you can do thread safe operations using synchronize. See How to synchronize or lock upon variables in Java?. That will make sure only one thread is making changes at a time on that variable. If a new thread comes in, it waits for the lock to get free and then makes the changes on that variable. However this doesn't guarantee the order. It just means that one thread operates on it at time and is in FIFO order.

Shobhit Puri
  • 25,769
  • 11
  • 95
  • 124
1

As already pointed out in a parallel answer, the overriden methods of FirebaseMessagingService run in a background thread, so you should use synchronization strategies in order to access/use mutable object from different thread.

But the question I want to answer is a bit different. Let's for a moment assume, that overriden methods run on a main thread. So is there a possibility, that the order of execution will be STEP 1 then STEP 2 and then STEP 3?

Android works with a technique called MessageQueue, basically there are Messages posted on that queue, on which Looper loops and "parses/executes" them.

Now if we assume, that you are currently located on STEP 1, it means, that there was a particular Message which is currently being executed (hypothetically, let's assume that action is - perform onCreate() of this activity).

Until this message is fully executed there cannot exist another Message which might get have a chance to be executed. So if we assume, that Firebase dispatches an event on background thread but the actual overriden method is being run on main thread, then this overriden method would have chance to be executed only after current Message (activity's onCreate()) has finished. In other words, there would be posted another Message on the MessageQueue, which would perform onMessageReceived() when the Looper will give chance for this message to be executed.

So, theoretically, there is no chance that the ordering would be STEP 1 -> STEP 2 -> STEP 3.

If STEP 1 is already executed, then it will continue with STEP 3 and the STEP 2 (at some point in future, because you can't know what other Messages are already posted on MessageQueue).

See this article for more details about MessageQueue and related classes.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
0

I suggest you a different approach, because using those global variables can lead to unexpected behavior. If your ctr var is related to your activity, then keep it inside. If you need it on other activities consider passing it via the Intent as an extra.

Use LocalBroadcastManager to inform your activity that you received the push message

public class FcmListener extends FirebaseMessagingService {
    public static final String ACTION_MESSAGE_RECEIVED = "ACTION_MESSAGE_RECEIVED"

    @Override
    public void onMessageReceived(RemoteMessage mssg) {
        Intent intent = new Intent(ACTION_MESSAGE_RECEIVED) // put extra vars as needed
        boolean delivered = LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
        // 'delivered' is true if there is at least someone listening to the broadcast, eg. your activity
        // If your activity is not running, then 'delivered' is false so you can act accordingly
    }
}

Then inside your activity

public class StatusActivity extends BaseActivity {

    private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (TextUtils.equals(FcmListener.ACTION_MESSAGE_RECEIVED, action)) {
                // do stuff with 'ctr'
            }
        }
    };

    @Override
    protected void onStart() {
        super.onStart();
        IntentFilter filter = new IntentFilter(FcmListener.ACTION_MESSAGE_RECEIVED);
        LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, filter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
    }

}
Kazikal
  • 156
  • 7