2

I have been searching everywhere but just can't figure how to get the current (top) activity of a running Android application.

Alright, my scenario is I received a Firebase Cloud Messaging Data payload while the app is in the foreground and the ​onMessageReceived (of a subclass of FirebaseMessagingService) is invoked. I need to find out what screen the user is viewing and then decide to dismiss (finish()) it or send some data (via Extras / Bundle) and refresh the view.

So, how do I find out what is the current View / Activity and to discuss or send some data and cause the view to refresh?

Thanks!

KENdi
  • 7,576
  • 2
  • 16
  • 31
ikevin8me
  • 4,253
  • 5
  • 44
  • 84

3 Answers3

4

Just as a follow up to Kevin Krumwiede's already accepted answer, here are some implementation details for one possible way to follow his approach (any mistakes are mine):

Create a reusable BroadcastReceiver

public class CurrentActivityReceiver extends BroadcastReceiver {    
    private static final String TAG = CurrentActivityReceiver.class.getSimpleName();
    public static final String CURRENT_ACTIVITY_ACTION = "current.activity.action";
    public static final IntentFilter CURRENT_ACTIVITY_RECEIVER_FILTER = new IntentFilter(CURRENT_ACTIVITY_ACTION);

    private Activity receivingActivity;

    public CurrentActivityReceiver(Activity activity) {
        this.receivingActivity = activity;
    }

    @Override
    public void onReceive(Context sender, Intent intent) {
        Log.v(TAG, "onReceive: finishing:" + receivingActivity.getClass().getSimpleName());

        if (<your custom logic goes here>) {
            receivingActivity.finish();
        }
    }
}

Instantiate and use that BroadcastReceiver in each of your activities

public class MainActivity extends AppCompatActivity {

    private BroadcastReceiver currentActivityReceiver;

    @Override
    protected void onResume() {
        super.onResume();

        currentActivityReceiver = new CurrentActivityReceiver(this);
        LocalBroadcastManager.getInstance(this).
            registerReceiver(currentActivityReceiver, CurrentActivityReceiver.CURRENT_ACTIVITY_RECEIVER_FILTER);
    }

    @Override
    protected void onPause() {
        LocalBroadcastManager.getInstance(this).
            unregisterReceiver(currentActivityReceiver);
        currentActivityReceiver = null;
        super.onPause();
    }
}

Finally, send the appropriate broadcast from within your FirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
       Intent localMessage = new Intent(CurrentActivityReceiver.CURRENT_ACTIVITY_ACTION);   
       LocalBroadcastManager.getInstance(MyApplication.this).
            sendBroadcast(localMessage);
    }

}

This code registers and unregisters the currentActivityReceiver in such a way as to ensure that the broadcast receiver is active only when the Activity is active.

If you have a large number of Activities in your app, you might want to create an abstract base Activity class and put the onResume and onPause code in that, and have your other Activities inherit from that class.

You can also add data to the Intent named "localMessage" in onMessageReceived (e.g. with localMessage.putExtra()) and retrieve that data in the receiver later.

One advantage of Kevin's answer is that his approach does not require any additional permissions (like GET_TASKS).

Also, as Kevin pointed out, there are other, more convenient ways to pass messages around your app besides BroadcastReceiver (e.g. EventBus and Otto). IMHO, these are great, but they require an additional library which will add some method count overhead. And, if your app already uses BroadcastReceivers in a lot of other places, you might feel, for aesthetic and maintenance reasons, that you don't want to have two ways to pass messages around in the app. (That said, EventBus is pretty cool and I feel it's less cumbersome than BroadcastReceivers.)

albert c braun
  • 2,650
  • 1
  • 22
  • 32
3

We get the current foreground running Activity

    ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

permission needed

<uses-permission android:name="android.permission.GET_TASKS"/>
jagapathi
  • 1,635
  • 1
  • 19
  • 32
1

Someone else posted the correct answer and then deleted it, so I'll post it again:

You don't need to determine the top activity. Each of your activities should listen for some signal from the FirebaseMessagingService and take the appropriate action. The signal could be an Intent broadcast on the LocalBroadcastManager, or you could use some kind of event bus.

Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82