Library used: appcompat-v7:22.2.1,design:22.2.1
Theme used:
Devices/Android versions reproduced on: Nexus 6
Issue: Return activity quickly redraws/appears then fades in with desired behaviour, only with "Don't keep activities alive".
I am wondering if this is a bug or expected behaviour. I have a very simple setup. Activity A contains a toolbar wrapped in an AppbarLayout and CoorindinatorLayout. The toolbar contains a Cardview and a TextView. Upon click of the TextView, Activity A launches Activity B. I am using shared elements and passing them through as Option's via ActivityCompat.StartActivity(bundle, options);
My shared elements work perfectly, even after device rotation. After reading about how I can PostPoneEnterTransition and combo it up with PreDrawListeners I am able to successfully achieve the desired transition even after rotation. My actual activity contains a Viewpager / TabLayout and 2+ fragments but for simplicity sake, I've stripped it back in the video as well as to see if something else was causing this issue.
While dealing with rotation and postponing of the enter transition back to Activity A, I decided to open developer options and check "Don't keep activities alive". The video depicts the app running with that option enabled. If you look closely, you can see upon return to Activity A, it is completely drawn and hidden very quickly and then the fade in occurs as well as the shared element transition.
I've also excluded the navigation bar and status bar in the animations so that I don't see those flicker (redraw redundantly).
My questions are:
Is this a bug, or am I missing a step in order to prevent this.
Why would the app/transitions behave differently with "Don't keep activities alive" vs a plain old device rotation (destroy/recreate).
I've noticed by playing around with some google apps, this behaviour does not occur, or at least that I could find. Is there a way to concretely check if the activity I am returning too is "completely destroyed" so I can cancel the animation? Or do something different?
I can include specifics and code samples if required but my setup is very simple, and reflects a bunch of boilerplate examples from the Android documentation / Stack-overflow.
Sorry I meant to respond to this earlier. What I ended up doing was recreating the example in a completely fresh project following code samples and tutorials as best I could. First making it work with a single image view, and then of course adding my custom layout which was a floating search bar. Everything worked as expected. I went back and reviewed my actual project source (which was littered with different attempts and commented out code while trying to debug this issue) and cleaned it up. I can't say for sure, but I believe it came down to two possible issues:
"Unless you do something unusual..." - Most likely I "was" doing something unusual by the time I created this issue do to my debugging efforts and lack of full comprehension of the shared elements transition framework and lifecycle.
I think what was happening was the shared element transition was failing do to views not being mapped properly. I was excluding the statusBarBackground inside a transition defined in XML. My statusBarBackground was set to transparent so that I had the nice overlay effect for an expanded drawer layout. I found out that while trying to add the statusbarbackground as a shared element via code, the view was actually null resulting in a crash (NPE). As well as I had set a background color (instead of transparent) to my drawer layout. I can't say for sure, but a combination of these mistakes lead to the strange behaviour.
To conclude, I would say that this issue should be closed and everything is working as intended. It would be nice to get a little more insight on handling a transparent status bar as a shared element.
Is this a bug, or am I missing a step in order to prevent this?
No. Everything is working as intended.
Why would the app/transitions behave differently with "Don't keep activities alive" vs a plain old device rotation (destroy/recreate)?
It doesn't. When everything is setup proper and your timing and mapping of shared elements is correct, "Don't keep activities alive" is a concrete way to test your transitions against configuration changes.
I've noticed by playing around with some google apps, this behaviour does not occur, or at least that I could find. Is there a way to concretely check if the activity I am returning too is "completely destroyed" so I can cancel the animation? Or do something different?
This is because the Google dev's did it right :)
For anyone struggling with shared elements, here is a bit of advice.
Start small. Use a single view first and confirm you are getting the correct behaviour in all circumstances, even after rotation and config changes, then you can add complexity.
Use SharedElementCallback to debug your transitions. You can check which views are mapped, which view failed etc.
Related
I'm trying to run a shared element transition from a recycler view to a detail view containing a pager. Pretty much the same as in this blog post.
Everything works, except that the back-from-detail-to-overview animation is clipped to the overview recycler view cells.
After watching this talk, I learned, that unless setSharedElementsUseOverlay is set to false on the activity's window, the transitions will run on an overlay that's on top of everything - the whole content of the activity if I understood correctly. So it should not be possible that the transition is hidden or clipped.
I searched both for setSharedElementsUseOverlay and windowSharedElementsUseOverlay in my project and didn't find anything. The default is supposed to be true. I also tried setting it explicitly to true, both in the theme and programmatically and nothing... the transition is still clipped!
I tried to cause the clipping with the demo project from the blog post, and also wasn't able to - setting setSharedElementsUseOverlay to false doesn't cause any clipping. I ensured that no view in the whole project has clipChildren or clipPadding set to false.
I have no idea what else to do. I tried debugging Android's sources but the transitions classes are unwieldy and I couldn't even find where the overlay view is used. The only thing that I get working in my project is setting clipChildren and clipPadding to false all the way up in the hierarchy, but this is not what I want - besides of undesired side effects (even when doing it temporarily as it may overwrite non-defaults of parents) it also doesn't cause the effect I want without further tweaking, as now overlay views of the shared element appear on top during the transition.
Well, I can step by step modify the example project until it's the same as my actual project, but this is a very tedious task as the actual project is very large and complex. I have done some changes that seem relevant, like adding intermediate views and so on. No success so far.
I simply want to use the overlay. What can be the reason for it not working? Or at least how can I debug this?
I've reproduced this so far on Android M and N. Haven't tested on any other versions.
This is a bit of a desperation call for some good advice.
I began doing a project which involves Navigation drawer as the main menu for the application. After looking at the Android tutorial I followed the example and start developing on top of that. That example is a single activity that replaces the fragments depending on the selected option in the drawer. In part, I followed this design because if I launched Activities the drawer was lost and the Activity would appear with the launching transition and didn't look nice at all.
Now, my project is not a small one. During development I faced several issues like:
onResume not being called on the Fragments (due to not being attached to several activities but one instead.
All the data between Fragments should pass through the single Activity
Managing the Options Menus in the ActionBar became a real pain.
And many others I don't recall now
Now I am facing a new issue. In one of the fragments I need to have a Spinner that will switch fragments inside this one. And of course, the fragment will need to change the navigation mode in the action bar. This was a major headache to develop, but now I am facing a bigger problem with some fragments inside losing the activity context (like if they were detached).
After so many problems I just decided to switch back the whole app to Activities (this is a custom app that will run in just 1 tablet model, so no worries about fragmentation). So, in short I am looking for advice on the less painful way to do this.
I am on a extremely tight deadline that lead me to start implementing without designing (like a complete noob). Now I am being hit with so many issues that, if I didn't need the money, I would cancel this project at once.
Please help!
I can give a little advice, but sadly your situation can't really be solved by any one answer here.
First off, switching from a Fragment design to an Activity design is a lot easier than switching the opposite way. You can actually use all of the fragments you had before, and just have each activity loading only 1 of the fragments (or multiple if you prefer).
Also, when handling Intents (starting new activity), after the startActivity() call you can call overridePendingTransition() to make the launching transition whatever you want (or remove it completely).
This is an odd problem that took me quite awhile to reproduce reliably.
I have a menu activity that is very simple; just some buttons defined in xml.
I have an activity with a layout with a GLSurfaceView and some buttons defined in xml.
These buttons have onClick attributes defined. This activity is accessed from the menu activity.
In the OpenGL activity there are the associated onClick functions "onFoo(View view)".
When I navigate back to the menu activity using the native Back button nothing interesting happens; however, when I click ANY of the xml defined buttons with an onClick attribute and then navigate back some of the ImageViews on the menu activity appear as black but otherwise in their correct locations, sizes, etc. Their xml defined onClick functions work correctly as well.
I am having all of the images on the menu activity re-exported (to eliminate any export setting flaws since the assets were originally exported at various times), but while I wait for that to happen I figured maybe someone out there has run into this problem before.
For the purpose of limiting variables in this problem I even commented out the function's contents in the OpenGL activity to make sure nothing in the onClick functions was causing a conflict.
e.g.
public void onMainMenu (View view)
{
}
So, to clarify, if I click a button defined in xml with an onClick attribute e.g.
android:onClick="onMainMenu" with the above empty method, then press the native back button the issue occurs, but not when skipping the clicking of the onMainMenu button.
I can't be sure if it is always the same set of ImageViews that turn black, but one ImageView does seem to consistently survive with the correct Drawable; this is odd because the ImageViews are defined identically other than their src attribute. They are all relatively the same size and not large at all.
I originally thought it had something to do with the EGL context (Android displays black rectangles instead of drawable images after opening openGL context) (and it still may be the case), but then I discovered how to reproduce it 100% of the time by pressing a button with an onClick attribute before navigating backwards. Memory usage is in control and I am lost for a possible solution or trail to one.
I can reproduce this on the three devices I have: an HTC One, Droid Bionic, Galaxy Tab 2 7.
The Application is minSdk:14, target:17. Hardware acceleration is on.
I tried playing with hardware acceleration settings with the following results:
If I turn off hardware acceleration for the application, and add it to just the OpenGl activity the main menu issue does not appear, but the same issue starts occurring in the OpenGL activity. In the case of this activity some ImageView's drawable resources are switched out at run-time. The switched in resources display correctly, but when switched back to the same resource that the was defined for that ImageView in xml it renders black.
To clarify the switching: in one such case I have views with a drawable-state-selector for their backgrounds. When switching between the two states (they function like tabs i.e. their default states as defined in xml are opposite) the default state always displays as black but the secondary state displays correctly.
If I turn off hardware acceleration for the application AND the OpenGL activity, the problem appears to go away completely.
I worry about using that as a solution though as I can't be sure of any performance problems that may occur on devices I do not have to test with.
Removing hardware acceleration from the OpenGL activity breaks a view that overlays the GLSurfaceView on at least the Droid Bionic, so I'd rather not use this pseudo-solution.
This is the first time I have posted a question on Stack Overflow. I always find a solid lead searching, but just could not find a solution or even a problem with similar circumstances in this case.
Thanks for any help and wisdom the community can provide!
The problem came down to a call to GLES20.glDeleteTextures(int size, int[] textureNames, int offset). I was calling this during onPause() which was somehow causing a conflict. I am not sure how it was related to touching a UI item outside of the GLSurfaceView. Removing the one call somehow prevents the issue.
I'm looking for the the best way to reproduce, in an Android app, the behavior of the iPhone UiNavigationController within an UITabBarController.
I'm working on this Android app where I have a TabActivity and 4 tabs. I've already gone through a lot of posts regarding the use of activities and tabs and how it's not a good idea to use activities for everything, which seems fair enough. I decided to use one Activity on each tab anyway, since it makes sense in my application.
However, in one of those activities I have a deep navigation tree with more than one branch and up to 12 different views the user can go through.
The problem is: Android controls the navigation through activities inside an app, if you click the back button it will go to the previous one, but if I'm navigating through views, using one Activity, and I click back, it just finishes it. So how can I have a smooth navigation behavior between views in an Activity?
I had implemented this using a TabActivity with FragmentActivity as each tab. Utilizing Fragments API you can organize the code just like you would be using 12 different activities, still using only 1 for each tab in fact. Fragment's framework will handle back key press for you to show previous fragment instead of closing the entire activity.
There are some problems with such approach, for example, there's no MapFragment, but the workarounds can be found here on SOF.
You will need Android Support Package if your minimum SDK version is lower than 3.0.
Well I know very little about UiNavigationViewController, but I guess you want something to navigate between different Views. As you are using TabActivity, every tab should load into a separate Activity.
But since you want to branch it out, using that many Activities is not a perfect solution, neither the ActivityGroup too. The better solution, as per my opinion(I have run into similar problem once) is to have the main or root tabs loads into separate Activity, but for their branches, use the ViewFlipper, which flips the Views. So the whole Layout(Subclass of View) can be flipped.
You may run into some problem while flipping more than two Views (as what people say, though I never had any problem). So in that case you can use layout.setVisibility(View.GONE) to hide the layout and just change it with View.VISIBLE for next view.
And about the concerns of back button, you need to store the last used View or Activity into a variable, and in the override of onBackPressed(), just need to call them.
There might be better solution than this, not that I can remember, but yeah it's the easiest solution I can come up with.
Which you think is the best way of doing a wizard like application (user can navigate between screens with a next and back button, and each screen has to save some state data) in Android platform.
I mainly can think in two approaches:
Having one activity+view for each screen and then i make the screen switch by calling each activity. What make this nice is that i can use the system back button as my back handler and i don't have to take care of that myself, aslo each activity will save it's own state.
Having one activity and many views, and what i switch views in each screen change, this helps me re-use more code, but makes saving states a mess.
What do you think? Which is the best way of doing this on Android?
This library is no longer being developed.
Use Android Navigation Component with combination of ViewModels to build a wizard flow.
I've developed a lightweight Android library, which is built on top of Android's ViewPager that can be used for creating wizard like activities. Check it out: WizarDroid.
I suggest going with 2 as it fits the goal of activities and views. Saving state in this case is easy - if you use the MVC pattern, you can simply have a model object that is passed along to the views. Each view will have portions of the model that it can read/write. No matter where you are, the model should always have the current state. If you get disposed, just save the model. Restore works automatically since you already read from the model when you show each page.
I've gone with the first approach as it seems more natural. Another app uses ViewFlipper for switching views but that's far from anything like wizard.
9 years ago this was obviously a very different kettle of fish - but I think the best way to do this now is with Fragments.
Have a Fragment for each 'page' in the wizard, letting it handle its own lifecycle and state.
Change page from within each Fragment with Fragment.getFragmentManager() - this returns the FragmentManager from the parent Activity, allowing the Fragment to replace itself.
I think 2 is better. Put each "page" in a view and then just alternate between showing and hiding them. Makes it trivial to do nice transitions. What state are you thinking of maintaining? The only one that doesn't work automatically would be focus and I think you probably want to reset that every time you switch pages. It is also trivial to catch back if you think that is the right behavior for your app.
With 1 you can reuse almost all of your code (just define your own WizardBase class) but I think activities are much slower to launch (and require more memory) than switching between views.