Android Manifest string resource for parentActivityName? - android

On phones I need Activity C's parent to be Activity B and on tablets I need Activity C's parent to be Activity A. However, I can't set a string resource for the parentActivityName. Is there a way to do it via XML? Thanks!
<activity
android:name="com.example.app.ActivityC"
<!-- #string resource not accepted here -->
android:parentActivityName="com.example.app.ActivityB">
</activity>

As far as I know, there's no way. You might do it with your activity itself though. Create a new activity to handle starts on different devices
public class ActivityD {
protected void onCreate (Bundle savedInstanceState) {
boolean isTablet = false || true; // get configuration
Class<?> activity = isTablet ? ActivityB.class : ActivityA.class;
startActivity(new Intent(this, activity));
finish();
}
}
and define it as parent instead
<activity
android:name="com.example.app.ActivityC"
android:parentActivityName="com.example.app.ActivityD">
</activity>
It's not completely XML, but the best I could think about.

Related

Pressing back button from one activity refreshes previous activity in stack

On pressing back button from child activity parent activity displays for a second and refreshes itself.
In child activity I have this code in java file
#Override
public void onBackPressed()
{
Intent moveback =
new Intent(ClassActivityEdit.this, ClassActivity.class);
startActivity(moveback);
finish();
}
ClassActivityEdit is child class. In manifest file code is as follows
<activity android:name=".ClassActivity"
android:label="Class Activity">
<intent-filter>
<action android:name="com.teamtreehouse.oslist.ClassActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ClassActivityEdit"
android:label="Class Activity"
android:noHistory="true">
<intent-filter>
<action android:name="com.teamtreehouse.oslist.ClassActivityEdit" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
On back button I just want the ClassActivity layout to be displayed without it being refreshed.
Edit:
ClassActivityEdit doesnt extend ClassActivity. Its just that some button press in ClassActivity will result in opening ClassActivityEdit.
Edit2
the below code in ClassActivity starts ClassActivityEdit
public void editListener(View v) {
Intent addNewClass =
new Intent(ClassActivity.this, ClassActivityEdit.class);
RelativeLayout buttonTableRow = (RelativeLayout) v.getParent();
TextView getCourseID = (TextView) buttonTableRow.findViewById(R.id.courseNumberActivity);
String courseIDString = getCourseID.getText().toString();
Bundle bundle = new Bundle();
//Add your data to bundle
bundle.putString("CourseIDString", courseIDString);
addNewClass.putExtras(bundle);
startActivity(addNewClass);
}
Edit 3: I also have a Landing (MAIN) activity which flashes for a second. On pressing back button from ClassActivityEdit activity Landing activity flashes again and then the ClassActivity activity loads. Finding it a bit tricky to solve.
public class LoadingPage extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_page);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent mainIntent = new Intent(LoadingPage.this, ClassActivity.class);
startActivity(mainIntent);
}
}, 1000);
}
}
Your Problem is so much strange ! just by not overriding OnBackPressed you will get the result you want.
I guess the problem is in your manifest.
android:noHistory="true"
It doesn't let the activity to stay in history stack, try removing it. also try this:
android:launchMode="singleInstance"
By doing this, the activity wont become created again.
The problem is with your override to the back press (which does not need to be overridden) and is likely a symptom of with what your activity does when focus returns to it.
Firstly if you don't override onBackPress the previous activity will load (that's the default behaviour because of the backstack) so you don't need to manually call it with a new intent and tell manually tell it to go to the previous activity.
When your parent activity (ClassActivity) then starts again it will go through the normal lifecycle - it will get resumed and all saved instance states get restored. Since you haven't posted it you need to make sure onResume and onRestart are not doing anything in your parent activity such as loading or setting data.
If you do keep the onBackPress you wrote then it will create a new instance and onCreate will always be called, unless it is singleInstance flagged, in which case onNewIntent will be called, but neither of these things seem to be what you want.
In response to your Edit 3 you need to make sure that LoadingPage has android:noHistory="true" so that it is not available to the backstack and then finish it explicitly to clean it up when you start the main class
That is a simple as calling finish when starting your intent
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent mainIntent = new Intent(LoadingPage.this, ClassActivity.class);
startActivity(mainIntent);
finish(); //end the wrapping activity (LoadingPage)
}
}, 1000);
The last thing you should be aware of is the difference between up and back navigation. In case you are navigating back via the home/up button you should also tell the manifest that these two activities are related. In the manifest entry for ClassActivityEdit you should add android:parentActivityName="com.teamtreehouse.oslist.ClassActivity"
Just let the back button do what it normally does. Don't override it and don't start a new activity. The parent activity is below the child activity in the stack, so it should appear when the child activity finishes.
By default, Android will retain activities in a stack, so when you go from Activity A to Activity B, Activity A will be brought back when you finish Activity B unless you do some other stuff like mess with the launchMode, finish A on returning from B, etc.
From what can be seen in your code, your problem should be solved by not overriding onBackPressed() in your child activity. Also, you should remove your <intent-filter> block for the child activity in the manifest.
I recommend reading up on managing the activity lifecycle and tasks and back stack.
First of all there is no need of overriding onBackPressed(). As Doug mentioned the parent activity is below the child activity in the stack , so it would be visible just after the child activity finishes on back pressed.
There is a suggestion for you as the ActionBarActivity is deprecated so it would be better to extend the class AppCompatActivity in your activity class.
I have tried to replicate the issue but failed. So I have created a classes.
LandingPage.java
public class LandingPage extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_page);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(LandingPage.this, ClassActivity.class));
}
}, 1000);
}
}
ClassActivity.java
public class ClassActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.class_activity);
//Do whatever you want to do
}
public void editListener(View v)
{
Intent addNewClass = new Intent(ClassActivity.this,ClassActivityEdit.class);
RelativeLayout buttonTableRow = (RelativeLayout) v.getParent();
EditText getCourseID = (EditText) buttonTableRow.findViewById(R.id.courseNumberActivity);
String courseIDString = getCourseID.getText().toString();
addNewClass.putExtra("CourseIDString", courseIDString);
startActivity(addNewClass);
}
}
ChildActivityEdit.java
public class ClassActivityEdit extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.class_activity_edit);
String course_no = getIntent().getStringExtra("CourseIDString");
Toast.makeText(ClassActivityEdit.this,course_no,Toast.LENGTH_SHORT).show();
//Do whatever you want to do
}
}
Your main problem is that you have overridden onBackPressed in the child activity.
What I understand from your code is-
ClassActivity --> Parent Activity
ClassActivityEdit --> Child Activity
In manifest, android:noHistory="true" is specified for child i.e. ClassActivityEdit activity. So it won't be stored in stack. Nothing is mentioned for parent.
In onBackPressed of your child activity you are again creating new Parent activity even though it is already present in the stack. It's just below your child activity.
Even if you don't override onBackPressed, parent activity will still load. In your case, it is creating many instances of parent activity.
One more thing, unless you want your activity to handle or respond to specific actions, you don't need to add intent filters for activity in manifest. According to documentation,
"Intent filter Specifies the types of intents that an activity, service, or broadcast receiver can respond to. An intent filter declares the capabilities of its parent component — what an activity or service can do and what types of broadcasts a receiver can handle. It opens the component to receiving intents of the advertised type, while filtering out those that are not meaningful for the component."
you can using Intent easily move for back Activity. but your back activity refresh all date write in onresum() method then it esyly refresh data
In child activity I have this code in java file
#Override
public void onBackPressed()
{
Intent moveback =
new Intent(ClassActivityEdit.this, ClassActivity.class);
startActivity(moveback);
finish();
}
When you start child activity from parent activity your parent activity move to stack and child activity display in onBackPressed event on child activity you create a new instance of parent activity and in activity life cycle onCreate event called first and views inside it creating by default values, so when you click on back button in child activity without creating a new instance of parent activity android display parent activity with previous savedInstanceState then onResume event called.
for more details see Activity Life Cycle
Change your onBackPressed() in child activity to this or you can also remove the onBackPressed() from child activity
#Override
public void onBackPressed(){
super.onBackPressed(); // call super back pressed method
}
Make sure that you don't finish() parent activity when you move from parent activity to child activity
Try using FLAG_ACTIVITY_REORDER_TO_FRONT when starting the ClassActivity intent.
you said,
On pressing back button from ClassActivityEdit activity Landing activity flashes again and then the ClassActivity activity loads.
you might be calling finish() somewhere in the ClassActivity which will cause the activity to be removed from the stack. If so, remove it.
#Override
public void onBackPressed(){
finish();
super.onBackPressed();
}
this will solve your issue.
finish() will destroy your child activity and super.onBackPressed() will redirect you to parent activity.
You need to replace
startActivity(addNewClass);
with
startActivityForResult(addNewClass,101);
and then, in OnActivityResult you can refresh your data.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==101){
if(resultCode==RESULT_CANCELED){
//refresh data accordingly
}else if(resultCode==RESULT_OK){
//refresh data accordingly
}
}
}

why the "up" button moves me to the main activity and not to the parent activity

I have an application with three activities.
MainActivity which looks like that:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button b = new Button(this);
b.setText("click me to go to child activity");
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, ChildActivity.class));
}
});
setContentView(b);
}
}
ChildActivity which looks like that:
public class ChildActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TextView(this) {{
setText("I'm the child activity");
}});
}
}
And OtherActivity which looks like that:
public class OtherActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TextView(this) {{
setText("I'm other activity");
}});
}
}
In the manifest I have such declaration:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity android:name="pl.psobolewski.test.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="pl.psobolewski.test.ChildActivity" />
<activity android:name="pl.psobolewski.test.OtherActivity" />
</application>
Now when I start the application, it starts with MainActivity, from there I can go to ChildActivity, but there is no way to go to OtherActivity.
Then in the manifest I change this line:
<activity android:name="pl.psobolewski.test.ChildActivity" />
to:
<activity android:name="pl.psobolewski.test.ChildActivity" android:parentActivityName="pl.psobolewski.test.OtherActivity" />
Now I start again this application on my phone, which has Android API 16. It starts with MainActivity, there I can press the button and move to ChildActivity. Now the ChildActivity looks a little bit different than before: the logo on ActionBar has a little arrow-like icon (documentation calls it "a left-facing caret") which means it can be used to move up. But when I press it I don't go to OtherActivity - even though it is declared as the parent of ChildActivity - but to the MainActivity.
I find it contrary with the Android documentation which says:
http://developer.android.com/guide/topics/manifest/activity-element.html
"android:parentActivityName
The system reads this attribute to determine which activity should be started when the use presses the Up button in the action bar. The system can also use this information to synthesize a back stack of activities with TaskStackBuilder."
I also thought that adding android:parentActivityName attribute without calling setDisplayHomeAsUpEnabled would not turn the application logo into the up button - the documentation at http://developer.android.com/training/implementing-navigation/ancestral.html suggests so.
My question is: why the "up" button moves me to the MainActivity and not to the OtherActivity?
The Action Bar up navigation handler has been implemented in such a way that if the parent of current activity has no parent, then an Intent is created with ACTION_MAIN & CATEGORY_LAUNCHER to start the activity. This results in MainActivity being launched.
Have a look at definition of getParentActivityIntent() in Activity.java
To overcome this, in your ChildActivity.java override below 2 methods of Activity.
#Override
public boolean shouldUpRecreateTask(Intent intent) {
return true; // This creates a new task stack
}
#Override
public Intent getParentActivityIntent() {
Intent intent = new Intent(this, OtherActivity.class);
return intent;
}
If you don't want to override getParentActivityIntent, then you need to define a parent activity for OtherActivity in AndroidManifest.xml file, to overcome the earlier mentioned reason.
If you don't override shouldUpRecreateTask, since OtherActivity does not appear in history stack, it will remove all activities until the root activity of the task is reached, resulting in 'in-app home' behavior.

Android Second Activity Error

So My application Consists of first activity which shows some text, and on action bar there is a File menu, in which I put My location option.
I call another activity in mainActivity with onOptionItemSelected as follows:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_photo:
openPhoto();
return true;
case R.id.action_video:
openVideo();
return true;
case R.id.action_map:
Intent intent = new Intent(this, GPSTracker.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
in manifest i declare the second activity as follows:
<activity
android:name="com.example.locateme.GPSTracker"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
and in GPSTracker.java i write this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gpstracker);
}
also there is my code for finding the location.
I am running the app, bu when i press My Location option the app crashes.
Here are the logcat errors after removing intent for GPS activity
The full code of the app is here, in case there may be something i missed.
Do i call the second activity in the wrong way?
java.lang.InstantiationException: can't instantiate class com.example.locateme.GPSTracker; no empty constructor
is quite obvious error.
Somewhere in your GPSTracker class you have a definition like
public GPSTracker(SomeClass referenceName) {
//...
}
This block of code should be removed or replaced with constructor without params. The first option if prefered: use onCreate as your constructor.
First, remove the intent-filter for Your GPS Activity in Your Manifest.xml, here You had set both activities (Main and GPS) as a launcher. Set only one Activity as LAUNCHER and MAIN. And then it will be good to see LogCat Output to know why it crashs

Organize FragmentActivity navigation stack

The application(target API level must be 7th) has FragmentActivity which analyzes at onCreate the fragment key passed as an extra.
Now what is needed is to reorder to front the activity that is already created with the given fragment key.
Let's say the FragmentActivity with different fragment keys are FA1, FA2 and FA3 - each is the same activity Class instance with different fragments.
Now in the stack FA1 > FA2 > FA3 i want to use the intent rather than the back button to get to FA2, by default that gives:
FA1 > FA2 > FA3 > new FA2.
I'd like to get either FA1 > FA3 > FA2 as the FA3 might have some pending operations, FA1 > FA2 is not as good but definitely better than default.
If there were several activities I'd use the FLAG_ACTIVITY_REORDER_TO_FRONT flag for intents, but that does not work for this case.
FA1, FA2, FA3, etc. are all the instances of the same class MyFA, that's why I'm not able to use the intent flag and the FragmentManager seems to be out of help until there's a standard global fragments cache.
Milestone (currently working and to be improved) solution One thing I've learned today is activity-alias which allowed to make several aliases for the same activity with the different Intent extras used as id's. Now with the REORDER_TO_FRONT flag it works as I wanted.
Solution feedback The solution has no low-level operations, I like a lot more than digging at the tasks or back-stacks. Now the drawback is that each of such activities needs a separate alias with the hardcoded path, I don't really like it.
Requirements (bounty is here) Whoever comes with a decent optimization takes 150 300 cookies. Not bad ? Any other solid solution is also highly appreciated.
Currently I have like 10 aliases at application manifest, e.g.
<activity
android:name=".activity.FragmentActivity"
android:configChanges="orientation"
android:screenOrientation="portrait" >
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="com.company.name.intent.FragmentActivity" />
</intent-filter>
</activity>
<activity-alias
android:name="com.company.name.intent.FragmentActivity.FragmentedOne"
android:targetActivity=".activity.FragmentActivity" >
<intent-filter>
<action android:name="com.company.name.intent.FragmentActivity.FragmentedOne" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="fragment_key_extra"
android:value="FragmentOne" />
</activity-alias>
<activity-alias
android:name="com.company.name.intent.FragmentActivity.FragmentedTwo"
android:targetActivity=".activity.FragmentActivity" >
<intent-filter>
<action android:name="com.company.name.intent.FragmentActivity.FragmentedTwo" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="fragment_key_extra"
android:value="FragmentTwo" />
</activity-alias>
And then the activities are reordered with
Intent intent = new Intent(
"com.company.name.intent.FragmentActivity.FragmentedOne");
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
This answer is worth 300 cookies :-D Mmmmm
Extend Application so we can create our own back stack list with a global scope.
import android.app.Application;
import android.content.Intent;
class MyApp extends Application {
//This is our very own back stack.
private ArrayList<Intent> backStack = new ArrayList<Intent>();
public void reorderBackStack(){
//Do what you want to the order of your backstack
//You can read the value of your intent extras from here.
}
public void addIntent(Intent i){ // this gets called from our activities onCreate
backStack.add(i);
}
public void goBack(){
if(backStack.size() >= 2){ // can go back
backStack.remove(backStack.size() - 1); // drop the last item in stack if you want. This is how Android does it. (no forward capability)
this.startActivity(backStack.get(backStack.size() - 1));
}
}
}
Add a reference to our custom back stack in our activity.
public class MainActivity extends Activity {
MyApp myapp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myapp = ((MyApp)getApplicationContext());
myapp.addIntent(this.getIntent()); //add the intent for this instance to backStack.
myapp.reorderBackStack(); // call this anytime we need to reorder the back stack.
}
#Override
public void onNewIntent(Intent newIntent){
this.setIntent(newIntent);
myapp.addIntent(this.getIntent());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
// We won't be using the back stack we will be using our own list of intents as a back stack so we need to override the back button.
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
myapp.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Override the back button so we can use our own back stack instead of Android's.
Edit
I put together a proof of concept.
Pros
No Aliases
Completely dynamic and reusable
Low level control
Easy to use (Extend CustomBackStackActivity instead of FragmentActivity or Activity)
Cons
Not an out-of-the-box solution. Will require tweaking and debugging.
The .apk is Here on my google drive.
The complete project folder is here.
Zipped downloadable project folder is here.
Please don't complain about my code. I know I used strings where I should have used constants and I duplicated code instead of seperating it and my spacing isn't perfect and I used excessive loops and objects. I haven't sorted out the savedInstanceState. Again, this is just a proof of concept. It works and I thought it might help someone.
You can look into using the functionality provided by the FragmentManager. It has functions such as popBackStack.
You can also use FragmentTransaction to add fragments to the backstack. You can use addToBackStack to accomplish this.
So with these two classes you should be able to reorder your fragments in the backstack as necessary.
Here is the solution:
1. In your FragmentActivity implement a Interface for the callback from Fragment to Activity.
2. When you start any Fragment put it in back stack with the argument or tag (addToBackStack(String arg0))with the help of which you can pop up with that tag.
3. When you need to reorder the fragments then call the method of the interface which you implemented with proper arguments as per requirement and then use popBackStack(String arg1, String arg2) to get the fragment with the tag you put it in the backstack.
Based on your idea of using activity-alias to solve this issue, I wrote a Historian class that will do the following:
Scan the Activity list in your package for aliases to your specific Activity.
Set up a lookup table that maps each alias to an Intent.
Provide a startActivity() and activityDestroyed() methods that will do some bookkeeping so the lookup table can be used to dynamically assign an alias to a running Activity based on the Intent.
Here's an example on how to use it:
in AndroidManifest.xml
<activity android:name=".MyFragmentActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity-alias android:name=".Alias0" android:targetActivity=".MyFragmentActivity" />
<activity-alias android:name=".Alias1" android:targetActivity=".MyFragmentActivity" />
<activity-alias android:name=".Alias2" android:targetActivity=".MyFragmentActivity" />
<activity-alias android:name=".Alias3" android:targetActivity=".MyFragmentActivity" />
<activity-alias android:name=".Alias4" android:targetActivity=".MyFragmentActivity" />
within your Activity class
public class MyFragmentActivity extends FragmentActivity
implements Historian.Host {
private Historian<MyFragmentActivity> mHistorian;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHistorian = new Historian<MyFragmentActivity>(this);
// ...
}
#Override
protected void onDestroy() {
super.onDestroy();
mHistorian.activityDestroyed(this);
}
#Override
public boolean matchIntent(Intent intent0, Intent intent1) {
if (intent0 == null || intent1 == null) return false;
final String title0 = intent0.getStringExtra("title");
final String title1 = intent1.getStringExtra("title");
return title0.equals(title1);
}
// ...
}
Instead of starting a new instance of your activity like this:
Intent intent = new Intent(this, MyFragmentActivity.class);
intent.putExtra("title", newActivityTitle);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
You do this:
Intent intent = new Intent(this, MyFragmentActivity.class);
intent.putExtra("title", newActivityTitle);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mHistorian.startActivity(this, intent);
So you still need to add a few activity-alias into your manifest manually (to be used as a pool) and implement the matchIntent() method in your Activity (to help detect whether two Intents are equal to you) but the rest is handled dynamically by the Historian class.
I haven't tested the code exhaustively, but it seems to work fine on some simple tests that I did. The idea is actually very similar to my answer on the other question (just need to use FLAG_ACTIVITY_CLEAR_TOP instead of FLAG_ACTIVITY_REORDER_TO_FRONT there) but using the activity-alias instead of the inner child classes make it much cleaner :)
I have answered something similar, but the solution is not the best as FA1 > FA2 > FA3 will take you to FA1 > FA2 rather than FA1 > FA3 > FA2.
My answer was for question : How to tag Activity
Anyway, I edited the code a bit to use a "tag" which will be a string, but I think you can use the main solutions that uses integer indices. In summary, this should allow you to fallBackToActivity with a certain TAG. I am not sure how will each Activity decide what will its tag be, but again, in my previous answer it was a simple matter of an incremental integer.
package sherif.android.stack.overflow;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class SuperActivity extends FragmentActivity {
private static String EXTRA_INDEX = "SUPER_INDEX";
private static int RESULT_FALLBACK = 0x123456;
private String tag; //this is your tag
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getIntent()!=null) {
tag = getIntent().getStringExtra(EXTRA_INDEX, "default_tag");
}
}
protected final String getIndex() {
return tag;
}
protected final void fallBackToActivity(String tag) {
Intent intent = new Intent();
intent.putExtra(EXTRA_INDEX, tag);
setResult(RESULT_FALLBACK, intent);
finish();
}
//#Override
//public void startActivityForResult(Intent intent, int requestCode) {
// intent.putExtra(EXTRA_INDEX, getIndex());
// super.startActivityForResult(intent, requestCode);
//}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_FALLBACK) {
if(!data.getStringExtra(EXTRA_INDEX, "default_tag").equals(getIndex())) {
setResult(RESULT_FALLBACK, data);
finish();
}
}
}
}

Android: dynamically choosing a launch activity doesn't always work

I've read a few articles here (and other places) that describe how to dynamically choose which activity to show when launching an app. Below is my code:
AndroidManifest.xml
<activity android:name=".StartupActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
StartupActivity.java
public class StartupActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent;
if (RandomClass.getSomeStaticBoolean())
{
intent = new Intent(this, ActivityOften.class);
}
else
{
intent = new Intent(this, ActivityRare.class);
}
startActivity(intent);
finish();
}
}
Both ActivityOften and ActivityRare are declared in the manifest (without the launcher category of course) and extend ListActivity and Activity respectively. 99% of the time the 1st activity to get shown is ActivityOften based on RandomClass.getSomeStaticBoolean().
So launching my app from the icon for the 1st time I break inside the StartupActivity.onCreate. The choice is properly made. But then any subsequent attempts to launch the app (from a shortcut or the apps menu) show the ActivityOften again. No further breaks occur inside the StartupActivity class. Despite the fact that I know that RandomClass.getSomeStaticBoolean() has changed value and that ActivityRare should appear, the 1st activity keeps popping up.
Any ideas?
Thanks, Merci, Gracias, Danke, Grazie!
Sean
It is happening because your application activity is loaded from the history stack.
Set android:noHistory=true in the manifest for both ActivityOften and ActivityRare. That should solve your problem.
Just as a suggestion, you could just have one activity instead of three by choosing the content View dynamically. i.e.
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (RandomClass.getSomeStaticBoolean())
{
setContentView(R.layout.Often);
// Set up often ....
}
else
{
setContentView(R.layout.Rare);
// Set up rare ....
}
}
This would mean that you would have to write setup code both views in on activity, which can get a bit messy.

Categories

Resources