android switch between two canvas - android

I have no idea why my app isnt liking the following and would be grateful for any help.
I have a main activity that sets the following onCreate
setContentView(new Splash(this));
Splash being a surfaceview with the following in its constructor
this.setBackgroundDrawable(getResources().getDrawable(R.drawable.splash));
Then I have a thread in Splash that waits 3seconds or 3000 miliseconds.
Then calls the second surfaceview in the main activity
setContentView(new GameCanvas(this));
Everything works fine until it calls the seoncds setContentView, the screen doesnt change, it sticks on the splash screen.
any idea why?
Here is my thread
new Thread(){
public void run(){
try{
Log.e("here", "sleeping");
sleep(3000);
//main being the main activity class
main.killSplash();
//Log.e("here", "KILL SPLASH");
}catch(Exception e){
//
}
}
}.start();
p.s i have a feeling it is because I'm calling the switch canvas method from inside a thread

Activities are designed to be different "screens" in your application, and thus you should separate your splash screen's activity from your main game activity. Once an activity has drawn, I don't believe changing the contentView will trigger a redraw. I believe you are only supposed to call setContentView once- from the onCreate method.
Also note that each activity is automatically run in a new thread.
As an aside, you might want to follow some of the Android Developer tutorials. setContentView is primarily for establishing the layout and contents of your activity, usually defined in an XML resource, whereas you seem to be treating it as a means for switching view instances.

Related

Android Screen Rotation firing multiple AsyncTask Threads

From the Activity, I am creating a Handler to fire off my AsyncTask every 45 seconds in order to refresh the content of my ListView's DataAdapter. The AsyncTask works great and keeps the user informed on the progress through ProgressUpdates and Toast messages.
Since the thread's doInBackground is fire and forget and not re-usable, I am having to create a new instance of the AsyncTask from my Hander that is firing off every 45 seconds. The problem is when the screen is rotated and and then I get concurrent messages going off because the Hander was recreated and created a new instance of the AsyncTask, so the friendly user progress through ProgressUpdates and Toast messages is overwhelming and makes utilizing the ListView difficult.
And please don't suggest this as a solution: android:screenOrientation="portrait" is not an option.
For something that has to run so frequently, should I just be using a custom Thread and not the AsyncTask class? ToDo: Not shown, I have to update the Adapter later from the Sensor's onSensorChanged event to update bearings on for each location in the ListView, I was going to run that on a separate AsyncTask class because I don't need to notify the user everytime the device bearing has changed.
Since the AsyncThread cannot be reused, am I doing this all wrong? In short, what is the best way to have the Activity refresh the ListView and keeping off the UI thread when doing so?
The problem is when the screen is rotated and and then I get concurrent messages going off because the Hander was recreated and created a new instance of the AsyncTask.
Reason quoting from API Activity - Configuration Changes:
Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate.
So every object has a activity-scope life cycle (i.e. Handler, AsyncTask and etc. defined within your activity class) is suffered by this activity recreation. However, you can bypass this activity recreation, as stated in the later paragraph of Activity - Configuration Changes section:
In some special cases, you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with the android:configChanges attribute in its manifest. For any types of configuration changes you say that you handle there, you will receive a call to your current activity's onConfigurationChanged(Configuration) method instead of being restarted. If a configuration change involves any that you do not handle, however, the activity will still be restarted and onConfigurationChanged(Configuration) will not be called.
Not related to topic, but as a good practice, you should always destroy used object (Handler, AsyncTask and etc.) properly when activity is about to finish (i.e. in onDestroy() method).
For something that has to run so frequently, should I just be using a custom Thread and not the AsyncTask class?
AsyncTask is pretty handy but not suit for periodic task, I would use ScheduledExecutorService or TimerTask in this case, check out my answer here for sample code.
Can you please post a bit of your code ? It may be useful to understand where your problem is.
As york has pointed it out, you should probably use TimerTask. It seems that it suit better with what you are trying to do.
If it is the creation of a new instance of the Handler that create the probleme you can try something like this :
private Handler mHandler = null;
#Override
public void onCreate(Bundle _savedInstanceState) {
super.onCreate(_savedInstanceState);
setContentView(R.layout.my_layout);
if (mHandler == null) {
// TODO create your handler here
}
}
EDIT :
You can test _savedInstanceState == null too.
_savedInstanceState is used to save the state of the activity so turning the phone shouldn't be a problem anymore.
However, if you leave the activity and then go back to it, it will create a new handler (except if you instanciate it as a static variable).

What does "setContentView" really do?

In my main activity, I would like to have it set up, so that I first get met by a contentView just showing a background and some text. After X seconds, I want to change to my other view (GLSurfaceView).
This is obviously something I am doing completely wrong.
This is how I've imagined it could've been done (it's all in the onCreate method):
setContentView(R.layout.main);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
viewer = new Viewer(this);
setContentView(viewer);
Where layout Main is what I want to show at the beginning and Viewer is my GLSurfaceView class.
What happens is that it just goes black for 10 seconds and then it starts loading the objects I've got that is shown through OpenGLES.
There's nothing wrong with the layout Main, since it works if I just erase the lines under where the Thread.sleep takes action. Though, nothing happens before the Thread.sleep is over...
With that said, my questions are following:
Why is the contentView not changing until after Thread.sleep is done?
What would be an appropiate solution to what I want to achieve?
I'm assuming this in your onCreate() and thats why you are seeing nothing.
The way I would implement this is to start a thread using AsyncTask sleep in the doInBackground and in the onPostExecute set up the new view.
Don't make sleep the main thread(UI thread).Use a threads,AsynkTask or TimerTask for that type of works instead.
You're not sleeping the UI thread in the way you think you are.
The simplest thing for what you're looking to achieve is to separate the views into separate activities and let Android handle the transition between the views. It adds another file to your codebase, but it's fairly straightforward. Let's say your initial, plain view (R.layout.main) is for a SplashActivity activity, and your post-splash view goes into PostSplashActivity. Then you could do something like this:
public class SplashActivity extends Activity {
private static long DELAY = 10000; //milliseconds;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Handler().postDelayed(
new Runnable() {
#Override
public void run() {
Intent postSplash = new Intent(SplashActivity.this, PostSplashActivity.class);
SplashActivity.this.startActivity(postSplash);
SplashActivity.this.finish();
}
}, DELAY);
}
}
This will draw your R.layout.main layout, and then puts a startActivity call for your PostSplashActivity on the message queue and tells the queue to wait DELAY milliseconds to execute it.
It seems like you are making the main thread sleep. This may be why the code is running tell after.
It sounds like you want something like a splash screen. I like to think of these as separate to the following screen, so always use a separate activity rather than calling setContentView twice. You'd still need to sleep in a thread.
Just personal preference though...

How to change content view from a GLSurfaceView?

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.

How to launch a background activity from a widget?

I have an android widget which has a very simple function. The widget simply launches an activity when pressed, runs through the activity, pops a toast, and closes the activity.
The annoying thing is that when the widget is pressed on the home screen, the screen flickers as it opens and closes the activity. Is there any way to launch the activity from the background, to avoid this flicker? I'm kind of looking to do something similar to the ATK widget, which simply pops up a toast after closing all the background processes.
If it's possible to just run a single function in place of a PendingIntent, that would definitely work as well. Thanks!
I eventually did this by implementing a service instead of an activity. The service runs in the background and then stops itself once it has finished. The PendingIntent simply launches the service, using the getService() method of PendingIntent.
I know I'm very late, but I was having a similar problem and I didn't want to use a service.
If your activity is very quick, it is enough to modify your manifest and insert this into the activity your widget will be launching,
android:theme="#android:style/Theme.Translucent.NoTitleBar"
This way your activity will be transparent thus no flickering will be seen and, being it very quick it won't get in the way.
Please note that this may only be used if your activity is fast, otherwise it will result in a frozen effect.
I'm doing this kind of thing using Application class. You need to declare your own - e.g. MyApplication class (need to be declared in Android manifest) and during creation MyApplication just launch separate Thread:
public class MyApplication()
{
// only lazy initializations here!
public MyApplication()
{
super();
}
#Override
public void onCreate()
{
super.onCreate();
Log.d(TAG, "Starting MyApplication"+this.toString());
Thread myThread=new MyThread();
myThread.start();
}
}
So in the end you will have "background" application which doesn't contain any activities. Application will be alive while your thread is alive. From those thread you can start whatever you want - for instance popup window, toast or any activity - depending on what you want.

ViewFlipper - how to force it to show the first View?

when I add a ViewFlipper, the UI thread seems to wait for the onCreate() method in the activity to be finished. Then it shows the second view. Why does it happen?
My current code is:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
viewFlipper = (ViewFlipper) findViewById(R.id.ScreenSwitch);
viewFlipper.setInAnimation(AnimationUtils.makeInAnimation(this, true));
viewFlipper.setOutAnimation(AnimationUtils.makeOutAnimation(this, true));
//do the necessary loading, when the splash screen persists
doSomeLoading();
viewFlipper.showNext();
}
Actually, the doSomeLoading consists of a for loop counting to ten millions and doing nothing. Now it just waits for loop to be done and shows the second view.
I would really appreciate a solution without having to create a separate Thread, because it seems to be pointless, invalidate() doesn't help there.
Maybe with viewFlipper.showPrevious();?
EDIT
I don't have your full code but here is the idea :
When you do long loading or slow actions, most of the time, you can think AsynTask or background thread.
So you need to create a new inner class. Lets say AsyncLoader. You will implement the method doInBackground() of this class and put your doSomeLoading() in it.
Now, implement onPostExecute() and put your viewFlipper.showNext(); in it.
Then, in your onCreate() method, replace the doSomeLoading() by new AsyncLoader.execute();
This should be nice. I might have forgotten some stuff as it's not real code. Check this for more explanations.

Categories

Resources