I do not understand the differences between when a user locks the screen (using the top screen lock button) and immediately returns to the application vs. when the user presses the home button and then immediately returns to the application.
It seems that all the same calls are being made. From my observations:
Called when home button or screen lock are pressed: onPause -> onStop
Called when application is pressed after home button or screen lock is re-pressed: onRestart -> onStart -> onResume
My individual problem:
This is particularly causing me greif because I am recreating a SurfaceView and a GLSurfaceView to a FrameLayout upon onResume, however, depending on the button pressed, the ordering of the elements is getting changed. I have the following code in my onResume:
cameraPreviewArea = (FrameLayout) findViewById(id.camera_preview);
cameraPreviewArea.addView(glView, glLayout);
cameraPreviewArea.addView(camprevSurfaceView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
This has the effect of displaying my glSurfaceView on top in the following situations: the first time the app has launched, and when the app is being resumed from being screen-locked and then screen-unlocked. However, upon pressing the home button, and then reopening the application, the SurfaceView is being placed ON TOP of the glSurfaceView!
If I switch the addView calls as follows, the opposite situations will occur. I could fix this with some boolean flag, but it it unclear where I would set the boolean because of my uncertainty as to the difference between a screen lock/unlock and the home button. Also, I do not want to solve the problem in this manner anyway because it seems hacky and lacks any real understanding of the problem.
Thank you in advance!
In general, there is no reason you should need to constantly add and remove views from the hierarchy of your Activity, and removing this code will make your application more consistent.
Since both of the views you are interested in are SurfaceView components, if there is some action that you need to take when the window becomes visible or hidden, you can take advantage of the SurfaceHolder.Callback to monitor the onSurfaceCreated() and onSurfaceDestroyed() methods.
This specific situation - using two surfaceViews and specifying their Z order within a window - does not seem to currently be supported by Android. This thread over at the android developer group shares the following information:
Multiple active overlapping surface views, of any sort, are not
currently supported by the framework. You may get them to work, but
it is mostly due to luck -- the view hierarchy does not define the
Z-ordering of those surfaces, nor try to ensure they are Z-ordered in
any particular way, so this may change for whatever reason.
Well... there you go!
...But for anyone attempting this I found a workaround: make your camera preview size a tiny 1x1 square. This will allow you to display both simultaneously (because a camera preview must be visible in order for the preview to continue) and ignore the pesky SurfaceView issues that the cameraPreview presents you with. I believe there is a better solution using strictly one GLSurfaceView, but it is not compatible below 3.0.
Related
I have an APK that runs completely fine across several android levels varying from android 5 through 9. We started testing a new android 9 phone (Hot Pepper HPP-L55B aka Serrano), and I'm seeing an interesting issue that I'm hoping someone has come across.
All of my Activities extend a base activity that does some standard logging (such as logging onCreate, onResume, etc).
On app launch:
Activity 1 - MainLaunch
onCreate starts the activity Splash then calls finish
Activity 2 - Splash
onCreate sets the content view and finds the WebView on the screen.
onResume sets a gif in the webview so it's rendered on the splash screen. It also starts a thread that sleeps for a few seconds that then kicks off Activity 3. The gif animates as expected.
Activity 3 - Launchpad
onCreate sets the content view and finds references to other items on the screen (buttons and textviews).
onResume checks a few internal things, and may or may not hide things on the UI based on configuration. Nothing to exciting.
There are times this process will go through without a hitch, and other times where the UI that was being displayed in Activity 2 (splash) stays up while my logs are showing that the code thinks it's showing UI 3. The gif in this case is no longer animating.
As you click around on the splash screen the buttons that are referenced and would be showing on Activity 3 are being pressed. So basically like the splash screen is covering the 3rd activities screen and allowing button push pass through. If i turn the screen off/on again the splash screen still shows up. Throwing breakpoints in activity 3 get hit as the hidden buttons get clicked.
Anyone ever see this before or have suggestions how to fix it? This phone model seems to be the only one with the issue. So it definitely seems like a phone model problem and not anything i can control. Any suggestions?
This problem boiled down to the processor (MediaTek) being used in combination with the theme being used for the application. At least that was the only thing that was found different across the supported phones we tested.
The theme for the activities were changed:
from #android:style/Theme.Translucent.NoTitleBar
to #android:style/Theme.Light.NoTitleBar
I have bulit a TicTacToe game for Android and for starting a new game I call startActvityForResult() to let the user choose some options in the new Actvity. Then I call setResult() and finish() to get back to my gameActivity containing the SurfaceView in a LinearLayout.
But here comes the Problem: The whole SurfaceView is just a black area until I tap somewhere, then it acts as it should: the onTouchEvent() method is called and the game becomes visible.
Any ideas how I can get rid of that black screen?
I already tried setting the LinearLayout and the SurfaceView visible/invisible during onResume()/onPause. And invalidate()or postInvalidate()don't work either.
I found out it seems that it is displayed correctly, if the surface is drawn twice, so I call postInvalidate()inside of draw()via a boolean flag.
This is difficult to answer without any code or more detailed information, but you should start/stop rendering to your surface view in the onPause()/onResume(), or in the onSurfaceDestroyed()/onSurfaceCreated() methods. So basically, you must properly handle the surface view in the activity lifecycle.
This is quite specifically dealing with this topic (activity lifecycle + surface view).
As a quick fix, you could just try calling onTouchEvent() manually in onResume or onSurfaceCreated().
I'm a little confused over how key events (back key, volume keys) relate to Views in android.
Take for example the problem I currently have:
Working OK
Create Layout (for example, Relative layout)
Add View to Layout (A GL SurfaceView)
Run app and wait for everything to load (and for GLSurfaceView to be created)
Press home key
Re-launch app
Press back to exit
Not Working OK
Create Layout (for example, Relative layout)
Add View to Layout
Run app and press home key before GLSurfaceView is fully create/displayed
Re-launch app quickly again before GLSurfaceView is fully create/displayed
Wait for SurfaceView to be displayed
Although touch events work Keys no longer work and app can't be exited
why is this? Is there anyway to get focus back to this view? (if 'focus' is the correct terminology in this example).
I've tried
myGLView.requestFocus();
I've also tried various other methods but nothing seems to work - surely there must be a quick and easy way to make sure key events work with the currently visible GLSurfaceView?
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 was wondering why not use android:configChanges="keyboardHidden|orientation" in every (almost every ;)) activity?
Goods:
no need to worry about your activity been rotated
it's faster
Not so nice:
need to change your layouts if they are depending on screen size (e.g. layouts with two columns or so)
Bad:
no flexible way to have different layouts on different orientation
not so good when using fragments
But if we don't use different layouts, why not?
Quick Background
By default, when certain key configuration changes happen on Android (a common example is an orientation change), Android fully restarts the running Activity to help it adjust to such changes.
When you define android:configChanges="keyboardHidden|orientation" in your AndroidManifest, you are telling Android: "Please don't do the default reset when the keyboard is pulled out, or the phone is rotated; I want to handle this myself. Yes, I know what I'm doing"
Is this a good thing? We shall soon see...
No worries?
One of the pros you start with is that there is:
no need to worry about your activity been rotated
In many cases, people mistakenly believe that when they have an error that is being generated by an orientation change ("rotation"), they can simply fix it by putting in android:configChanges="keyboardHidden|orientation".
However, android:configChanges="keyboardHidden|orientation" is nothing more than a bandaid. In truth, there are many ways a configuration change can be triggered. For example, if the user selects a new language (i.e. the locale has changed), your activity will be restarted in the same way it does by an orientation change. If you want you can view a list of all the different types of config changes.
Edit: More importantly, though, as hackbod points out in the comments, your activity will also be restarted when your app is in the background and Android decides to free up some memory by killing it. When the user comes back to your app, Android will attempt to restart the activity in the same way it does if there was some other configuration change. If you can't handle that - the user will not be happy...
In other words, using android:configChanges="keyboardHidden|orientation" is not a solution for your "worries." The right way is to code your activities so that they are happy with any restart Android throws at them. This is a good practice that will help you down the road, so get used to it.
So when should I use it?
As you mentioned there is a distinct advantage. Overwriting the default configuration change for a rotation by handling it yourself will speed things up. However, this speed does come with a price of convenience.
To put it simply, if you use the same layout for both portrait and landscape you're in good shape by doing the overwrite. Instead of a full-blown reload of the activity, the views will simply shift around to fill the remaining space.
However, if for some reason you use a different layout when the device is in landscape, the fact that Android reloads your Activity is good because it will then load up the correct layout. [If you use the override on such an Activity, and want to do some magical re-layout at runtime... well, good luck - it's far from simple]
Quick Summary
By all means, if android:configChanges="keyboardHidden|orientation" is right for you, then use it. But PLEASE be sure to test what happens when something changes, because an orientation change is not the only way a full Activity restart can be triggered.
From my point of view: If the layout is the same in both landscape and portrait mode - you might aswell disable one of the two in your app.
The reason why I state this is that I as a user expect the app to provide me with some benefit, when I change orientation. If it doesn't matter how I hold my phone, then I don't need the choice.
Take for instance an app where you have a ListView, and upon clicking a ListItem you want to be shown a detailed view for that item. In landscape you would od this by dividing the screen in two, having the ListView on the left and the detailed view on the right. In Portrait you would have the list in one screen and then change the screen to the detailed view when a ListItem is selected. In that case orientation change makes sense as well as different layouts.
I don see why.... occasional restarts are ok in my opinion... configChanges handles most cases for me... well maybe in some types of applications this can be problem but it depends really on type of app and how you restore state when app restarts... When one of my app restarts user is logged back and last activity opens by my code and user jus loses some steps to go back where he was but not big deal.. In other some state is always persisted and some state is always restored on restart. When activity restarted it had to be that app have not been used or something... so no problem at all... In game for example this can be problem maybe or in some other type of app I don't know...
I say that when you do it this way applications just works fine under normal circumstances. And code is much more readable without ton of logic needed for saving and restoring where u just can make new bugs and have to maintain it all the time... sure if android gets out of power and kill you application window it lose the context and starts again, but this happen just in special situations and on newer devices I belive this is more and more rare...
So kill me, but I use this across applications quite successfully...
android:configChanges="locale|keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
But I understand that for some special kind of applications it may be not good way but most of apps can live with this just OK.
Yeah I think pausing will make it quicker than releasing the player. Still have the pause though.
Have now found a solution that won't pause the song.
State in the manifest that you will handle the config change for screen orientation and then use the onConfigurationChanged method to load the layout file. By doing this in logCat I can see onPause, onCreate & onResume aren't called, and therefore the song isn't paused.
update the manifest to handle the orientation.
android:configChanges="orientation|screenSize"
add this code
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
setContentView(R.layout.activity_main);
}