9

I have an app-wide utility class AppUtils, where I can publish app relevant information at any rate:

  1. either as a SnackBar, when I am in the app
  2. or by means of the notification manager

For instance when the mesaages is going as a Snackbar I need the track of the current displayed View container to use it in Snackbar.make(view, text, length); When I want to publish that message by means of the NotificationManager.notify(int, Builder); and I need the Class signature in here

Intent resultIntent = new Intent(this, ResultActivity.class);

Therefore I have in my AppUtils:

public static void setCurrentViewAndClass(View v, Class<?> c)
{
    view = v; // view is static
    cls = c;  // cls is static
}

where I can remember from everywhere in my project the current view (for Snackbar parameter) and cls (for Notification Intent).

Further on, I clear those parameters, e.g. when I leave the app to the background:

public static void clearCurrentViewAndClass()
{
    view = null;
    cls = null;
}

A. When those parameters are NOT null, I know that my app has the focus with corresponding view and I can show the relevant message as a Snackbar. B. When these parameters are null, I know that my app is in the background and I want to show the relevant message as a Notification

So whenever a Fragment/Activity is created or resumed, I call setClassAndview() it in each onResume() to remember the parameters.

Is there a more elegant way to get track of the current displayed Activity or active Class ?

Ralf Wickum
  • 2,850
  • 9
  • 55
  • 103

3 Answers3

7

As an example... create an Application class (MyApp) that is registered in AndroidManifest:

<application
        android:name=".MyApp"
        ...>

In MyApp application class .onCreate() set:

registerActivityLifecycleCallbacks(new MyAppActivityLifecycleCallbacks());

In MyApp, create a static field that holds a count of visible Activities and a method for determining if the app is in the foreground or not:

private static int mActivityCount = 0;

public static boolean isAppInForeground() {
    return mActivityCount != 0;
}

And finally setup your ActivityLifecycleCallbacks class for keeping count of visible Activities:

private static final class MyAppActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {

        public void onActivityCreated(Activity activity, Bundle bundle) {
            // No operations
        }

        public void onActivityDestroyed(Activity activity) {
            // No operations
        }

        public void onActivityPaused(Activity activity) {
            // No operations
        }

        public void onActivityResumed(Activity activity) {
            // No operations
        }

        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            // No operations
        }

        public void onActivityStarted(Activity activity) {
            mActivityCount++;
        }

        public void onActivityStopped(Activity activity) {
            mActivityCount--;
        }
    }

And now you should be able to call MyApp.isAppInForeground() to determine if any of your Activities are currently in the foreground. If you need a reference to the current visible Activity you could handle that here as well.

Jason Grife
  • 1,197
  • 11
  • 14
  • this works perfectly for Activities; very nice! Is there something similar for Fragments? – Ralf Wickum Nov 08 '16 at 08:27
  • The Android SDK doesn't provide this for Fragments, but you could create a Base Fragment that all your fragments extend from. In that Base Fragment lifecylcle events, you would perform callbacks. And your Application class could be setup as the listener for those callbacks. – Jason Grife Nov 12 '16 at 19:13
  • Are there any examples for those Fragment lifecycle callbacks with an application setup as a listener? – Ralf Wickum Nov 15 '16 at 09:16
2

You can use ActivityManager for getting current Activity.

This link explains how.

However, you cannot get current Fragment since there may be multiple fragments simultaneously. You can find current fragment on a specific ViewGroup by using FragmentManager.

getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
Community
  • 1
  • 1
Efe Budak
  • 659
  • 5
  • 27
0

This is not precisely what you asked for, but you can greatly improve maintainability of your current code by using event bus pattern. Subscribing to specific events in the interested Views, Activities, Services etc. will let you handle any amount of notifications without explicitly tracking their receivers.

This works like this:

  1. You subscribe to events in each interested component after it is fully initialized.
  2. Receive and handle the event, optionally cancel the event, if the component thinks, that other components don't need it.
  3. Unsubscribe when the component no longer needs events (the View is hidden/detached, Fragment is destroyed, Activity is closed/minimized).

The beauty of this approach lies in flexibility — you can always add more logic around each event without affecting other components, which subscribe to it. Furthermore, you can chose the best time to subscribe/unsubscribe independently for each component (e.g. the notifications may be emitted anytime, but snackbars should only be shown when Activity is visible and resumed).

There are multiple good options for implementing an event bus in your app:

  1. Global Android broadcasts: best suited when you have multiple high-order components (Activities, Services, Broadcast receivers), interested in common events. You can use intent filter priorities and ordered broadcasts to cancel event handling half-way.
  2. LocalBroadcastManager. Dead simple, few features, but also easy to use with familiar API.
  3. Various specialized event bus libraries, pick you favorite.
  4. Various APIs, that can be used as event buses, even if this is not their primary purpose: RxJava (I recommend reading this article), PendingIntents, ContentResolver.notifyUri etc.
user1643723
  • 4,109
  • 1
  • 24
  • 48