My application displays a splash screen for 1 second before displaying the main activity. Both the splash screen and main activity share a common image that is required to animate from the center of the splash screen to the top of the main activity layout.
Since it wasn't obvious how to accomplish this animation if the splash screen was implemented as a <layer-list> background image in the main activity (see Splash Screens the Right Way or How do I make a splash screen?), I decided to implement the splash screen as a normal activity and use a shared element transition to animate the image between the two activities. Initially, I used the following onCreate() implementation in the splash activity:
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
ImageView imageView = (ImageView)findViewById(R.id.imageView);
String transitionName = ViewCompat.getTransitionName(imageView);
Intent intent = new Intent(this, LoginActivity.class);
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(
this, imageView, transitionName);
imageView.postDelayed(() -> {
ActivityCompat.startActivity(SplashActivity.this, intent, options.toBundle());
finish();
}, 1000);
}
}
There are two problems with this approach:
Calling finish() immediately after calling startActivity() causes the splash activity window to be hidden/destroyed before the animation starts which results in the home screen temporarily flashing into view during the animation.
Pressing back from the main activity automatically triggers a shared element return transition that results in the image appearing suspended over the home screen for 500 ms after the main activity window has been closed. The return transition fails because the splash activity has already called finish() and therefore is no longer on the back stack.
To solve the first problem, I wrapped the finish() call in a postDelay() Runnable to ensure that it only gets invoked once the shared element transition has completed. A 1500 ms delay works in my application, but that value should be adjusted to depending on the timing required by other use cases.
...
imageView.postDelayed(() -> {
ActivityCompat.startActivity(SplashActivity.this, intent, options.toBundle());
imageView.postDelayed(this::finish, 1500);
}, 1000);
To solve the second problem, I overrode the main activity's onBackPressed() method to directly call finish() thereby avoiding the default implementation's call to finishAfterTransitions(). This prevents the Activity from attempting to perform the shared element return transition.
#Override
public void onBackPressed() {
finish();
}
Any alternative approaches or suggestions to improve this solution would be appreciated.
Why don't you use fragments that sharing same activity instead? I don't see a reason to use 2 different activities for such a simple things.
Instead of finish(); use ActivityCompat. finishAfterTransition(this);
I faced similar problem also.
One approach can be to not to call finish() in Splash screen and in next screen call finishAffinity() on onBackPressed().
Related
Normally when the back button is clicked it goes to the previous activity and if the current activity is the first activity, the application closes.
I have a splash screen (that is logically my first activity) and then the menu activity loads.
I want to close the program when the back button is pressed on my menu activity (as if it is the first activity) and avoid going back to the splash screen again, but I know that I should not exit the program.
I was wondering what is the functionality of back button on the first activity?
does it put the program to pause?
Avoid splash screens !
Instead of using your splash as the main activity, use menu activity as the main one, and in onCreate() chain off the splash activity, which will close and disappear forever.
When new Activity is launched from first Activity, first Activity is executed until onStop() method, then it stops and waits for relaunch, unless you killed it by calling .finish(), in that case launched Activity becomes first Activity and back button will minimize application on back button press. In order to control what application does on back button press you can override this method in your Activities and implement your own custom behaviour:
#Override
public void onBackPressed() {
super.onBackPressed()
}
Very good example of how lifecycle of Fragments/Activities work can be seen in picture below:
Hope this helps. Good luck.
While you are on the SplashScreen, on the method calling your menu activity I assume you are doing something like startActivity (new Intent (this, MenuActivity.class)); in Java or startActivity(Intent(this, MenuActivity::class.java)) for Kotlin just after that call finish() this will remove your SplashScreen from the back stack
add this attribute to your splash activity (in manifest):
android:excludeFromRecents="true"
pressing back in per activity, transfer control to prev activity in stack (back stack) that not excluded from "Recents".
I'm trying the new Android API, specifically the new animations. I have two activities and used setEnterTransition() and setExitTransition() on the second activity with a Slide transition. Everything works fine when I switch activities using the buttons inside them, or using the back button, but when I'm on the second activity and I press the Home Button the return animation is not played...
Second activity onCreate() method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActionBar() != null) {
getActionBar().setDisplayShowHomeEnabled(false);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
Slide slideTransition = new Slide();
slideTransition.setDuration(1000);
slideTransition.setSlideEdge(Gravity.RIGHT);
getWindow().setEnterTransition(getSlideTransition(Gravity.RIGHT, 1000));
getWindow().setExitTransition(getSlideTransition(Gravity.LEFT, 1000));
getWindow().setAllowEnterTransitionOverlap(true);
setContentView(R.layout.activity_second);
//...
}
The first activity is set as parent of the second activity in the manifest.
I find some solutions that use the overridePendingTransition() method, but I would like a solution that uses the new methods (if that is possible).
Thanks!
This is by design. The return transition is only triggered when the activity is explicitly finished (i.e. you press the back button or call finishAfterTransition()). When you press the home button, you are putting the application into the background so that the user can return to that same activity at a later time. If you were to finish the activity when you pressed the home button, the user would be confused as to why they were not taken to that same activity when they return to the application later on.
It is also worth mentioning that the new Lollipop transition APIs are not meant to replace overridePendingTransition(). The two are fundamentally different. The Lollipop transition APIs give you a way to animate the contents inside an activity's view hierarchy individually when you switch from one activity to another. On the other hand, overridePendingTranition() allows you to override the system's default window animation when the activity window is being added or removed from the screen. In other words, the former operates on the views inside the activity's window whereas the latter operates on the entire activity window itself.
One last major difference between the two is that the new Lollipop transition APIs only work between two activities that belong to the same task. If you want to perform an exit/enter animation when navigating between two activities belonging to two different tasks, you'd need to use overridePendingTransition() instead.
I have an Android app that does about 30 seconds of heavy duty number crunching at the start of the app. How do I display a screen that disappears at the end of the initial processing?
What I currently do is:
My activity_main.xml's topmost view is a ViewAnimator which has (for now) two child views - the main view, and a FrameLayout which currently is a white background that fills the screen and a child text view with "Processing..." on it.
My MainActivity.java's onCreate() method calls a user-defined method doInitialProcessing(); doInitialProcessing calls the ViewAnimator's setDisplayedChild method to show the "Processing" view, then does the number crunching, then calls setDisplayedChild again to show the main view.
In the Eclipse Emulator, what usually happens is, the screen turns white at first, then goes black, then the main view appears. (Every now and then, the "Processing..." text shows up.)
Is this the right way to go about this? Show the initial call to setDisplayedChild be in a separate thread? Does the fact that it is called from onCreate have anything to do with it?
There are two ways to do it:
Create a normal activity with a layout for your splash and start the other activity using a timer. (this way, you cannot load data in the second activity)
The other way is to create a splash fragment, that is displayed for a few seconds while the content is loaded in the background.
I use the following timer to start my activity from SPlash activity. This can also be used in a fragment:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent in = new Intent(SplashActivity.this, HomeActivity.class);
startActivity(in);
finish();
}
}, SPLASH_TIME_OUT);
SPLASH_TIME_OUT is the delay in integer value. (1000 for sec)
You can use a Splash Screen that shows something like the logo of your app for instance for some seconds while the app munches on the numbers.Here is a good tutorial on creating Splash Screens.You can also read up on this StackOverflow question.
My application starts with a welcome screen Activity, but that screen has an option to skip that screen altogether in future launches.
What's the proper Android way to do this? Initially, I just automatically detected the skipWelcome preference and switched to the 2nd activity from Welcome. But this had the effect of allowing the user to hit the back button to the welcome screen we promised never to show again.
Right now, in the Welcome activity, I read the preference and call finish() on the current activity:
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
boolean skipWelcome = preferences.getBoolean("skipWelcome", false);
if (skipWelcome) {
this.finish();
}
And then I implement onDestroy to move on to the next Activity:
#Override
public void onDestroy() {
super.onDestroy();
startActivity(new Intent(Welcome.this, StartFoo.class));
}
But this makes for some weird visual transitions. I'm starting to think that I need a base Activity that pops open Welcome only if proper, and then goes to StartFoo.
I can't comment on Mayra's answer or I would (not enough rep), but that's the correct approach.
Hidden in the Android documentation is this important phrase for Activity.startActivityForResult(),
"As a special case, if you call
startActivityForResult() with a
requestCode >= 0 during the initial
onCreate(Bundle
savedInstanceState)/onResume() of your
activity, then your window will not be
displayed until a result is returned
back from the started activity. This
is to avoid visible flickering when
redirecting to another activity."
Another important note is that this call does not block and execution continues, so you need to stop execution of the onCreate by returning
if (skipWelcome) {
// Create intent
// Launch intent with startActivityForResult()
return;
}
The final piece is to call finish immediately in the welcome activity's onActivityResult as Mayra says.
There are a few solutions to this.
Did you try just launching the activity and finishing? I vauguely remember that working, but I could be wrong.
More correctly, in if(skipWelcome) you can start the new activity for result, then when onActivityResult is called, immidiately finish the welcome activity.
Or, you can have your launcher activity not have a view (don't set content), and launch either the welcome activity or StartFoo.
i have a program that shows a splash screen.But the problem is whenever i refresh same page again it appears.Is there any method to stop splash screen again and again.I want it just comes at first time not again and again.
Thank you
So you basically want the splash screen appear once per app launch.
Here's a quick and dirty way:
Subclass android.app.Application as, say, MyApp;
Declare that class in AndroidManifest.xml (<application android:name=".MyApp" ... >) so that it would get instantiated at app launch time;
Give it a public static boolean SPLASH_SHOWN = false;
Now, in your Activity's onCreate() check if SPLASH_SHOWN = false, show splash and set it to true.
If you implement the splash screen in the same activity with another view layout (the main layout) - for example, display splash screen first, then swich the view to the main layout - I suggest to control the content view setting in onResume().
Use a boolean variable (displayedSplash) to remember whether the splash screen has been displayed. If it has not been displayed (start the activity the first time, displayedSplash == false), then set the view to the splash screen, after that switch to the main layout and set displayedSplash = true. If it has been displayed (refresh the page, displayedSplash == true), just set the view to the main layout.
Another simple and safe solution for simple splash screen is implementing it as an activity, then start the main activity. When the onResume() is called the second time, just finish the activity. Please refer to this Wiki for the detail.
Most of the times I call finish() method inside onPause() method in splash activity. This will work fine for me