Is there a way to dynamically change the starting activity in Android based upon a conditionally? What I attempted to do (that didn't work) was the following:
remove the LAUNCHER category as defined in my AndroidManifest.xml
create a custom Application class that the app uses
override the onCreate method of my Application class to define some code like the following:
.
if (condition) {
startActivity(new Intent(this, MenuActivity.class));
} else {
startActivity(new Intent(this, LoginActivity.class));
}
Why not have an initial Activity with no UI that checks the condition in its onCreate, then launches the next Activity, then calls finish() on itself? I've never called finish() from within onCreate() though, so I'm not sure if this will work.
EDIT
Seems to work fine. Here's some code to make it clearer.
Initial Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent;
if (condition) {
intent = new Intent(this, ClassA.class);
} else {
intent = new Intent(this, ClassB.class);
}
startActivity(intent);
finish();
// note we never called setContentView()
}
Other Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
Here's what I personally did for one of my small mobile projects. Instead of creating a separate, screen-less Activity where the condition is and which launches the corresponding screen, I put the condition in one Activity and did a dynamic setContentView(), as in:
if (!userIsLoggedIn) {
setContentView(R.layout.signup);
} else {
setContentView(R.layout.homescreen);
}
Two important notes to this approach:
1: Instead of writing that in onCreate(), you want to put the decision-making inside onResume() precisely because the latter is always called whenever the screen needs to be displayed in front. You can see that from the Android activity life cycle. So if, for example, the user just downloaded my app and launched it for the first time, because no user is logged in, she will be led to the signup page. When she's done signing up and for some reason presses the HOME button (not BACK, which exits the app altogether!) and then resumes the app, the layout that she will see is already the home screen's. If I put the conditional inside onCreate(), what would have been displayed is the sign up screen because according to the life cycle, it doesn't go back to onCreate() when bringing back an app to the front.
2: This solution is ideal only if merging the functionalities of those two Activities would not produce a long diabolical block of code. Like I said, my project was a small one (its primary feature occurs in the background), so that single dynamic Activity didn't have too much in it. The screen-less Activity is definitely the way to go if you need your code to be more human-readable.
Related
I know we can keep only one instance by
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
but I need that my app can create maximum two instances of certain activity not more than that.
I am using a chained search feature like image below
When Instance3 of the activity1 is created i want to destroy:-
Instance1 of activity1
Instance1 of activity2
Tried to used this to kill a specific activity but activity have same Pid for all processes in an app
android.os.Process.killProcess( stack.getLast());
is there a way we can moderate which instances should be kept alive?
any help would be great thanks!
In my opinion this is the wrong architecture. For chained search you should only ever have a single instance of each Activity. You should flip between the different Activity instances by calling startActivity() and setting Intent.FLAG_ACTIVITY_REORDER_TO_FRONT in the Intent you use. Also add the data you want to display as "extras" in the Intent.
To be able to use the BACK button to back through the chain (no matter how long it is), each Activity should manage a stack that contains the data that it needs to recreate the page whenever the user backs into it. In onCreate() and in onNewIntent() the data (from the "extras") should be pushed onto the stack and displayed. You then override onBackPressed() and go back to the previous Activity by calling startActivity(), and setting Intent.FLAG_ACTIVITY_REORDER_TO_FRONT in the Intent you use. You also add an "extra" to the Intent that indicates the user wants to "go back". In onBackPressed() you should also discard the top element off the data stack of the Activity that is being left. This will ensure that the stack is correct when the user then backs into this Activity.
In onNewIntent() if the user just backed into the Activity, you just display the data that is already on top of the stack of managed data.
In this way, you only ever have one instance of each Activity, the user can chain all day through the set of activities and the BACK button always works and you don't have to worry about running out of memory.
Trying to accomplish this using taskAffinity or Intent flags or similar will not work. Don't waste your time. It is also bad programming style.
I hope this is clear.
Basically you want to remove entries 1 and 2 from the backstack when you create the 5th one, but leave the 3rd and 4th. Unfortunately, the backstack doesn't work that way, you can only manipulate it from the top. You have the option of clearing all the activities except the last one if you set the flags FLAG_ACTIVITY_CLEAR_TASK and FLAG_ACTIVITY_NEW_TASK, you will have an empty task only with the just started activity.
If I were you, I wouldn't worry about memory consumption by the old activities though. As long as you stop the resource-consuming processes in your activities when they leave the screen and don't hold the references to them so they can be garbage collected, Android can manage the memory itself fine. What you should think about is whether it makes sense for the user to come back to the old activities if he presses back. If yes, then leave them, if no, then don't.
In case you want to kill all your activities on the back button press, there is an Activity.finishAffinity() method. Just override the onBackPressed method to call it.
You can use a little hack with EventBus or BroadcastReceiver or some other Bus. Check my following code for my idea. For this app, I will keep maximum 2 instances of MainActivity
public class MainActivity extends AppCompatActivity {
public static int count = 0;
int id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
count ++;
id = getIntent().getIntExtra("ID", 0);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MainActivity.class);
intent.putExtra("ID", count);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
EventBus.getDefault().post(new Event(count));
}
#Subscribe
public void onEvent(Event event) {
if (id < (event.getID() - 2)) {//put your logic code to finish the activity here
Log.i("MainActivity", id + " is killed ");
finish();
}
}
#Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
}
you can do this bro,
declare one Activity object like this
public static Activity factivity;
onCreate()
{
factivity = this;
}
now you can use that object to kill that specific activity on another activity like this:
onCreate()
{
FirstActivity.factivity.finish();
}
I have an Android App, and has several activities. I need to provide the button for each activity or specific activity which should allow to Close the App, without going to back to previous activities or run in background.
I tried
finish();
System.exit(0);
Both combination and individually its not working but closing the current activity and navigate to previous activity.
I looked the code from the following question
Need code for exit from app in android
First, having a Quit button is not reccomended in Android as it's not part of the expected UX.
But if you really need it, then you can call your home activity with an intent containing an extra, for instance :
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra("FORCE_EXIT", true);
Finally in your home activity, when handling the intent (in the onNewIntent() method), if the "ForceExit" extra is set, then finish the activity.
The stack will have been cleared completely by the FLAG_ACTIVITY_CLEAR_TOP and your app will then stop.
The most recommended approach that works for most cases is to feature only 1 Activity, using fragments for content displaying and logic.
This way you only need to finish() the main Activity since it will control the app lifecycle by design.
You will have many other benefits, such as dependency control and reusability, aswell as built-in functionality like animations using fragment transactions while having the possibility of keeping a fragment backstack, which you can manage accordingly towards your expected user interaction and without affecting the conveniency of finishing your app by calling finish() on your host Activity.
Another thing you can do, is to flag intents like this: intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); before launching a new Activity.
This way you can maintain your back trace clean, hence finishing the application whenever the user press the back button or call finish() from any event. However the use of flags is discouraged and considered bad practise.
This may be a hack to solve your problem. but i have just made an app and tested my code and it is working fine.
You will need to create a new activity called QuitActivity or whatever you want to name it and when you want to finish your app or quit your app you will have to start that activity via using this code
Intent i = new Intent(getApplicationContext(), QuitActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
this.finish();
then this is my code for quit activity that does nothing but closes it self after clearing the backstack so your app will quit.
public class QuitActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.finish();
}
}
hope this helps you.
First Finish your current Activity while moving to next by this code
startActivity(intent);
Classname.this.finish();
Second thing just override onBackPressed
#Override
public void onBackPressed() {
//do nothing
}
Use:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
when starting a new Activity, as described in API Documentation.
type only System.exit(0);
or create static boolean needToExit;
set needToExit = true;
in place where you call
finish();
System.exit(0);
in all other activity overwrite onresume
public void onResume(){
super.onResume();
if (MySettingsClass.needToExit){
finish();
System.exit(0);
return;
}
//your other code;
}
I tried some of the answers here using the flags or System.exit(0), but for me it either didn't work or it resulted in weird behavior. Sometimes it would kill the app, but then immediately restart it. I realized that I should just be doing things more of the standard way using request and result codes.
Basically, in your parent activity, start your child activity with:
startActivityForResult(new Intent(this, ChildActivity.class), CHILD_ACTIVITY_REQUEST_CODE);
where CHILD_ACTIVITY_REQUEST_CODE is just a constant (static final) integer. Then in your child activity, when they press the exit button, finish the activity with:
setResultAndFinish(RESULT_CODE_EXIT);
where RESULT_CODE_EXIT is another constant (static final) integer. Then back in your parent activity, handle the result code and finish the parent activity too:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CHILD_ACTIVITY_REQUEST_CODE) {
if(resultCode != ChildActivity.RESULT_CODE_EXIT) {
finish();
return;
}
}
}
I have application and when I navigate back using Intent and startActivity(), views are null, onCreate() is called and activities are re-initialized. Why is that and how to bypass it?
I navigate back to activity like that:
#Override
public void onBackPressed() {
if (this.getClass() == XXX.class) {
Intent i = new Intent(this, YYY.class);
startActivity(i); //<-- activity restarts
return;
}
}
super.onBackPressed();
}
I use ActionbarSherlock, so I have activity with ActionBar initialization and every single activity just extends it. The way I navigate back to activity is described in this activity.
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
initUIComponents();
setListeners();
resetProgress();
}
and initUI() initializes UI.
EDIT
What I mean, how can I go back to previously created activity (not the one that is called via onBackPressed) and not recreate it? I use startActivity(), but apparently it recreates the whole thing
If you want that when you press back, you want to show the previous screen, then you don't have to do it in your code. Android Runtime internally maintains the stack, and will take care of showing the last-shown-activity when you press back. No need to handle it via onBackPressed()
However, if you want something other than this default action, that is when you should use onBackPressed(). Else, just let Android handle it.
So, in your application, if Activity 1 calls Activity 2, and user presses back, then the default action would be to show Activity 1 again. Don't override the onBackPressed() method
Edit:
For a custom flow of activities, you'll have to build the logic yourself. You need to override onRestart() in Activity 1, and onStop() in Activity 3. That way, onCreate won't be called again. By your logic, I mean, flags to keep track of which activity you're in, checking those flags, and calling the desired activity from there.
Edit 2:
This previous SO question, answers what you need:
Android Activity management , which suggests setting the flag FLAG_ACTIVITY_REORDER_TO_FRONT on the intent, and then calling startActivity()
Check out Android activity stack management using Intent flags for other stack reordering options: Stack management
I'm building a group of apps as a package similar to MS Office. Here each app has its own launcher as well as it can be launched from inside the home app. Each app has a login page. I need to display the login page when the app is launched from android launcher and not showing login page while launch from home app, How can i achieve this?
My scenario:
From Launcher----->(App)Login page--->(App)Home screen
From Home app----->(App)Home screen
You can do that by launching an empty activity (with no UI) and in its OnCreate method depending on some variable information (You can use SharedPreferences perhaps for that purpose) you can decide which Activity to start (Login or Home Screen app).
PS:
Btw if the login always leads to the same activity (Home Screen and is not used to login somewhere else) you don't even need the empty activity, you can check this in the Oncreate method of the login activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (logged_in_check_is_true)
{
Intent intent = new Intent(this, HomeScreenActivity.class);
this.startActivity (intent);
this.finishActivity (0);
}
...
You should always start LoginPageActivity. But if you start it from your "home app" just pass special extra to activtiy:
public class LoginPageActivity extends Activity {
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean needLogin = getIntent().getBooleanExtra("need login extra", true);
if (!needLogin)
{
// start your home screen
}
//setup login page
}
}
In home app just pass "need login extra" as false.
Basically similar to what tozka said yet you can also launch the activity you expect to be more often required and onCreate you check if you are in the right activity. If not call startActivity with the other activity without inflating any views etc before. So if your expectation is right then in more than 50% of the cases you are already in the right activity saving your app from two activities being called when it is launched
I have two activities but I want to apply a condition on application start, if one is true then start first activity else start second activity. Right now I am doing it by starting a third activity displaying some welcome stuff and examining the value in background..then appropriate activity gets called. I think there must be some standard way to do this. Peace.
Since you need to specify starting activity in manifest, you can always start first activity, check your condition on onCreate() and if you need to start second one - start second one and call finish() for the first activity.
Otherwise usually people use splash activity to check all the conditions at the startup (which is your current solution).
There's no need for a third Activity to check the condition.
If you simply have your MAIN/LAUNCHER Activity check on the condition as the very first thing it does in onCreate(...) (but after calling super.onCreate(...)), it can either continue or call startActivity(...) for the other Activity and immediately call finish() to self-terminate.
That way the first Activity will never be seen if the condition dictates the second Activity should be started.
Example..
public class FirstActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Don't even set the content view at this point
// we want to be invisible for the moment
// Pseudo-code check for condition
if (!runMe) {
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
finish();
}
else {
// Continue as normal
setContentView(R.layout.main);
...
}
}
}