Changing the theme of a singleTop activity - android

So I've got an activity in my app that is currently marked as
android:launchMode="singleTop"
...and I currently have logic in both onCreate and onNewIntent to make sure that the screen is always showing the data delivered by the newest Intent that launched. And I'd like to be able to change between Holo.Light and Holo.Dark based on the data delivered by that Intent.
Calling setTheme doesn't work (see these two links):
Why getApplicationContext().setTheme() in a Activity does not work?
http://code.google.com/p/android/issues/detail?id=4394
That second link has a workaround that involves creating a second AndroidManifest.xml entry that has the other theme and points to an empty subclass of the activity in question. This works, but it breaks singleTop (since there can now be two instances of the activity on the stack).
I'm out of ideas. Anybody know if there's any way to do this aside from rolling my own custom ActionBar view for this activity?

You need to set the theme using the setTheme() method, but then to reload the activity.
I have a singleTask activity, and a code that runs on API<11, so I have this code to reload the activity:
public void reload() {
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
}
I'm pretty much just finishing the activity and calling it again. I disable any transition animation to make the reloading look instant.

Since you're referring to the Holo themes I assume you're working with API 11+.
API 11 added the method Activity#recreate(), which sends your current activity through the same teardown/recreate process that normally happens for config changes such as rotating the screen between landscape and portrait orientation. Your onCreate method will be called again on a new Activity instance, allowing you to set the theme on the Activity before the window is initialized as usual.
The Google Books apps uses this tactic to switch between light/dark themes for "night mode."

I'll post my solution that doesn't really add nothing new here but merge the various tips together.
After changing the Theme of the activity and optionally ( depends on what you are looking for ) of the application:
public void updateTheme( Activity a, int themeID ) {
a.getApplication().setTheme( themeID );
a.setTheme( themeID );
}
You then have to recreate the activity ( just as after a configuration change ).
For the OS 11> there is a API , instead for previous versions you have to force it finishing and restarting the activity just as Udinic pointed out.
public boolean isBeforeHoneycomb() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
}
public void reload() {
if( isBeforeHoneycomb() ) {
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
}else{
recreate();
}
}

Related

change activity theme elegantly

When it comes to Theme Changing activity, now my solution is: when i pressed a theme option then recreate the whole activity and setTheme before super.oncreate().So the user will encounter screen splash when switch between themes. How to make it elegantly?
From an App called 'TickTick',it turns out to be very smooth during switch:
Start recent activity without transition may seems a bit better.
public void reload() {
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
}

Trying to reload an Android activity from itself not working

My problem is: I can't figure out a way to restart my activity from itself. For example in a game, if you die, there's a menu with an option to retry, which restart the stage instantly. That's exactly the case.
As i have read from a lot of others answers on this matter, there are 2 main methods for reloading an activity:
1- finish();
startActivity(getIntent());
2- recreate();
The first method doesn't seem to work for me because it restart the activity, but leave the previous created one open on the back of my stack. Looks like the finish() statement is not doing its stuff. I have tried to put it in front, after, and all kind of ways, but it never closes the activity left behind.
On the other hand, the option number 2 cannot be called (as far as i know) from outside the UI thread, and if i do, the app crashes. I tried to call the recreate method using:
Activity.this.runOnUiThread(new Runnable() {
public void run() {
recreate();
}
});
But this approach gives me a very awful blinking on my screen. A black screen suddenly appears, and that doesn't seems right.
Try this:
Intent intent = getActivity().getIntent();
getActivity().finish();
startActivity(intent);
You should add FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK flags to the intent, such as:
Intent intent = getActivity().getIntent();
intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
getActivity().finish();
startActivity(intent);
This will force the system to remove the previous task from the stack.

Changing application theme programmatically(not inside main activity)

I need to set the application theme according to the user preference. This process happens in separate activity and it is not my main activity. I used this code to change the application theme:
getApplicationContext().setTheme(R.style.theme);
I know that it is perfectly work if I used it before
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
methods inside onCreate() method. But I have to do it in separate method. I tried to restart the application after that code as follows but it is not restart the application.
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
finish();
startActivity(intent);
Also I don't have any idea after restarting the application that it would work.
Any suggestion would be appreciated to solve the problem to change the application theme programmatically .
Try the following, it restarts the application after one second:
private void restartSelf() {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 1000, // one second
PendingIntent.getActivity(this, 0, getIntent(), PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT));
finish();
}
restartSelf() should be a member of your main activity. Alternatively, you may replace this with your application's context and and getIntent() with the main activity's Intent.
If I understood you correctly, can you try saving the user preference choice?
After the user chooses a theme, you can save the choice in persistent memory (such as shared preferences) and after the select, restart the application. In the onCreate of the main activity, you can access the user choice and set the theme there before super.onCreate( ) by accessing the persistent memory.

How to avoid black screen while invoking another activity in android?

i am invoking an activity using intent from main activity. But during the invocation few system dialog boxes are displayed because of which a black screen is displayed. How can i avoid such black screen.
Please check the flags you are setting in your intent.
If you have a finish(); or FLAG_ACTIVITY_CLEAR_TASK - a blank screen may show up on pre ICS devices as the current activity has been cleared before another activity is started.
Intent intent = new Intent(getApplicationContext(), Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
overridePendingTransition (0, 0);
If you want to finish the current activity during switching to other, call finish() after startActivity() method.
Checkout any long running or heavy tasks under the onCreate() method of new activity, it will block the activity onload untill the tasks has been finish.
Also check some transition properties ot other window flags these may also be the reasons in some cases.

Removing an activity from the history stack

My app shows a signup activity the first time the user runs the app, looks like:
ActivitySplashScreen (welcome to game, sign up for an account?)
ActivitySplashScreenSignUp (great, fill in this info)
ActivityGameMain (main game screen)
so the activities launch each other in exactly that order, when the user clicks through a button on each screen.
When the user goes from activity #2 to #3, is it possible to wipe #1 and #2 off the history stack completely? I'd like it so that if the user is at #3, and hits the back button, they just go to the homescreen, instead of back to the splash screen.
I think I can accomplish this with tasks (ie. start a new task on #3) but wanted to see if there was simpler method,
Thanks
You can achieve this by setting the android:noHistory attribute to "true" in the relevant <activity> entries in your AndroidManifest.xml file. For example:
<activity
android:name=".AnyActivity"
android:noHistory="true" />
You can use forwarding to remove the previous activity from the activity stack while launching the next one. There's an example of this in the APIDemos, but basically all you're doing is calling finish() immediately after calling startActivity().
Yes, have a look at Intent.FLAG_ACTIVITY_NO_HISTORY.
This is likely not the ideal way to do it. If someone has a better way, I will be looking forward to implementing it. Here's how I accomplished this specific task with pre-version-11 sdk.
in each class you want to go away when it's clear time, you need to do this:
... interesting code stuff ...
Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
startActivityForResult(i, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == R.string.unwind_stack_result_id) {
this.setResult(R.string.unwind_stack_result_id);
this.finish();
}
}
then the one that needs to set off the chain of pops from the stack needs to just call this when you want to initiate it:
NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();
Then the activities aren't on the stack!
Remember folks, that you can start an activity, and then begin cleaning up behind it, execution does not follow a single (the ui) thread.
One way that works pre API 11 is to start ActivityGameMain first, then in the onCreate of that Activity start your ActivitySplashScreen activity. The ActivityGameMain won't appear as you call startActivity too soon for the splash.
Then you can clear the stack when starting ActivityGameMain by setting these flags on the Intent:
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
You also must add this to ActivitySplashScreen:
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
So that pressing back on that activity doesn't go back to your ActivityGameMain.
I assume you don't want the splash screen to be gone back to either, to achieve this I suggest setting it to noHistory in your AndroidManifest.xml. Then put the goBackPressed code in your ActivitySplashScreenSignUp class instead.
However I have found a few ways to break this. Start another app from a notification while ActivitySplashScreenSignUp is shown and the back history is not reset.
The only real way around this is in API 11:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
I use this way.
Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
I know I'm late on this (it's been two years since the question was asked) but I accomplished this by intercepting the back button press. Rather than checking for specific activities, I just look at the count and if it's less than 3 it simply sends the app to the back (pausing the app and returning the user to whatever was running before launch). I check for less than three because I only have one intro screen. Also, I check the count because my app allows the user to navigate back to the home screen through the menu, so this allows them to back up through other screens like normal if there are activities other than the intro screen on the stack.
//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
#Override
public void onBackPressed() {
//Check the activity stack and see if it's more than two deep (initial screen and home screen)
//If it's more than two deep, then let the app proccess the press
ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
int activityCount = tasks.get(0).numActivities;
if (activityCount < 3)
{
moveTaskToBack(true);
}
else
{
super.onBackPressed();
}
}
In the manifest you can add:
android:noHistory="true"
<activity
android:name=".ActivityName"
android:noHistory="true" />
You can also call
finish()
immediately after calling startActivity(..)
Just set noHistory="true" in Manifest file.
It makes activity being removed from the backstack.
It is crazy that no one has mentioned this elegant solution. This should be the accepted answer.
SplashActivity -> AuthActivity -> DashActivity
if (!sessionManager.isLoggedIn()) {
Intent intent = new Intent(context, AuthActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
finish();
} else {
Intent intent = new Intent(context, DashActivity.class);
context.startActivity(intent);
finish();
}
The key here is to use intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); for the intermediary Activity. Once that middle link is broken, the DashActivity will the first and last in the stack.
android:noHistory="true" is a bad solution, as it causes problems when relying on the Activity as a callback e.g onActivityResult. This is the recommended solution and should be accepted.
It's too late but hope it helps. Most of the answers are not pointing into the right direction. There are two simple flags for such thing.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
From Android docs:
public static final int FLAG_ACTIVITY_CLEAR_TASK
Added in API level 11
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the
activity to be cleared before the activity is started. That is, the
activity becomes the new root of an otherwise empty task, and any old
activities are finished. This can only be used in conjunction with
FLAG_ACTIVITY_NEW_TASK.
Just call this.finish() before startActivity(intent) like this-
Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
this.finish();
startActivity(intent);
Removing a activity from a History is done By setting the flag before the activity You Don't want
A->B->C->D
Suppose A,B,C and D are 4 Activities if you want to clear B and C then
set flag
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
In the activity A and B
Here is the code bit
Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
super.finishAndRemoveTask();
}
else {
super.finish();
}
Here I have listed few ways to accomplish this task:
Go to the manifest.xml- and put android:noHistory="true", to remove the activity from the stack.
While switching from present activity to some other activity, in intent set flag as (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK). It is demonstrated in the example below.
Intent intent = new Intent(CurrentActivity.this, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent);here
Note :Putting the intent flags can cause blank screen for sometime (while switching activity).
Try this:
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)
it is API Level 1, check the link.

Categories

Resources