I wrote this dynamic keyboard app to track frequencies in an online PowerBall-type game. I used a SurfaceView because I can do stuff in real-time that I can't do with Buttons. The app works great with one thread: onPause destroys the surface/thread and onResume creates the surface/thread again. I thought that it would be cool to add another keyboard in a Tabbed View fragment so the user can track the keno numbers as well. For example
Fragment1:
return new PowerBallPanel(getActivity(),15,3);
Fragment2:
return new PowerBallPanel(getActivity(),75,5);
I thought Fragments were very similar to individual apps but every time I add Fragment2 I get a Surface Locked Exception, even though it's not running yet.
I am confused.
Thanks.
Chris
The answer is to include the Thread class as a sub-class of the surfaceview class. Hope this helps someone else.
Related
I have inherited some code hence I don't have true freedom to change it. :(
I have a main activity, from which other activities (I will refer to these as sub activities from now on) are called. Whenever one of these completes, it calls finish and returns data to the main activity.
Each activity (including the main one) has a bar on the top that displays a custom view. The custom view contains a canvas which has a drawing that is dependant upon the state of the network.. i.e. wifi/mobile etc...
Since that 'state' data never changes, it's held within a singleton and the view gets data from the singleton to define what it draws. That is working with no issues, i.e. the data is always as I expect it.
When I first launch the MainActivity, as the network changes, the data changes and each call to 'invalidate' the view receives a system call to 'onDraw' as I would expect.
In each of the sub activities the same is again true.
Upon finishing a sub activity and returning to the mainActivity, calls to invalidate no longer cause a call to onDraw to occur.
I have looked at this for quite a while now and just cannot figure out what is going wrong.
In my constructor I have:
setWillNotDraw(false);
Whenever the data changes the following methods are called:
invalidate();
requestLayout();
Now, there's one more thing... upon returning to the activity at that immediate point, I refresh and this DOES draw correctly, i.e. invalidate does trigger an onDraw call... any subsequent network changes (which are propogated) fail to result in the onDraw call.
I'm wondering if this is to do with the view somehow being detached. I can see that 'onDetachedFromWindow' is called, however the trigger for this is the destruction of the subactivity, hence I don't see why that should affect the MainActivity but it's the only thing I can think of.
I'm hoping I've provided enough information for someone to help me...
Well, in the end my answer has very little to do with the question and I guess this is an example of how an issue can be solved by going back to absolute basics and checking for the obvious.
My activities all inherit from an abstract activity. Within that activity there is an instance of the view. The views in which I was having trouble were using that declaration as opposed to having their own instance, hence behaviour from one activity was then affecting another inadvertently.
So, if I'd been able to post up all the code, I'm sure someone else would have spotted this but, unfortunately I couldn't in this instance.
Still, whilst this posting doesn't provide a resolution that will help others, maybe it does say... step back and check the obvious first!
I have a MainActivity that extends SherlockActivityFragment. This activity holds some fragments and a menu. Each menu item leads to new SherlockActivities. One particular SherlockActivity when it is loaded contains a carousel, that moves extremely slow.
However, once the orientation changes this carousel performs perfectly. I know that the Activity is reloaded on orientation change. But I have no idea what could start this to begin with, or even where to start looking.
Has anyone come across any similar issues? What did you do to profile the issue and what was your fix?
If you can think of relevant parts of the code (eg onCreate etc) please ask and I'll post it. Each activity has about 150 - 200 LoC)
Edit:
Here is the intent that I am using to start the SherlockActivity in question:
Intent rankIntent = new Intent(context, RankActivity.class);
rankIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(rankIntent);
break;
I've read that on orientation change onDestory() is called followed by onCreate. This makes me think that maybe some resource is freed that wasn't initially available. But the flag in the intent is intended to clear the backstack and any resources with it.
I've also tested with using the finish() method just before loading the new activity with no improvements.
This seems like a far reach but I recently had a problem I'd say could be similar.
I learnt that Android doesn't handle scaling images particularly well - could it be that the images are scaled before you change the orientation and not scaled once you do?
Answering the 2nd part of your question: since my app doesn't perform any resource-needy logic operations and is based on its UI, what I did was comment out some of its elements one at a time to see if it helps; that's how I found out an ImageView that was scaled up in my case.
Right now I'm developing a game in Android (OpenGL ES 1.1) and I'm seeing that whenever I create a new SurfaceView (GLView) its thread is created. That's ok. The problem comes when I want to finish the Activity that holds the SurfaceView (and go back to the menu). It seems that the activities are not released because each GLThread is referencing it. This may finish with an OOM error.
Some MAT pictures:
The first picture: the MarkitActivity represents each single instance of the Activity that deals with SurfaceView.
The second picture: The list of all the activities in memory.
The Third Picture: What is holding the Activities from GC.
If any code is needed I will post it. Nevertheless I have already tried the following things:
->Weak reference of the Activity Context to the renderer and to the surfaceview.
->Application Context instead of Activity Context (in normal and weak mode).
->Trying to stop (in a hard way) the thread (interrupt) and waiting for join (Which the program does it, but the thread does not care, it is still there...)
->Trying without debugging, just in case in debugger mode the values changes (the MAT pictures are without debugger).
->Trying the Activity as singleInstance mode. Weird results and errors everywhere.
->onPause and onResume are correctly controlled for the view.
Any hint, idea, question or help will be really appreciated. Thanks in advance!
Carlos.
I had a similar problem with threads (but not using OpenGL), and end up solving it using a simple trick.
Before exting activity (in onPause() or onStop(), try nulling the thread like this:
myThread = null;
It seems that it makes the Thread GC collectable, and therefore you activity becomes also collectable.
It worked for me, as well as for some people with similar problems to whom I gave the same suggestion.
Regards.
I have finished the Layout exercise and wondering why they include the call to populateFields() in both onCreate and onResume.
According to Activity Lifecycle "onResume" will always be performed before the Activity is shown so why not just there?
I have real production code that populates fields and is only called in onResume and it works just fine.
I thought one reason would be that maybe onResume is called after the activity is shown, but a bit of googling digs this (mostly unrelated) thread:
http://groups.google.com/group/android-developers/browse_thread/thread/ddea4830bedf8c6c?pli=1
Quote: onResume() is thus the last thing that happens before the UI is shown
This is what Dianne Hackborn says so i guess we can trust her :)
Actually I have seen apps (in my app and also others), where fields were only populated in onCreate(), but not in onResume().
Lets call that app 'A'.
The effect was that when the user pressed the home button, went to a different app, and then returned to 'A', the screen stayed black, as 'A' was still in memory and thus the system did not bother to call onCreate(), but directly went into onResume().
So basically I'd say (and this seconds what #Torp wrote) populate the UI in onResume() and be done.
But then, this answer is slightly off-topic as it does not answer your "why" question.
You don't populate in onResume because it will be called every time the activity is shown.
You generally want to create as few objects as possible, so you create them once and for all in onCreate, and then you can always check that they are still updated in onResume.
I'm working on a small game and I'm having problems changing my Activity's content view when a GLSurfaceView is set, let me describe how the app works:
The app has only one Activity, it starts with a static view: setContentView(R.layout.main);, when the user sends a certain input using menus a GLSurfaceView is instantiated and set via setContentView(gameSession); (where gameSession is the class extending GLSurfaceView). The GLSurfaceView class then sets the Renderer on which the real application logic runs.
What happens now is that the game logic (ran inside the Renderer) is the one responsible for knowing when the game is over and the view should change back to R.layout.main, the Renderer then calls a synchronized method on the GLSurfaceView, which notifies the Activity to be changed (again with setContentView(R.layout.main);).
And here comes the problem, as soon as setContentView(R.layout.main); is called everything hangs, the GLSurfaceView is still there (just not getting updated anymore). I fear that I'm experiencing a deadlock, with the Activity waiting for the Renderer to be done before removing it.
I've been thinking on a few solutions but all of them bring other issues:
Having the GLSurfaceView or the Activity see if the game is over by polling a flag on the Renderer, but there is no loop on those classes, (and the onDraw on the GLSurfaceView is never called)
Using the queueEvent() method, but the Renderer class doesn't have it (and using GLSurfaceView.queueEvent() doesn't work because the Runnable remains of the Renderer thread)
Implementing some kind of message thread only to check for game end, but that sounds like a waste of resources.
Has any one of you experienced a similar issue? What's the best way to change your Activity's content view from a GLSurfaceView to something else if the logic for when to swap is on the Renderer?
You shouldn't be calling setContentView() multiple times.
You could instead use multiple activities, calling finish() on your game activity when you're done with it to return to the static view Activity.