8

I have a MainActivity (which has launchMode=singleTop) from which I go to other activities, For eg B and C. Now, I want to navigate back to MainActivity on some button click in B and C. And also I want transition animation.

Here is the code

CODE 1

Intent intent=new Intent(this,MainActivity.class);
        Bundle animation= ActivityOptions.makeCustomAnimation(getApplicationContext(), R.animator.translate_left_to_right, R.animator.translate_source_left_to_right).toBundle();
        startActivity(intent,animation);
        finish();

The above code works fine, EXCEPT the fact that a new instance of MainActivity is created on top of the old one! I don't want that to happen. So, after a bit of research I tried the below code


CODE 2

Intent intent=new Intent(this,ListingActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        Bundle animation= ActivityOptions.makeCustomAnimation(getApplicationContext(), R.animator.translate_left_to_right, R.animator.translate_source_left_to_right).toBundle();
        startActivity(intent,animation);
        finish();

This code seemed to remove the problem of creating a new instance of the activity as the flag FLAG_ACTIVITY_CLEAR_TOP took care of it. BUT, now the transition animation does not seem to work!
Does the flag FLAG_ACTIVITY_CLEAR_TOP not allow any animation? What is the solution to my problem? I need both animation transition and also that a new instance of the MainActivity should NOT be created.


EDIT
This seems to do the trick as suggested by David Wasser.

 Intent intent=new Intent(this,ListingActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        finish();
        overridePendingTransition(R.animator.translate_left_to_right,R.animator.translate_source_left_to_right);

BUT the animation is not smooth. There is a glitch in the animation. I think that is because the activity (B or C) gets destroyed before the animation is complete. I am not sure though

Posting the animations files

translate_left_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="-100%p"
    android:toXDelta="0%p"
    android:duration="400"/>


translate_right_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="100%p"
    android:toXDelta="0"
    android:duration="400"/>


translate_source_left_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0%p"
    android:toXDelta="50%p"
    android:duration="400"/>


translate_source_right_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="-50%p"
    android:duration="400"/>
Ashwin
  • 12,691
  • 31
  • 118
  • 190
  • Try setting `Intent.FLAG_ACTIVITY_SINGLE_TOP` in addition to `Intent.FLAG_ACTIVITY_CLEAR_TOP` and see if that helps. – David Wasser Jan 28 '15 at 16:45
  • If that doesn't work, you could try using `overridePendingTransition(int enterAnim, int exitAnim)` after calling `finish()` and see if that helps. – David Wasser Jan 28 '15 at 16:51
  • @DavidWasser : I made it work by making the MainActivity as 'singleInstance'. But the question still remains - how could CLEAR_TOP, make the animation go away? – Ashwin Jan 29 '15 at 02:10
  • I'm afraid using singleInstance launch mode is going to give you more headaches than you bargained for. Your application now runs in 2 separate tasks.When you have activity B or C on top, try pressing HOME and look at the recent task list. This is a very bad solution. – David Wasser Jan 29 '15 at 08:03
  • @DavidWasser hmmm.. Then what should be the solution. I tried your 1st solution. That doesn't seem to work. Will try the override one and let you know. – Ashwin Jan 29 '15 at 08:06
  • What devices are you testing on? What version of Android? – David Wasser Jan 29 '15 at 10:29
  • @DavidWasser : I tested on MotoG. Android 4.4.4 – Ashwin Jan 29 '15 at 10:30
  • @DavidWasser : Is this a bug?? – Ashwin Jan 30 '15 at 03:44
  • @DavidWasser : Would using singleTask be a good idea? – Ashwin Jan 30 '15 at 04:03
  • @Ashwin, Did you mean the backstack is A-B-C, while A is `MainActivity`? And do you want to add an animation when activity B back again to activity A? – Anggrayudi H Jan 30 '15 at 12:03
  • @AlbertNicko : It is either A->B or A->C. In either case I want on a button click in B or C, I want to navigate back to A with animation and also WITHOUT creating a new instance of A – Ashwin Jan 30 '15 at 12:23
  • Even though you've declared your Activity as `singleTop`, you should still add `Intent.FLAG_ACTIVITY_SINGLE_TOP` to the `Intent`. With this flag and `Intent.FLAG_ACTIVITY_CLEAR_TOP` ensures that a new instance won't be created. You can also remove the call to `finish()` after `startActivity()` as this isn't necessary. – David Wasser Jan 30 '15 at 12:44
  • I've got a device with Android 4.4.2 on it and have tested this and it all works fine for me. You may have a buggy device. – David Wasser Jan 30 '15 at 12:44
  • Can you post your animation XML? – David Wasser Jan 30 '15 at 12:45
  • Actually, a better solution, instead of calling `startActivity()`, would be to just call `finish()` and immediately after that call `overridePendingTransition()`. Please try that. – David Wasser Jan 30 '15 at 12:47
  • Here's another question with same issue: http://stackoverflow.com/questions/17228726/overridependingtransition-behaiving-different-with-intent-flags?rq=1 – David Wasser Jan 30 '15 at 13:17
  • @Ashwin, I made a miss understanding in the desrciption. Please read again. – Anggrayudi H Jan 30 '15 at 15:26
  • It looks to me like this is a bug on a specific device or in specific circumstances. Your code works fine for me on a 4.4.2 device (LG L65). We need to try to find a workaround that solves your problem. – David Wasser Jan 30 '15 at 16:55
  • @DavidWasser : Hi David. Sorry for the delay. I have posted the animation files. And not calling startActivity() is not a good solution for me. Because in some cases I need to pass intent data back to Activity A. Which code is working fine in LG L65?? Code1 or Code 2? – Ashwin Jan 31 '15 at 03:11
  • Code 2 works fine on the LG L65. – David Wasser Feb 01 '15 at 21:19
  • Clearly code 1 will not do what you want. Not on any Android version nor on any device. – David Wasser Feb 01 '15 at 21:21
  • @DavidWasser : Hmmm. The other link you gave to the similar issue doesn't give a solution to the problem. Is a work around possible? – Ashwin Feb 02 '15 at 03:07
  • @DavidWasser : Hi David. Just wanted to get something clarified. You said code2 worked for you. You tried it with animation right?? You were able to see the animation and also avoiding a new instance of Activity?? – Ashwin Feb 03 '15 at 06:38
  • @DavidWasser : And do you think code1 will do what I want, if I just change the sequence of statements so that finish() is called before startActivity()?? I will try it out myself buy just wanted to know if should work or not? – Ashwin Feb 03 '15 at 06:41
  • Code1 will always create a new instance. That much is clear. Rearranging the order of the method calls will not change that. Yes, code2 worked (with animations and no new instance creation) on an LG L65. – David Wasser Feb 03 '15 at 10:52

4 Answers4

4

I played around a lot with this. I was finally able to reproduce your problem. I was missing the launchMode="singleTop" for the MainActivity, which was why I didn't see the behaviour earlier. Sorry about that.

If I add launchMode="singleTop" to MainActivity in the manifest, then I can reproduce the behaviour with code 2.

Using my suggested code, I was able to solve the problem:

    Intent intent=new Intent(this,ListingActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
    overridePendingTransition(R.animator.translate_left_to_right,
                              R.animator.translate_source_left_to_right);

However, I also needed to change the animation resource file translate_source_left_to_right.xml to this:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
       android:fromXDelta="0%p"
       android:toXDelta="100%p"
       android:duration="400" />

This is what was causing the "glitch" in the animation. You had the incoming activity animate from -100% to 0% and the outgoing activity animate from 0% to 50% over the same period of time. So the outgoing activity moves half the screen width and then stops. I changed the outgoing animation so that it animates from 0% to 100% and now you see both views animating over the complete width (which I think is what you want).

Thanks for the challenge :-)

Maalevolent
  • 472
  • 1
  • 5
  • 12
David Wasser
  • 93,459
  • 16
  • 209
  • 274
2

There is better solution to do that without using Intent.FLAG_ACTIVITY_* or another FLAG. You can try to add android:noHistory="boolean" attribute in the AndroidManifest.xml. By using this attribute, please understand my concept map below:

enter image description here

DESCRIPTIONS

Because of ActivityC and ActivityD (also called with last activities) has a true value, so they cannot back to MainActivity, but they can back to ActivityA and ActivityB first. Also, ActivityA and ActivityB can back to MainActivity. So, no new instance will be created.

After you declared the value in the manifest, you only need to call the following code to open the next Activity (no FLAG is needed):

If you want to go to A from C or from D (in this case your activities, not the Activity on the concept map), call:

startActivity(new Intent(C.this, A.class));

See the concept map again, ActivityA is chained with ActivityC, and ActivityB is chained with ActivityD. Because of these activities look like chains, so you cannot call finish() or pressing Back Key to go to MainActivity directly. So that, call above code.

If you want to go to your ActivityA from ActivityB (in this case your activities, not the Activity on the concept map), you can call finish(). By default, Android will make you back to previous activity without call finish() when press the Back Key.

Usually, I don't need android:launchMode attribute while using android:noHistory="boolean" attribute.

Remember:

  • Set your last Activity with android:noHistory="true" in the manifest.
  • Another Activity must be set with false value.
  • Apply this attribute for all of your Activity.

As additional, here is how to use it inside your manifest:

<activity android:name=".MyActivity" android:noHistory="true" />

Add the animation

Override onResume() method in your ActivityA (in this case your activities, not the Activity on the concept map) and do your animation here:

@Override
public void onResume(){
    super.onResume();
    overridePendingTransition(R.anim.enterAnim, R.anim.exitAnim);
}

If doesn't work with onResume() method, try to override the animation in the onStart() method:

@Override
public void onStart(){
    super.onStart();
    overridePendingTransition(R.anim.enterAnim, R.anim.exitAnim);
}
Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87
  • 2
    This doesn't address OP's problem at all. OP isn't having issues with Activity navigation or workflow. Only with Activity transition animation in a specific case. In any case, your suggestion is not good. Using `noHistory="true"` has all kinds of side-effects that make a mess of the application's normal navigation flow. See what happens if you do this and then press the HOME button or take an incoming phone call when Activity `A` or `B` are on screen. After returning to the application, those Activities will be gone! – David Wasser Jan 30 '15 at 16:52
  • The `noHistory` flag is to be used sparingly and only in very specific instances, where you don't want the user to be able to BACK into the `Activity`. – David Wasser Jan 30 '15 at 16:52
  • 2
    @DavidWasser, you are right. I tried to press the HOME button where the activity is set with `noHistory="true"`. And the activity gets destroyed. – Anggrayudi H Jan 31 '15 at 11:21
1

This happens because transition donot have object to start transition and to end transition When we use clear stack then all activity get cleared and transition will left without nothing so have done this by implementing following line in my style code

But use this causiously

<item name="android:windowDisablePreview">true</item>

Sahil Bansal
  • 609
  • 8
  • 6
0

I have exactly the same issue with you.
However, using @David Wasser 's solution will sacrifice the parallax effect during transition. May be some developers don't want such behavior as well.

I then find another solution by checking if your MainActivity exists in backstack or not. Please check my answer here below:

how to check if activity is still in the stack?

Note that my solution will disable the animation, using system's default animation (same as finish()). But since you are really shutting down the current activity, I think this is more natural.

Sira Lam
  • 5,179
  • 3
  • 34
  • 68