I have a single activity timer application in which I have overridden the onPause() method to pause the timer when the user presses the home or back button. However, I would like the timer to keep moving in the case that the user manually turns off his screen, but I know this will also call the onPause() method. Is there any way to get around this?
You can override onBackPressed to allow you to put some extra logic when the back button is pressed. However, a better approach might be to put your code in onStop(), which is only called when another Activity is moved to the foreground.
See the Android Docs for more detail
I ended up doing this by detecting and ignoring a screen turn off event inside the onPause() method. Instructions on how to do this can be found here: http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
Specifically, I used this code from the comments (courtesy of Kyle):
#Override
protected void onCreate() {
// initialize receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
//NEW
PowerManager pm =(PowerManager) getSystemService(Context.POWER_SERVICE);
// your code
}
#Override
protected void onPause() {
// when the screen is about to turn off
// Use the PowerManager to see if the screen is turning off
if (pm.isScreenOn() == false) {
// this is the case when onPause() is called by the system due to the screen turning off
System.out.println(“SCREEN TURNED OFF”);
} else {
// this is when onPause() is called when the screen has not turned off
}
super.onPause();
}
Related
I am making an android app in java in which I need to trigger some database requests whenever an activity is completely destroyed which would probably happen if the user presses the back button or leaves the app itself... But the onDestroy() function in my app is randomly getting triggered even when the user is still on the activity... I guess the probable reason for this is configuration changes but I am not able to figure out a proper solution for this.
Is there a way we could exactly detect when an activity is left by a user avoiding any in-page configuration changes??
The onDestroy() that I am using is this:
#Override
protected void onDestroy() {
/// do smthng
super.onDestroy();
}
Any help would be appreciated!!
Solved:
Thank you for the answer guys... For me onStop() worked out perfectly and it is working in every case whether it might be pressing the back button or exiting the activity or the app itself!!
If you want to check if the user ended the activity, meaning pressed back, do this:
#override
public void onBackPressed(){
//do something before we finish the activity
super.onBackPressed();
}
If you want to check when user, goes to next activity, then resturns to the same activity:
#override
public void onResume(){
//do something when return back to this activity
super.onResume();
}
#override
public void onPause(){
//do something before going to another activity
super.onPause();
}
onDestroy is called when the activity is destroyed or finished and not guaranteed to be called always, don't depend on it
We can check on whether our application is foreground or background based on the activity entering and exiting the foreground by implementing ActivityLifecycleCallbacks.
Good reference : https://medium.com/#iamsadesh/android-how-to-detect-when-app-goes-background-foreground-fd5a4d331f8a
Quoting from the above article,
#Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
and,
#Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
by which we can make sure that our app is in foreground or not. Here you always have the control of what activity is in foreground based on which you can check and execute the logic.
I want to make a cloud synchronization everytime my app is brought to front and a second time if the app disappears in background.
So I overwrote the onStart and onStop event methods of my activity:
#Override
protected void onStart() {
super.onStart();
doSync();
}
#Override
protected void onStop() {
doSync();
super.onStop();
}
Ok, that works fine for me but I found out that these methods are also called if I start a new activity (f.e. SettingsActivity.class) within my app (onStop) and come back to the main activity (onStart).
Is there a good way to ignore the calls of my own activities and only react on calls from "outside", f.e. I only want to synchronize if the user stops the app by pressing the home button and I also want to synchronize only if the user returns to the app by starting it from the app dreawer or app switcher?
+++ SOLUTION +++
Now I found a solution for my problem and I want to share it. Maybe it's not the best way because it's no SDK-based functionality but it works and it's quite simple.
I declared a flag, set it to false when the activity is created. Everytime I start another activity in the same app, I will set the flag to true and check its state in onPause and onResume.
public class MainActivity extends Activity {
private boolean transition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
transition = false;
}
private void startSettingsActivity() {
transition = true;
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
}
private void doSync() {
// all steps for the cloud synchronization
}
#Override
protected void onResume() {
super.onResume();
if (!transition) {
// this is the case the user returns from
// the app drawer or app switcher or starts
// the app for the first time, so do sync
doSync();
} else {
// this is the case the user returns from another
// activity, so don't sync but reset the flag
transition = false;
}
}
#Override
protected void onPause() {
if (!transition) {
// this is the case the user presses the home button or
// navigate back (leaves the app), so do final sync
doSync();
} else {
// this is the case the user starts another activity, but
// stays in the app, so do nothing
}
super.onPause();
}
}
Couldn't find a solid answer to this anywhere. I have a method where finish() is being called, and onPause() is called afterward.
Is onPause() guaranteed to be called after a call to finish() ?
Android will generally call onPause() if you call finish() at some point during your Activity's lifecycle unless you call finish() in your onCreate().
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
finish();
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
Run, and observe that your log will only contain "onDestroy". Call finish() almost anywhere else and you'll see onPause() called.
The system calls this method as the first indication that the user is leaving your activity (though it does not always mean the activity is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back). so
onPause() is guaranteed..The official documentation here
EDIT 1
onCreate() is to onDestroy() && onStart() is to onStop() && onResume() is to onPause() .. onStart() is called when onCreate() finishes its work. if not its not called.. onResume() indicates the ui is about to be shown to the user -(An Activity's content is the screen the user sees).
if you call finish() in onCreate(), onPause() will be skipped because onResume() was never called same goes to onStart() .. so in some cases you can say its not; but that will be false, because what's an Activity that is not a screen or serve as a container for screens-(Fragment).
and why would you call finish(); directly in your Activity's onCreate()? From how Activities work in general, onPause() will always guarantee is calling..
Yes, whenever you activity is going to be disappeared, onPause is called.
It is a bit late but may help future visitors.
I faced the problem of onPause() not being called when I tried to make an splash screen for my app following this tutorial.
After some fiddling around and forcing my mind I figured out why! the onCreate() method looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
So before the activity gets a chance to get started or resumed I was forcing it to be finished and so bypassing the other state method calls!
But as far as I know from the official Activity documentation in any other situation (at least normal ones!) the onPause() method is guaranteed to be called!
When I play my song and press the back button to return to return to home, the music continues playing. When I launch the app again, the music plays twice. I think it's the onResume method because I commented out the method and the problem stopped. How do I get onResume work properly? I tried using if(backgroundMusic.isplaying()) inside the onResume, but the app crashes when I resume from another activity. What am I doing wrong?
//global mediaplayer
MediaPlayer backgroundMusic;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadBackgroundMusic();
}
private void loadBackgroundMusic() {
//load mp3 into object and start it
backgroundMusic = MediaPlayer.create(this,R.raw.backgrounmusic);
backgroundMusic.setLooping(true);
backgroundMusic.start();
}
#Override
protected void onPause() {
super.onPause();
backgroundMusic.release();
}
#Override
protected void onResume() {
super.onResume();
loadBackgroundMusic();
}
#Override
protected void onStop() {
super.onStop();
backgroundMusic.release();
}
I'm not really sure about the behavior you want. As I see it, it's one of two:
Music should be played only while my Activity is visible
If this is the case, you should look closer on the documentation for the Activity Lifecycle. This will for example tell you that onResume() will also be called the first time the Activity is created.
So the solution would be to start the music in onResume() and stop on onPause() or similar.
After starting my activity once, music should be played even if i return to home screen
In this case you really want a Service.
So I've got an activity in my android app, that runs on start.
This activity is just a page with a start button.
When I press the start button, it calls another activity and closes itself:
Intent i = new Intent(this, Dictating.class);
startActivity(i);
finish();
The other Activity is using Text-to-speech to dictate some words.
Now I've got something weird happening:
1) I listen to the dictating.
2) I press back button: dictating stops (what I want)
3) I run again the app, press the start button. Now I have my new activity running and dictating, but in the back I can hear the older Activity that resumed where it was, and continues dictating.
I would like for the new activity to start all over again, and not keep the other activity.
How can I do that ?
PS: This is an activity problem, and not a text-to-speech problem as I'm flushing the text-to-speech each time, It could not be kept in the memory
Thank you
EDIT:
Here is the onCreate of my Dictating class, there is tons of code in this class, I obviously don't want to post all my code, so here is some parts:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.streaming);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
this.txtCurrentWord = (TextView) findViewById(R.id.txtCurrentWord);
this.btnPlayPause = findViewById(R.id.btnPlayPause);
this.btnPlayPause.setOnClickListener(this);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
this.tts = new TextToSpeech(this, this);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
there are a few weird things I'm doing like:
Runnable task = new Runnable() {
public void run() {
//runs on ui
runOnUiThread(new Runnable() {
public void run() {
readNextWord();
}
});
}
};
worker.schedule(task, 1, TimeUnit.SECONDS);
this delays the next word by one second, and then executes a fonction in the main ui thread. not sure if this matter
And some flushing at the end:
#Override
public void onDestroy() {
tts.shutdown();
super.onDestroy();
}
You need to add launchMode property to your activity inside AndroidManifest file, for more detail see "Using the manifest file"
This question is over a year old, but I can't believe no one ever gave you the right answer. Also, I don't think you should have accepted an answer that clearly didn't solve anything for you. By accepting such answers, you're just cluttering the StackOverflow google search results with junk for other people with the same problem.
The flushing you do at the end is completely wrong. According to the Activity lifecycle, onDestroy() is never guaranteed to be called. If you want to make sure the flushing gets done properly, do it inside of onPause().
For now the solution I'm giving you does fix the main problem you've described. However, if you do get the time to do a more complete rewrite, you'll want use a service that you bind to your activity. That will give you the finer control you require.