I implemented a broadcast receiver to update one of my UI activities but my problem is this: when the back button is pressed by the user, android kills the broadcast receiver but when the home button is clicked, the state is retained. What am trying to achieve is retaining the state even after the back buttton is clicked-- onBackPressed() until the user explicitly calls finish(). Any pointers?
You shouldn't rely on your Activity being always accessible to receive the broadcast. Instead, use LocalBroadcastManager to attempt to deliver the broadcast to the Activity, and if it fails - store the update locally and apply it when the Activity is displayed next time.
You need to register your receiver in your onCreate() method and call unregisterReceiver() on onDestroy().
Edit:
You can see #Shiki's answer in here.
It does what you need.
Related
For example, I started an activity, there is a button in the activity
And then I start the background service, this service will check whether the target activity is on foreground, then trigger the click event of that button.
Is it possible to do this?
Why would you trigger a click event of an activity rather than notifying the activity about its results? Try to use local broadcasts which are sent from the service to the activity. The activity registers for that broadcast and in its onReceive of the BroadcastReceiver you'll trigger your onClick method or any other method of your choice. The Receiver is registered in onResume and unregistered in onPause to guarantee that the activity is actually visible.
I would not recommend to use a direct dependency on your activity as this might cause IllegalStateExceptions if in any circumstance your activity is not started or visible at all.
I can strongly recommend you to use eventbus concept like "otto by square" in this case.
you will subscribe to event from the activity this will keep to modularity and will let you do this function
If you have two activities A,B that both added connection listener to them. Lets say Activity A started Activity B (so A is in the background onPaused while B is active).
Now connection event comes, will it execute the code of the listener in both activities or just the visible activity which is B?
Thanks
Depends. I always register listeners in onResume (after making sure I have the current data) and unregister them in onPause. This way I make sure they only fire in the on-top app. But if you do not do this, the listener methods will be called on the event. Most likely on "A" first because it was registered first as listener.
Sometimes you want to have a listener still listen - maybe you want to finish() both Activities on a disconnect, that's one case where I would not unregister.
So it depends on your usecase.
NOTE: The listener will not "wake it up" in any case. Just the onXXX method will be called.
I have a flow in my android app where it is possible to open a chain of user profile activities, one activity from another.
Example : User profile A is opened where it contains a list of other user profiles. clicking an item from this list will open user profile B. Again, it lists other user profiles where user profile A might be part of. So clicking this item will open another activity of user profile A.
The app user can perform an action on the current activity of user profile A which needs to be reflected on all other user profile A activities in the back stack. So what i did was registered a receiver in the user profile activity that checks for the activity user id against the one coming from the broadcast and perform the relevant actions on the UI.
The problem is, that i cannot unreigster the receiver on onPause() or onStop() (according to a lot of threads recommendations here) since this is kindda counterproductive to what im trying to build here. And according to the documentation onDestroy() is not guarunteed to be called every time the activity terminates.
So what im basically asking here is - Is it a good practice to register all activity receivers on onCreate() and unregister them both on onDestroy() and onSaveInstanceState() so i will be 100% sure they are cleaned up on activity destruction ?
The only mention i saw in the documentation that recomments not to unregister receivers in onSaveInstanceState() was here - BroadcastReceiver - and it only says
Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack
EDIT:
Ok, i just saw this quote in the onDestroy() spec :
There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
So onSaveInstanceState() will not be called also.
But arent receivers qualified as things that are NOT "intended to remain around after the process goes away" ? I dont get why onDestroy() is not called in such situations. What happens to other resources that are released there (not just receivers) ?
In your case, using broadcast receiver to detect which Activity instance is running is not a good idea. You should use single instance for every Activity. Another solution is that you can create view stack in one Activity instead of Activity stack. Switching view is easier than switching Activity. As to how to use onDestroy and onSaveInstanceState(), it depends on your scenario. If you finish your Activity, the onDestroy will be called. If your Activity is destroyed by system in some situation, like screen rotation, the onSaveInstanceState will be triggered.
I have this requirement to send my application background and then bring it to foreground on some key capture intents (not from application launcher offcourse) So How can I send the current tasks to background and bring the same to foreground ?
Use moveTaskToBack() to send the activity in the background and still running if the user presses the back key.
see :Activity for the way on how to do this. its quite simple.
so in order to do this you will also need to override the onBackPressed() method or onKeyPressed() and call this method if the back button was pressed (dont forget to return true on the back pressed methods so android is aware that you consumed the event and doesnt finish the activity).
For returning to this activity that you have moved to the background you can post a notification with a pending intent to launch it back and that will automatically bring the activity to foreground.
Hope this helps.
To send you application to background you should call moveTaskToBack() from your Activity class. When your Activity gets new intent (btw. the onNewIntent() method from your Activity will be called) your Activity gets into foreground by system (you don't have to do anything).
What do you mean by "background?" Activities are stacked one upon another as you create new Activities, then accessed in reverse order using the device's back button. Think of the push() and pop() methods, it's the same paradigm. Applications that need to have code running non-interactively should extend android.app.Service, but beware that you can do some real damage implementing a service. Rogue processes can drain battery life and reduce UI responsiveness.
I solve all the problem pertaining to notification start with fresh activity after moveTaskToBack(true) when back key is pressed by
adding to manifest android:launchMode="SingleTask" android:clearTaskOnLaunch="true"in the activity xml markup section
I have a Service which tracks the location of the user. Currently, the Service boots when the application starts and stops when the application terminates. Unfortunately, if users keep the application in the background, the Service never stops and drains battery.
I would like the Service to stop when my application is not in the foreground. I was hoping the Application class would let me Override onPause and onResume handlers, but it does not have them. Is there another way I can accomplish this?
I haven't tested this yet, but it looks like if you use Context#bindService() (instead of Context#startService()), the service should stop when no more activities are bound to it. (see Service lifecycle).
Then use onPause()/onResume() in each activity to bind/unbind from the service.
Alternatively, you could add a pair of methods on your service which tell it to start/stop listening for location updates and call it from each activity's onResume()/onPause(). The service would still be running, but the location updates wouldn't be draining the battery.
Reading all the above answers I would suggest Simply add a boolean global flag for each activity & put it in your onResume & onPause & also while launching an Activity Something like this
public void onPause()
{
super.onPause();
activity1IsResumed = true;
}
&same for onResume
& similarly when launching a new Activity
startActivityForResult(myintent ,0);
activity2IsResumed = true;
activity1IsResumed = false;
then in your Service simply check
if(activity1IsResumed || activity2IsResumed || activity3IsResumed)
{
//your logic
}
else
{
//another logic
//or dont run location tracker
}
& you are done!
You should override the onPause and onResume methods on your Activity. If you have multiple activities you may want to have a common base class for them and put the start/stop logic into the base class.
I have not tried this approach but I think you can override the home key of android device by using KeyEvent.KEYCODE_HOME and you can use stopService(Intent) to stop your service and when again application resumes, you can write startService(Intent) in the onResume() method of your Activity.
This way I think your service will only stop when user explicitly presses home button to take application in the background and not when he switches from one activity to another.
What I would suggest is overriding the onPause/onReume methods as others have said. Without knowing more about the flow of your application and interactions between Activities, I can't give much more information beyond guesswork.
If your Activities are persistent, however, my recommendation would be to utilize the Intents better when switching between Activities.
For instance, each Activity should have a boolean "transition" flag. So, when you move from one Activity to the next, you set up an Intent extra:
intent.putExtra("transition",true);
Followed in the receiving Activity by: (in onCreate)
intent.getBooleanExtra("transition",false);
This way, for each Activity that launches, you can know whether it has come from another Activity, or if it has been launched from a home screen launcher. Thus, if it gets a true transition, then onPause should NOT stop the service--that means you will be returning to the previous Activity after it returns. If it receives no "transition" extra, or a false transition, then you can safely assume there is no Activity underneath it waiting to take over for the current one.
On the first Activity, you will simply need to stop the service if you are switching to another Activity, which you should be able to figure out programmatically if one Activity is started from another.
It sounds like the real problem is how to only stop the service when you go to an activity that isn't one of your own? One way would be to in your onPause method to stop the activity. Do this for all your activities. Then override your startActivity method. And in here do a conditional test to confirm that you are purposefully navigating to one of your own. If your are set a flag to true.
Now go back to your on pause overridden method. And only stop your service if the flag is not equal to true. Set the flag to false.
All events that navigate away will close your service. Navigating to your own will leave it intact.
Do the overriding in a base class that all your activities extend.
Writeen in my andolroid. Will post ezaple later.
Try using the Bound Services technique to accomplish this.
Bound Services | Android Developers
You can use bound services in a way such that the service will stop when no activities are bound to it. This way, when the app is not in the foreground, the service will not be running. When the user brings the app back to the foreground, the Activity will bind to the service and the service will resume.
Create methods registerActivity() and unRegisterActivity() in your Application object and implement first method in all you acts onResume() and second in acts onPause().
First method add activity to List<Activity> instance in your app object, unRegisterActivity() checks size of list in every call if==0 stopService();.