I'm working on a multimedia video processing application for Android, and I've run into a bit of a problem. I'm using the FragmentPagerAdapter class with a number of different fragments inside for various steps of video processing.
My first Fragment contains a SurfaceView and a MediaPlayer that feeds it, along with various playback controls. My problem happens when I swipe from fragment 1 (with the SurfaceView) to fragment 2 (empty at the moment). If I haven't yet called start(), nothing unusual happens, and I'm able to swipe between fragments normally. Once I call start() however, the entire screen starts flashing on and off when I swipe to the next Fragment, even if I've put the MediaPlayer in the idle state and it's not feeding frames to SurfaceView. The only thing that stops this is destroying the surface along with the containing view by swiping to the third Fragment so the FragmentPagerAdapter destroys Fragment one, or exiting the application via the home or back button so the view is destroyed.
I can't for the life of me figure out why this is happening, other than that perhaps the SurfaceView rendering thread is somehow interfering with the main UI thread. Nothing unusual appears on LogCat, either, so I'm a bit stuck. I'm running a Galaxy Nexus with android 4.1 as my test hardware.
Any help would be appreciated!
JT
UPDATE: I've managed to find a workaround for now by overriding the setPrimaryItem() method in the FragmentPagerAdapter to call a method that removes the SurfaceView from the hierarchy (using removeView() on its LinearLayout container) when the video player Fragment ceases to be displayed, and then reinstates the SurfaceView when it's active again. There's still a bit of a blink when this happens, unfortunately, so if anyone has additional thoughts, I'd be grateful!
From the Android Developers Blog
This widget[SurfaceView] works by creating a new window placed behind your application’s window. It then punches a hole through your application’s window to reveal the new window.
Because a SurfaceView’s content does not live in the application’s window, it cannot be transformed (moved, scaled, rotated) efficiently. This makes it difficult to use a SurfaceView inside a ListView or a ScrollView.
The Solution is to use a TextureView if you're building for 4.0 or above. If youre interested in using a TextureView to display video this thread might be helpful
Related
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 using a ViewPager with four fragments. In every fragment i'm using custom made components that that inheriths from SurfaceView.
If i'm too fast to swipe or change tab when the activity is brought up front the gui freezes. Events etc are still triggered, so the gui-thread is not locked.
I can also see "ghosts" of components sometimes in the view of the intialized components when I swipe.
Does anyone have any idea of what is causing this?
I'm experimenting with ways to do classical mobile game paradigm: a selector of levels, followed by a game screen.
I fully understand that there are plenty of ways to do that, but i was wondering about what goes wrong when i try this particular one (for learning purposes):
I have an activity, which holds references to my own GLSurfaceView child. On the activity start it loads a default 'level' and perfectly plays it. I can see Render thread started.
I implemented an OptionsMenu item, which after activation inflates a GridView with proper adapter, which allows user to select a level; and sets this inflated Layout to Activity by using setContentView. This is when GLThread dies.
Now i also implemented the OnClick's of that menu so that after click it loads a level in the game engine (works fine, btw) and brings back GLSurfaceView by using setContentView with saved (in 1.) reference.
And that's how i get a blank screen. Everything works fine, menu still works, i can go back to level selector, but in debugger i can see Render Thread doesn't exist.
Please, could someone explain to me what exactly goes wrong here? I'm totally not sure about this OpenGL intrinsic.
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.
In a nutshell, I use regular views for all my application except for on that uses a GLSurfaceView.
the UI flow works well. I can navigate form one to the over
except whith the GLSurfaceView
when I open the first time the GLSurfaceView everything works fine, but when I switch to another view and come back (pause menu) my view is completly black...
I tried several things and the closest I got from fixing it is to recreate the GLSurfaceView completly (but that takes too much time ...)
What I want is be able to do this:
if(glView){
activity.setContentView(mView);
}else{
activity.setContentView(id);
}
(id being an xml layout)
can somebody tell me what I'm doing wrong or point me to a tutorial that explain how to swap form GLViews to regular views
thanks a lot
Jason
after playing around a bit I figured out that when I load a new view my ogl context gets destroyed.
since I couldn't see a way to prevent this and that regenerating all the texture took too much time I witch everything to ogl