I have implemented a Fragment and override its lifecycle callbackas as following:
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dactivity = getActivity();
dactivity.bindService(new Intent(dactivity,EventosDatabaseService.class), this, 0);
}
#Override
public void onDestroy() {
super.onDestroy();
dactivity.unbindService(this);
}
It is documented that onActivityCreated call must heppen prior to onDestroy, then how come i get NullPointerException thrown because dactivity is null on onDestroy? what should i do to avoid it while making sure the binding wont produce a leak?
BTW, the RetainInstance of this fragment is false if that metters
Try bind your service in Fragment.onResume with registering broadcast listeners if available, and use Fragment.onPause to unbind service and unregister listeners
I wish the image i posted could offer better understanding to figure out how fragments work.
Related
I'm brand new using Event Bus from otto lib, So far I created a Event Bus Singleton class, which I'm using in several parts of my code. Now I'm working on a fragment view, But I still have a question, regarding:
When is the best time to register/unregister my event bus?
In a couple of posts I read that onStart() and onStop(), but without any specific reason why.
public class SomeFragment extends Fragment {
#Override
public void onStart() {
super.onStart();
EventBusSingleton.register(this);
}
#Override
public void onStop() {
super.onStop();
EventBusSingleton.unregister(this);
}
}
If I follow the same approach as in the activities doing the call onResume() and onPause() works fine as well.
public class SomeFragment extends Fragment {
#Override
public void onResume() {
super.onResume();
EventBusSingleton.register(this);
}
#Override
public void onPause() {
super.onPause();
EventBusSingleton.unregister(this);
}
}
What could be the potential risk(if exist) from each call way?
onPause()/onResume() is called when your activity does not have the focus anymore but could still be visible (think a dialog or alert on top of your activity).
onStop()/onStart() is called when your activity is not visible anymore.
Which one to use depends your use case. I believe it's not really a problem to have callbacks executed while in the paused state so I would just put the register/unregister in onStop()/onStart() but if you really want to make sure, you can put them in onPause()/onResume().
My problem was what my fragmets had two instances for bad coding, y delete de uneccesary instance and it solve the problem
I have a Fragment with a ListView and a BroadcastReceiver that updates the ListView when new data arrives. The Fragments life is controlled by a ViewPager.
In regard to where to (un)register the BroadcastReceiver, I found several places suggesting to do it in
onResume():
refreshReceiver = new RefreshReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
refreshReceiver,
refreshIntentFilter);
onPause():
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(refreshReceiver);
However, this does not work properly. When I long-press the home button to get to the Recent apps screen, onPause() is called. When new information comes in while I'm on Recent apps, the ListView misses the update and shows old information after I go back there.
Now I was thinking about moving the unregistering to the onStop() method (or even in onDestroy()), but is that guaranteed to be called when the fragment is destroyed? I was worried because if the BroadcastManager holds a reference to the BroadcastReceiver and that in turn holds a reference to the Fragment, it would be quite a serious memory leak.
if you don't need receiver, then unregister it. if you use it only in that fragment, you may consider unregistering it onViewDestroyed().
According this answer , if your fragment is single and not in pager you can un/register LBM in :
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
broadcast_manager, new IntentFilter("filter"));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcast_manager);
}
Else you need to find out when fragment is visible then register LBM.
through this:
public class MyFragment extends Fragment {
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
// Register LBM
}
}
// ...
}
you can register LBM in fragment
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
notify("onCreate");
}
#Override
protected void onPause() {
super.onPause();
notify("onPause");
}
#Override
protected void onResume() {
super.onResume();
notify("onResume");
}
#Override
protected void onStop() {
super.onStop();
notify("onStop");
}
#Override
protected void onDestroy() {
super.onDestroy();
notify("onDestroy");
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
notify("onRestoreInstanceState");
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
notify("onSaveInstanceState");
}
I'm if right, these are the methods to handle the life cycle of an activity. My question is, do you need to put these methods in each class if you want to handle your app life cycle properly, or just in the main class?
They have to be implemented once per activity. The code of one activity won't be used in anotherone unless the second is a subclass of the first.
As an additional note, only onCreate must be implemented, the others are optional.
You only need to override the methods that you want to use.
If you don't need to perform any special functions in onDestroy(), for example, you don't need to override it in any of your Activities.
A good way to identify whether or not you need it is to look at what you have in those methods. If all you are doing is calling super, then you don't need to include that method in your Activity because the default behavior will work just fine for you.
If you want your app to develop some certain behavior that can be applied to some specific part of the life cycle you have to put those methods in each class Activity. Because of the inheritance that a class have if you want some specific behavior through all the app I recommend you to use the Application class that modifies all the subsequent Activities the only problem is that not all the normal methods of an activity life cycle are available.
Here is some reference about lifecycle in Application class:
https://www.inkling.com/read/programming-android-mednieks-1st/chapter-11/life-cycle-methods-of-the
The best example of the method you always have to override is onCreate() because here is where you add all the normal start up behavior of the views and logic in your activity.
If you are not very well acquainted with android life cycle I do not recommend you to override these methods because they can lead you to strange behavior in your app, that is for my personal experience.
Iam little bit amazed with this.I have an onResume() in my activity.Its called and works well in my emulator, but in a physical device samsung galaxy note for specific with jellybean installed,its not called.Instead onCreate() is called all the time.Why this happens?
public void onResume(){
super.onResume();
if(firsttime){
try {
Toast.makeText(getApplicationContext(), "Resuming Activity",Toast.LENGTH_LONG).show();
addReminder();
} catch(Exception exception) {
exception.printStackTrace();
}
} else {
firsttime=true;
}
}
This is my code.firsttime is a static boolean variable.It is used to prevent onResume() being called when app is started for the first time
Considering your current scenario, you should save variable in preferences instead of relying on activities lifecycle since lifecycle depends on many things.
Using static variable for this scenario is bad choice in general.I think this should solve your problem.
Try to print something inside the onResume and check it in LogCat.... the code inside onResume may be causing this.
or else can you elaborate your question?
I think here is what happens,
when your app not the Top app, the activity manager actually destroy the activity, it only called
public void onSaveInstanceState(Bundle savedInstanceState)
no
onStop
called, so no
noResume
will be called.
The correct to do this is, when put all states of this activity when
public void onSaveInstanceState(Bundle savedInstanceState)
called.
and in your onCreate() function, do such thing
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
to check if you have some saved state.
Most code was copy from android developer site:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
I am using Otto 1.3.3 and when I resume my application sometimes I get an IllegalArgumentException with the following stacktrace:
Caused by: java.lang.IllegalArgumentException: Producer method for type class
com.couchsurfing.mobile.ui.setup
.SessionProviderFragment$SessionConnectionStateChangeEvent found on
type class com.couchsurfing.mobile.ui.setup.SessionProviderFragment,
but already registered by type class
com.couchsurfing.mobile.ui.setup.SessionProviderFragment.
at com.squareup.otto.Bus.register(Bus.java:194)
at com.couchsurfing.mobile.ui.BaseRetainedFragment
.onCreate(BaseRetainedFragment.java:20)
The SessionProviderFragment has its instance retained, please find below the extended class:
public abstract class BaseRetainedFragment extends SherlockFragment {
#Inject
Bus bus;
#Override
public void onCreate(final Bundle state) {
super.onCreate(state);
((CouchsurfingApplication) getActivity().getApplication()).inject(this);
setRetainInstance(true);
bus.register(this);
}
#Override
public void onDestroy() {
super.onDestroy();
bus.unregister(this);
bus = null;
}
}
I tried both using bus.register(this) in onAttach() or onCreate(), that didn't change the issue.
The proper place to register on the bus is in onResume() and the proper place to unregister is in onPause() like so:
public abstract class BaseRetainedFragment extends RoboSherlockFragment {
#Inject private Bus bus;
#Override
public void onCreate(final Bundle state) {
super.onCreate(state);
setRetainInstance(true);
}
#Override
public void onResume() {
super.onResume();
bus.register(this);
}
#Override
public void onPause() {
super.onDestroy();
bus.unregister(this);
}
}
Note that onDestroy() is not guaranteed to be called.
You might be about to comment on this and say, hey Chris, if I register in onResume() and and events are fired before I hit this method I won't receive the events! You would be right, but this means you aren't using Producers like you should be.
Also note, if you use roboguice-sherlock you don't have to inject yourself. You also don't need to null the Bus when the Fragment goes out of scope the garbage collector will clean it up for you.
I've used Otto and EventBus mostly to pass updates from background services to Activities and Fragments. I don't know your exact use case, but the most common use for me was to update the UI (e.g. ProgressBar, status message, etc).
Having said that, what I've found as most efficient, is to register the bus in the onViewCreated() method of the fragment and unregister it in the onDestroyView() method. Provided that the bus messages are persistent (via a provider for Otto or sticky events for EventBus), you will not lose any messages this way.
I am using one "Retained Fragment" per activity to save the state of an HTTP session request. My issue was that I didn't instantiate my "Retained Fragment" the proper way.
Before I had in onCreate():
if (savedInstanceState == null) {
sessionProviderFragment = new SessionProviderFragment();
getSupportFragmentManager().beginTransaction().add(sessionProviderFragment,
SessionProviderFragment.TAG).commit();
}
Apparently the code above could create several SessionProviderFragment when quitting the activity is reopening it later.
It seams that the correct way is :
sessionProviderFragment = (SessionProviderFragment) getSupportFragmentManager()
.findFragmentByTag(SessionProviderFragment.TAG);
// If not retained (or first time running), we need to create it.
if (sessionProviderFragment == null) {
sessionProviderFragment = new SessionProviderFragment();
getSupportFragmentManager().beginTransaction().add(sessionProviderFragment,
SessionProviderFragment.TAG).commit();
}
if (savedInstanceState == null) {
initUiFragment();
}
I also moved the bus register/unregister in onResume/onPause in my BaseFragment to be sure that I will always have one SessionProviderFragment registered on the bus at a time.
It's not really safe to have an #Produce on a Fragment, because more than one instance of the fragment can exist (and be registered on the bus) at the same time.
In my opinion #Produce really only makes sense on a singleton.