I would like to finish an activity from inside the onCreate method. When I call finish(), onDestroy() is not immediately called, the code keeps flowing past finish(). onDestroy() isn't called until after the onCreate() closing brace.
Per the onCreate() description at developer.android.com/reference.
You can call finish() from within this function, in which case
onDestroy() will be immediately called without any of the rest of the
activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Reason I ask is: I would like to check data from the Bundle passed to onCreate(). Of course I have control of what is passed to onCreate, but I still think it should be checked at the point of delivery.
My code contains class A, which starts Activity B. I believe the last two "outside of if clause" tags, shouldn't be called because the finish method in the if statement should have destroyed the activity. It has nothing to do with the if clause because the tag line after the second finish() call is still also read.
My Code:
Class A
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// goToBButton: when pressed sends message to class B.
Button goToBButton = (Button)this.findViewById(R.id.go_to__b_btn);
goToBButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
Log.i(TAG,"A Class: goToBButton, onClick");
Intent i = new Intent(A.this, B.class);
startActivityForResult(i,REQ_TO_B);
}
});
} // end onCreate
My Code ClassB
public class B extends Activity{
private static final String TAG = "tag";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layoutb);
// set as true, should always print Tag: one line before first finish"
if (true) {
Log.i(TAG,"B Class: one line before 1st finish");
finish();
}
// shouldn't get here after first finish
Log.i(TAG,"B Class: outside of if clause, before second finish");
finish();
// shouldn't get here after second finish
Log.i(TAG,"B Class: outside of if clause, after finish");
} // end onCreate
#Override
public void onStart () {
super.onStart();
Log.i(TAG,"B Class: onStart");
}
#Override
public void onRestart() {
super.onRestart();
Log.i(TAG,"B Class: onRestart");
}
#Override
public void onResume () {
super.onResume();
Log.i(TAG,"B Class: onResume");
}
#Override
public void onPause () {
super.onPause();
Log.i(TAG,"B Class: onPause");
}
#Override
public void onStop () {
super.onStop();
Log.i(TAG,"B Class: onStop");
}
#Override
public void onDestroy () {
super.onDestroy();
Log.i(TAG,"B Class: onDestroy");
}
} // end B Class
Here are the results of my tags:
11-26 15:53:40.456: INFO/tag(699): A Class: goToBButton, onClick
11-26 15:53:40.636: INFO/tag(699): A Class: onPause
11-26 15:53:40.865: INFO/tag(699): B Class: one line before 1st finish
11-26 15:53:40.896: INFO/tag(699): B Class: outside of if clause,
before second finish
11-26 15:53:40.917: INFO/tag(699): B Class: outside of if clause,
after finish
11-26 15:53:41.035: INFO/tag(699): A Class: onResume
11-26 15:53:41.165: INFO/tag(699): B Class: onDestroy
I'm guessing that it is because finish() doesn't cause the onCreate method to return. You could try simply adding
finish();
return;
Or use an if else
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layoutb);
if(good data){
//do stuff
}else{
finish();
}
}
It seems like finish() does not work until onCreate() return control to system. Please refer to this post: about finish() in android. You have to consider this issue if you don't want any of your code to be executed after calling finish.
Hope it helps.
Related
Can any one explains what happens if I execute this activity?
I am getting weird output and app is hanging.
public class ComedyAct extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new ProgressBar(this));
startActivity(new Intent(this,secondact.class));
Log.d("main","I am after start second act");
int i=0;
while(i<10000);
}
#Override
protected void onStart() {
super.onStart();
int i=0;
while(i<10000);
Log.d("main","I am in start first act");
}
#Override
protected void onStop() {
super.onStop();
int i=0;
while(i<10000);
Log.d("main","I am in stop first act");
}
}
I would suggest you to read the activity life cycle...
when you start another activity, the ComedyAct activity will be in stop state, onStart will never call in this case..
Activity life cycle is:
OnCreate---> OnStart--->OnResume
when another activity launches
then first of all onPause---->onStop--->onDestroy
when first activity will be on resume?
first of all onCreate---->--->onStart---->onResume, if activity is destroyed...
But if the activity is not destroyed..then first of all onRestart--->onStart--->OnResume, in this case onCreate will never be called...
I want to call foo() every time my activity is destroyed, unless it is destroyed as result of clicking on a specific menu option (that eventually calls finish()). Currently I do this by calling foo() on default in onDestroy, unless a FLAG is set to true, where FLAG is set when I intercept the click on the menu option.
Is there a better way of doing this than setting a flag? Perhaps some way I can attach a tag to Android's finish() so that I can see the reason? Normally I would just try to call foo where it applies, but I can't account for every reason an activity might be destroyed.
Further caveat is that I would prefer not to make changes to base class (RootActivity)
public abstract class RootActivity extends Activity{
private flag someCondition;
#Override
protected void onCreate(Bundle savedInstanceState){
//...
}
// ...
public void startJob(JobAction.Id jobaction){
if (!jobaction.someCondition){
return;
}else{
startSomeLongAsynchronousJob(someCondition);
finish(); //If this is why onDestroy happened in subclass, I dont want to call foo()
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
//...
startJob(JobAction.SOMEENUM); //Startjob is being called in the superclass
}
//...
}
public class SpecificJob extends SomeClassThatExtendsRoot{
private boolean FLAG = false;
#Override
public void onCreate(Bundle bundle){
super.onCreate(bundle);
//...
}
// ... some code ...
#Override
public onDestroy(){
if (!FLAG){ //Check if it was finish() that did this
foo();
}
super.onDestroy();
}
#Override
onOptionsItemSelected(MenuItem item){
super.onOptionsItemSelected(item);
if (item.getItemId()==r.id.DONTCALLFOO){
flag=true;
}
}
}
You have to override onSaveInstanceState in your activity.
#Override
protected void onSaveInstanceState(Bundle outState) {
Log.d("ApplicationFlow","onSaveInstanceState was called. System destroy your activity");
foo();
super.onSaveInstanceState(outState);
}
It is always called when the activity is destroyed by the system, and not by you (when you call finish()).
The purpose is give to user a chance to save some state in Bundle outState parameter. This bundle will be passed to onCreate(Bundle savedInstanceState) to the user restore the state, when the activity is going to be recreated.
See documentation
I just recently started learning how to build android apps, and encountered a problem:
I want, when users leave the app (go to the homescreen, multitask), and they return, that the app calls a certain method. How can I do that?
This problem is more tricky than it may look like. When you return to app after leaving it, then is called method onResume of activity which was active when app was interrupted. But same happens when you go from one activity to another (onResume of second activity is called). If you just call method from onResume, it will be called every time onResume of any activity is called.
Take a look at this solution...
First, you have BaseActivity which is extended by all activities that need to call that method:
abstract public class BaseActivity extends Activity implements IName {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
if (AppClass.getPausedActivity() != null) {
if (this.getClassName().equals(AppClass.getPausedActivity()))
//call specific method
}
AppClass.setPausedActivity("");
super.onResume();
}
#Override
protected void onPause() {
AppClass.setPausedActivity(this.getClassName());
super.onPause();
}
#Override
abstract public String getClassName();
}
As you can see it implements interface IName:
public interface IName
{
String getClassName();
}
BaseActivity in onPause (when it is interrupted) calls setPausedActivity method of AppClass which remembers last activity name that was interrupted. In onResume (when app and activity is continued) we compare name of current activity and last paused activity.
So, when app is interrupted, these names will be same because you paused one activity and you got back to the same one. When you call activity from some other activity these names will not be same and method will not be called.
Here is code for AppClass:
public class AppClass extends Application {
public static String pausedActivity;
public static String getPausedActivity() {
return pausedActivity;
}
public static void setPausedActivity(String _pausedActivity) {
pausedActivity = _pausedActivity;
}
}
Also, here is example of activity that extends BaseActivity:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
//here you set name of current activity
#Override
public String getClassName() {
return "MainActivity";
}
}
You are bound to the Activity lifecycle. You will need to implement corresponding logic to figure out if the user has been in your app before (i.e. using SharedPreferences).
What happens when finish() method is called in onStop() method?
Does it causes anr : means it calls
onPause()->onStop()->finish()->onPause()....
or it finishes the activity : means it calls directly
onDestroy()
Actually, I want to finish my activity when it is completely invisible.
EDIT:
See this scenario, I launch an activity B whose layout height and
width is smaller than activity A, so activity A is partially visible
and when I press the home button activity A becomes completely
invisible. At this point I want to close activity A, so that it do not
call onRestart().
Thanks in advance.
It finishes the activity and onDestroy() is called. If you want to finish your activity when it is invisible then you should call finish() in onStop().
according to your scenario, maintain one flag in MainActivity indicating that other Activity is launched or not? and make sure yourself to finish MainActivity or not based on that flag ...
this may help you...
public class MyActivity extends Activity {
private boolean isSecondActivityLaunched;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
isSecondActivityLaunched = false;
}
public void onClick(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
isSecondActivityLaunched = true;
}
#Override
protected void onStop() {
super.onStop();
if(!isSecondActivityLaunched) {
finish();
}
}
}
It will be best way in your case to call finish() ;
Thanks
Consider the following scenario:
The class TemplateActivity extends Activity. Within onResume() it performs a validation of a boolean variable then, if false, it finishes the method and the activity, and starts a new activity, OtherActivity.
When the class ChildActivity, which extends TemplateActivity, runs, it waits for super.onResume() to finish and then continue no matter if its super needs to start the Intent or not.
The question:
Is there a way to terminate the ChildActivity when the OtherActivity needs to start from the TemplateActivity? Without implementing the validity check in the child class.
Superclass:
class TemplateActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
if(!initialized)
{
startActivity(new Intent(this, OtherActivity.class));
finish();
return;
}
//Do stuff
}
}
Subclass:
class ChildActivity extends TemplateActivity {
#Override
protected void onResume() {
super.onResume();
//Do stuff
}
}
A more elegant solution would be a slightly different approach to the class design:
Introduce a method DoStuff() (replace with sensible name) in the TemplateActivity . Do all the // do stuff bits there.
Call this method from the end of TemplateActivity OnResume
Override it in the child activity to extend it with the child activity // do stuff bits.
Do not override onResume in the ChildActivity.
This way, if the condition fires in TemplateActivity OnResume, none of the parent and child DoStuff will be done. The ChildActivityshouldn't have to know anything about this behavior.
I guess this is what you're trying to get:
class ChildActivity extends TemplateActivity {
#Override
protected void onResume() {
super.onResume();
if (!isFinishing()) {
// Do stuff
}
}
}