If the user clicks on the Home button for example, the methods onPause() and onStop() are called.
I want to call onDestroy() from the onStop() method after 1mn, unless the user goes back on the app (which calls onResume() and onStart() methods).
I tried to implement Timer:
It fails, saying it cannot call the onDestroy if Looper not implemented.
When I implement the Looper, the onDestroy() method is never called.
Maybe calling onDestroy() from onStop() is not the good thing to do, and another "clean" solution exists to get the behavior I want. I just want to kill the app after 1mn no use.
In this case, please propose.
If my wish is the good way to proceed, could you share how to implement it ?
dont call onDestroy() directly , instead call finish() after the period you want
and to support the scenario you mentioned make sure not to kill the activity if the user resumed the activity
here's a piece of code i wrote for you .
the activity will kill its self if not resumed in 1 second ;
boolean notResumed;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startActivity(new Intent(this,Main2Activity.class));
}
#Override
protected void onResume() {
super.onResume();
notResumed=false;
}
#Override
protected void onStop() {
super.onStop();
notResumed=true;
Handler handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(notResumed)
finish();
}
},1000);
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d("debug","onDestroyCalled");
}
This answer is largely inspired from Abdelrahman's post above.
I just adapted few things to reinitialize the delay counter each time I go out of my app.
boolean notResumed;
//Declare my Handler in global to be used also in onResume() method
Handler myHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startActivity(new Intent(this,Main2Activity.class));
}
#Override
protected void onResume() {
super.onResume();
notResumed=false;
//Remove callbacks on the handler if it already exists
if (myHandler != null) {
//I send null here to remove all callbacks, all messages,
//and remove also the reference of the runnable
myHandler.removeCallbacks(null);
}
}
#Override
protected void onStop() {
super.onStop();
notResumed=true;
myHandler=new Handler();
myHandler.postDelayed(new Runnable() {
#Override
public void run() {
if(notResumed)
finish();
}
},10000);
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d("debug","onDestroyCalled");
}
Thanks a lot again to Abdelrahman Nazeer for its fast and accurate answer.
Please comment if something is not correctly done here. At least it works as expected...
Related
I created a basic sample application that all it does is call finish() during the Activity onStop(). Based on my understanding and from looking at other posts on Stackoverflow, this should trigger onDestroy().
My repro steps are launch the application, press the Home button on the device, which will trigger onStop(). The expected result is that it also hits onDestroy(), but I'm not seeing that.
If I call finish() during onPause() instead, it will trigger onStop() and onDestroy() as expected.
Anyone know why it would work during onPause() but not onStop()?
I've also noticed this message in the Logcat
I/ActivityManager: Activity reported stop, but no longer stopping: ActivityRecord{203ab0 u0 com.amazon.myapplication/.MainActivity t96 f}
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d("Sample", "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
Log.d("Sample", "onStart");
super.onStart();
}
#Override
protected void onResume() {
Log.d("Sample", "onResume");
super.onResume();
}
#Override
protected void onPause() {
Log.d("Sample", "onPause");
super.onPause();
}
#Override
protected void onStop() {
Log.d("Sample", "onStop");
finish();
super.onStop();
}
#Override
protected void onDestroy() {
Log.d("Sample", "onDestroy");
super.onDestroy();
}
In the onCreate() method of my activity I have a Timer + TimerTask that will schedule a ParseQuery. On The ParseQuery callback, which is on mainThread, I delegate an interface callback to make a simple UI update. This works when I let the Activity unchanged. But if I exit from the activity and enter again it (A new timer will NOT be created here, because it gets created only when starting the activity from a certain point) wouldn't work. I think is something with Activity instances but I cannot handle it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
....
uiTimer = new Timer();
uiTask = new TimerTask() {
#Override
public void run() {
doParseTask();
}
};
uiTimer.schedule(uiTask, shortCodeLeft);
}
doParseTask(){
Utils.doParseQuery(this, new MyListener{
#Override
public void onSuccess() {
updateUI();
}
});
}
updateUI(){
Log.i(TAG, "Show changed layout"); //This is always shown, this way I ensure it gets here!!
mTextView.setText(foo); //this doesn't work
mLayout.setVisibility(View.GONE); //this doesn't work
}
The ParseQuery is executed in done() callback method, I call the function that updates the UI:
public class Utils{
.......
doParseQuery(Context ctx, MyListener listener){
.......
query.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if(e == null){
....
listener.onSuccess();
}
}
});
}
}
What I have tried, with no success:
1. make the `uiTimer` and `uiTask` static global variables; // I thought that maybe it gets leaked into activity instances
2. update the UI using
runOnUiThread(new Runnable() {
#Override
public void run() {}
});
OR
mLayout.post(new Runnable() {
#Override
public void run() {
mLayout.setVisibility(View.GONE);
}
});
3. android:launchMode= "singleInstance" //in Manifest
If you want that your UITimer to gets executed every time your activity goes to foreground, you should implement the onStart or onResume method and move your uiTimer implementation to one of both method. Even your activity being already started these two methods are called after exiting the activity and reopening it again.
A better explanation of Android Activity lifecycle is well explained by google documentation https://developer.android.com/guide/components/activities/activity-lifecycle.html.
Your code would look like this:
#Override
protected void onStart() {
super.onStart();
....
uiTimer = new Timer();
uiTask = new TimerTask() {
#Override
public void run() {
doParseTask();
}
};
uiTimer.schedule(uiTask, shortCodeLeft);
}
doParseTask(){
Utils.doParseQuery(this, new MyListener{
#Override
public void onSuccess() {
updateUI();
}
});
}
When you exit from your activity, the instances mTextView and mLayout will be destroyed.
Then, when you create a new activity, the activity creates new instances of the text view and layout.
Your timer goes off and tries to update the original elements, which are now invalid as the activity has been closed (but the log still works as this is separate to your activity).
You should initialise the timer & task in onCreate(), and then in order to stop updating the old UI elements:
#Override
protected void onStop() {
if (uiTimer != null) {
uiTimer.cancel();
}
super.onStop();
}
I'm having trouble with resuming an app's activity after locking the device screen.
Here's the typical situation:
1. App is running.
2. Lock device.
3. Unlock device.
4. Instead of returning to running app, it shows a black screen.
I checked how the activity lifecycle is running and it seems this is what's happening when it unlocks:
1. Create
2. Start
3. Resume
4. Pause
Why is it stuck on pause? I'm sure this is really simple but as I'm still learning Android I'm super confused. Thanks for any help given!
EDIT:
I don't think I'm doing anything out of the ordinary but here's the basic code I'm using...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Java", "Create");
// Initialize NDK audio properties here
// Initialize the Content View
setContentView(R.layout.activity_main);
// Setup toolbar
Toolbar myToolbar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(myToolbar);
// Start thread
thread = new Thread() {
public void run() {
setPriority(Thread.MAX_PRIORITY);
// Audio Thread is running here
}
};
thread.start();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onPause() {
super.onPause();
if (thread != null) {
try {
thread.join();
}
catch (InterruptedException e) {
// e.printStackTrace();
}
thread = null;
}
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onStop() {
super.onStop();
}
Try this (it will instruct your app to save state):
protected void onSaveInstanceState(Bundle icicle) {
icicle.putLong("param", 1);
super.onSaveInstanceState(icicle);
}
I am not thread expert. but here it seems you are blocking ui thread in onpause. thread.join causes the current thread(in this case ui thread) to pause execution until thread terminates.
Activity.onPause() and onStop() are called in (at least) two situations:
The another Activity was launched on top of the current one.
The app was minimized.
Is there an easy way to tell the difference?
You could do it this way. Make all of your activities extend from a base activity. The base activity needs to keep a visibility counter that is incremented/decremented during onResume/onPause:
public abstract class MyBaseActivity extends ActionBarActivity {
private static int visibility = 0;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
}
#Override
protected void onResume() {
super.onResume();
visibility++;
handler.removeCallBacks(pauseAppRunnable);
}
#Override
protected void onPause() {
super.onPause();
visibility--;
handler.removeCallBacks(pauseAppRunnable);
// give a short delay here to account for the overhead of starting
// a new activity. Might have to tune this a bit (not tested).
handler.postDelayed(pauseAppRunnable, 100L);
}
#Override
protected void onDestroy() {
super.onDestroy();
// uncomment this if you want the app to NOT respond to invisibility
// if the user backed out of all open activities.
//handler.removeCallBacks(pauseAppRunnable);
}
private Runnable pauseAppRunnable = new Runnable() {
#Override
public void run() {
if (visibility == 0) {
// do something about it
}
}
};
}
I want to kill my Activity process when I pause it by answering a call or something like that
but when i try to start my app it closes instantly. Any solutions? Sample code below
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Things to do
}
//#Override
public void onPause() {
super.onPause();
android.os.Process.killProcess(android.os.Process.myPid());
}
You should implement a logical scenario based on activity's lifecycle methods.
update your code with
#Override
public void onPause() {
super.onPause();
this.finish();
}