There are three activities A, B, and C
Register EventBus in Activity A onCreate(),and unregister on onDestroy(), and a method onEvent(TestEvent e);
Activity A starts Activity B
Activity B starts Activity C
In Activity C:
EventBus.getDefault().post(new TestEvent("close A"));
I use EventBus in this way , and it works well. Is there anything wrong in my code ?
It's okay. EventBus is thread safe and has a lot of methods to make it easier to work with, like onEventMainThread, onEventBackgroundThread, onEventAsync.
The thing with your code is this: your activity will continue to get events even if it is in background. And that's okay (in this particular case). If, however, you'll have to implement something else in the future, keep this in mind:
onCreate register -> onDestroy unregister
onStart register -> onStop unregister
onResume register -> onPause unregister
And there's something else, too: you have to make absolutely sure that your activity is only registered ONCE. Because, if you register more than once, you will receive as many events as the number of registers. Thus, please modify your register like this:
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
If you need more details, please read more about EventBus here.
However, if you follow these simple rules, your activity's lifecycle. I use it a lot and I don't encounter issues.
Related
I have an application with multiple activities and have some behavior in onPause on my MainActivity that I don't want to happen when switching to another activity.
Right now whenever I switch activities the MainActivity onPause() is called and it always runs the behavior.
Activity lifecycles are tightly coordinated, so when launching one Activity B, from Activity A, the following lifecycle events will take place: ActivityA.onPause, ActivityB.onCreate, ActivityB.onStart, ActivityB.onResume, ActivityA.onStop. You can definitely leverage this lifecycle coordination to achieve what you want, if you are move you "behavoir" to the lifecycle method onStop (which is a better place to do most shutdown/stopping work at).
Create a Lifecycle registrar object that will perform the "behavior" when there are no activities are registered in the Lifecycle registrar object. Register your Activities inside of their onStart() and onStop() liefycle callbacks. Inside of the deregister method of your Lifecycle registration object check to see if there are any registered objects and if their aren't you perform you "behavior" whatever that may be. You can extend this functionality to work with Services, just register and deregister the service with the Lifecycle registrar inside the Service's onCreate, onDestroy respectively.
Using onStop instead of onPause, has the added benefit of keeping you from doing your paused/stopped "behavior" when the app is actually in the background and not just partially visibly, such as the case when the system displays a dialog. For example, when requesting to start Bluetooth, the Android OS will generate a dialog prompting the user, and calling onPause. This makes since for some apps but not all apps, and when you think about it, there are a various other use-cases that will cause the app to enter onPause(), that would be annoying to the user for you app to perform shutdown processes.
I have personally utilized this scheme to maintain a open connection, while the app is open and close the connection when the app is killed, or placed in the background. I even modified the Lifecycle Registrar object to maintain the connection during device rotation.
Here's a solution (a little dirty), you can use a boolean to know when you're switching the activity, set it to true just before you call startActivity(intent), and set it to false in onResume().
P.S, using onStop() is better than onPause() in your case, i believe you don't want to delete those cookies when the activity is partially visible
I am using Greenrobot's EventBus in my app, and it works fine.
However, if I press the back button to close the app, then restart the app instantly I seem to receive the event twice. If I then do so again, I will receive it three times and so on.
I am checking with logs and debugging to see if I have multiple instances of any classes, or if I am registering multiple times, but I can't see any extra classes and using isRegistered returns false.
Any ideas?
Thanks
Are your register/unregister calls paired correctly? E.g. if you register() in Activity.onResume(), are you calling unregister() in Activity.onPause().
Closing all activities does not kill your process. I.e. all registered classes are still there, you have to explicitly clean up and unregister from the event bus, or reuse them when the Activity comes back.
This is old, but just in case anyone has this problem also: Tread lightly when using EventBus inside dynamically generated things like Fragments or other classes; I didn't really understand why they were posting to the EventBus more than once, but I think it had to do with this (I had more than one dynamically generated Fragment). It worked normally once I put the register(), unregister(), onEvent() into the parent Activity code (which conveniently also uses onPause() and onResume()).
Same thing happening in my case when I am using the
EventBus.getDefault().postSticky(new Event("Hii !"));
for sending the event. The event is received multiple times when I come to that activity. So I fixed this by removing the event after receiving in onEvent method. This solved my problem. Used: removeStickyEvent(object)
#Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(Event event) {
/* Do something */
EventBus.getDefault().removeStickyEvent(event);
}
The problem was not that the event was actually fired multiple times, but that the handler was invoked multiple times. As seen in the code above, the bus.register method is called everytime I create the object; because of the activities lifecycle, this happened multiple times, causing the handler to be invoked multiple times.
I had a specific case that I want to share. Maybe it helps someone else.
While we are using a parent activity for all of our Activities in our project, we register and unregister EvenBus for each activity inside the parent class.
In one of our activities, we were calling EventBas before invoking the previous activity's EventBus. Then we had twice trigger
How can I stop my whole App in simple terms? (all activities, services, Threads, etc. simply everything) The life-cycle callbacks (especially onStop() and onDestroy()) should be called.
Google suggests the following possible solution:
kill the process: but this wouldn't call the lifecycle callbacks
and finish(); but this is only for one Activity:
But is it possible to access this method from outside like:
//Getting all activityies, how?
//For each gotten activity
AcitvityName.finish();
or via or via getParent().finish(); ?
This did not help me: Best way to quit android app?
FD
#Override
public void onPause() {
if(isFinishing()){
//code to finish() all activitys threads etc.....
}
super.onPause();
}
in onPause() you can check for isFinishing() and then if it is finishing it goes to onDestroy() so you can execute some code youd like
Use a broadcast receiver to call all your activities and call finish locally in them, invoking the current lifecycle callbacks.
Broadcastreceiver and Paused activity
http://developer.android.com/reference/android/content/BroadcastReceiver.html
Android don't allows user close application directly. You may minimize it to background or directly killing process.
But if you want to call some callbacks and release any resources when user remove your application from screen - you may to do following:
Clearing activity stack in onDestroy method (or if you wish in onBackPressed, onHomePressed). It must calls onDestroy methods in all removing activities so you may release any extended resources in onDestroy method of activity which has links on it.
So when user exit from your application - it will remove his activities and release all resources.
I have an Android activity we'll call A which has a button and another activity B. When the user clicks the button in Activity A, I'd like to finish A (let both onStop and onDestroy finish running) and then start up the instance of B. When I put a finish() and startActivity() call in the button click listener, the instance of B starts up before the old instance of A finishes. Can someone help me figure out a way to do what I'm looking for?
What you are looking for is not possible and actually is against Android's activity lifecycle implementation.
Correction
It is possible with android:noHistory="true" tag in your manifest, but for what you are trying to do it seems wrong (read the EDIT)... Messing with the activity stack makes a non intuitive application!
Android OS doesn't let you control when activities will be removed from memory (or killed), and therefore all these fancy "Task killers" are so popular (DONT use them, they only make things worse).
When your activity's onStop() is being called, the activity stops completely, and it just hangs in your memory, but that's fine...
If you want to reset the state of activity A, or close the app when exiting activity B, just create a set of rules in both onResume() and onStop(), you can do everything you wish by creating a set of rules in those functions.
for example: have a boolean in activity A that turns true just before calling activity B,call finish() on your activity A's if this boolean is true
I suggest that you take a look at Android's Activity lifecycle diagram, and make sure that everything you do follows the best practice.
EDIT
I saw your comment, it seems like you are trying to create things that are already in your memory, don't recreate them, it's a waste of CPU time, memory, and battery.
Instead, create a static class with a singleton that will hold all your shared data !
I believe you're looking for
onPause()
which is what gets called when the activity is sent to the background. You can do whatever cleanup you want in there. onStop should only be called when a user is exiting out of your program (or launching another one)
onPause is a better place to do this cleanup. See the Saving Persistent State section of the Activity doc.
When an activity's onPause() method is called, it should commit to the backing content provider or file any changes the user has made. This ensures that those changes will be seen by any other activity that is about to run. You will probably want to commit your data even more aggressively at key times during your activity's lifecycle: for example before starting a new activity, before finishing your own activity, when the user switches between input fields, etc.
While I'm not definite that your cleanup is for user changes, the bold sentence above implies that onPause will complete before the next Activity is created. Of course that probably implies that you'll have to move some setup to onResume...
Alternatively, you could move all your cleanup code to a method, let's just call it cleanup and then just call it before you start activity B. You'll have to put in appropriate guards for your onDestroy cleanup too of course.
override finish() method.
implement cleanUp() method.
create boolean isClean=false in the activity
in cleanUp() write your clean up code.
call cleanUp() in your finish()
check for isCleaned in finish() or in cleanUp() if its true then ignore the clean
now before you start B , call cleanUp() and set isCleand=true
after you call B , call finish()
Start activity A
from inside A startService(c) and finsh A
from inside the service , start Activity B
I have manager classes that take an activity as a listener. I use the managers to do threaded calls, work etc and then call back to the listener(activity) when things are done, need changed and so on.
I want to register and unregister the activity as a listener when it is no longer visible. This will prevent unwanted changes from happening (like dialogs appearing when the activity is no longer visible).
My question is, what lifecycle events are best to do this registering. I started with onPause() and onResume() which worked well except when I had an activity that was doing stuff in onActivityResult(). Since onActivityResult() gets called before onResume() my managers are not always registered in time.
Do I need to register in onResume() AND onActivityResult() or is there a better way to approach this?
An alternative approach may be to postpone the processing currently done in onActivityResult() until after the listeners are registered in onResume().
Possible ways of doing this include posting to the message queue, e.g. using a Handler, setting a Runnable object to be called by onResume, or simply storing the result data received by onActivityResult().
This would also ensure that the activity really has come to the foreground when the listener methods are called.
onResume() and onPause() are the best for this. The onDestroy(), per the documentation, is not guaranteed to be invoked though this is a favorite for many people, so stick with the pauses and resumes.
You can have the handle of the current Activity in the Manager class. Register its presence on onCreate() and unregister it on either onCreate() by some other Activity, or onBackPressed() of the current Activity.
On a related note, I would recommend an MVC (or similar) architecture where the controller has awareness of the view's status (the controller can track the onCreate() and onBackPressed() of each Activity).