2

I have an app with a service and ongoing notification and two activities:

Activity A and Activity B.

Activity A has a button that starts Activity B.

When clicking the notification I want the next scenarios to happen:

  1. If app closed -> launch the app with Activity A.
  2. If app is opened either in foreground or in the background (opened app list) in either activity -> show the current activity without launching a new Activity A, meaning if I am in Activity B -> show current Activity B and same for Activity A without launching a new one.

I searched a lot and finally found this answer, saying that you need to do:

final Intent notificationIntent = new Intent(context, ActivityA.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

In the Manifest I have:

Notice I used android:launchMode="singleTop".

    <activity
        android:name=".ActivityA"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:theme="@style/AppTheme.NoActionBar"></activity>
    <activity
        android:name=".ActivityB"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:theme="@style/AppTheme.NoActionBar"></activity>

It doesn't seem to work consistency enough, and it never works if to do the following: start app -> start activity A -> start service (show notification) -> go to Activity B -> click notification opens Activity A.

I was wondering if there is a better consistent solution:

Community
  • 1
  • 1
Ofek Agmon
  • 5,040
  • 14
  • 57
  • 101

1 Answers1

2

Of course it would always open ActivityA because you defined it here :

final Intent notificationIntent = new Intent(context, ActivityA.class);

what you need to do is define where you were at the end. here is how i would handle this:

Make a class and extend it from Application class

define a variable here, it can be boolean, enum,int ,etc... when you enter any of those activities, change that parameter.

in OnDestroy of each activity reset that particular variable to its default value.

In your service before making the intent, check which state you were at last and make your intent based on that.

public class MY_APPLCIATION extends Application {
    public static Boolean ActivityAIsRunning=false;
    public static Boolean ActivityBIsRunning=false;
}

override onResume and onDestroy of both activities :

public class ActivityA extends AppCompatActivity {
    // ......
     @Override
protected void onDestroy() {
    super.onDestroy();
    MY_APPLCIATION.ActivityAIsRunning=false;
}

@Override
protected void onResume() {
    super.onResume();
    MY_APPLCIATION.ActivityAIsRunning=true;
}
}

ActivityB :

public class ActivityB extends AppCompatActivity {
    // ......
     @Override
protected void onDestroy() {
    super.onDestroy();
    MY_APPLCIATION.ActivityBIsRunning=false;
}

@Override
protected void onResume() {
    super.onResume();
    MY_APPLCIATION.ActivityBIsRunning=true;
}
}

now there is a trick which you should pay attention to :

You should define the intent when you are creating the notification !

you should have another activity ( lets called it MY_NOTIFICATION_ACTIVITY ). and the notification should always go to this activity. now in that activity check which boolean is set and then call the desired activity (ActivityA or ActivityB). Do not forget that in your manifest you should make ActivityB singleInstance too !!!

*** ANOTHER SIMPLE METHOD

another simple method is that you update the notification in OnResume of each activity. by entering each activity you change the intent to that desired activity and make the same notification and update the last notification.

Community
  • 1
  • 1
Omid Heshmatinia
  • 5,089
  • 2
  • 35
  • 50
  • I did what you suggested using the redirect activity, and over there checking the boolean values and I did startActivity() with the appropriate activity. apparently startActivity will always start a new instance of the activity. when you wrote " call the desired activity (ActivityA or ActivityB)" how did you mean to "call" it? – Ofek Agmon Jun 05 '16 at 08:45
  • set both your activity launch mode in your manifest android:launchMode="singleInstance" @OfekAgmon – Omid Heshmatinia Jun 05 '16 at 08:57
  • I changed them both to "singleInstance", and it also doesn't work very good, the transition between activities doesn't look good because it actually kinda finishes the current activity and starts a new one. I think the best choice is probably to update the notification's intent each time the boolean values change, even though its sort of a lot of work – Ofek Agmon Jun 05 '16 at 09:51
  • singleinstance prevent from making a new instance of activity! not finish anything. check the flags you pass to intent @OfekAgmon – Omid Heshmatinia Jun 05 '16 at 19:03
  • IMHO this is still the wrong way to try to solve this problem. Its a lot of code and it doesn't work well (as you can see from the stream of comments). There's a simple way to do this which should work. I think there's something else that's causing the problem. – David Wasser Jun 09 '16 at 16:15
  • what is the more simple method ? @DavidWasser – Omid Heshmatinia Jun 10 '16 at 06:05
  • @Smartiz see http://stackoverflow.com/questions/5502427/resume-application-and-stack-from-notification – David Wasser Jun 10 '16 at 20:21
  • That is what the user first did and it did not solve the problem. my method is always working on any version of android. Also it let user to do whatever he/she likes to do, according to different state of her/his app. In last 3 lines of the question, the user mention that in what situation that method won't work. @DavidWasser – Omid Heshmatinia Jun 11 '16 at 04:10
  • In my opinion, the user has a different problem or didn't implement correctly. I don't believe that your solution "works on any version" because there are a lot of complex situations. Your code has a high level of dependency between components (not good OO design). Your code is difficult to maintain because it means that these variables need to be added/modified whenever a new `Activity` is added to the application. Also `launchMode="singleInstance"` has its own set of problems which I could write a book about. This is also a lot of code to solve a problem that should be solvable without any. – David Wasser Jun 11 '16 at 06:45
  • In order to use `launchMode="singleInstance"` you need to understand how `taskAffinity` works. You also need to realize that you can end up in a situation where you have multiple tasks running in parallel. The user will see multiple tasks in the "recent tasks" list and may be confused about which is which. Or it may be difficult or impossible for the user to return to one or the other of the tasks. – David Wasser Jun 11 '16 at 06:47