I have an Activity, which is going to switch among various different Fragment views from time to time. In my Activity code, let's say I have
#Override
public void onStart() {
super.onStart();
... // The rest of your onStart() code.
EasyTracker.getInstance().activityStart(this); // Add this method.
}
#Override
public void onStop() {
super.onStop();
... // The rest of your onStop() code.
EasyTracker.getInstance().activityStop(this); // Add this method.
}
In every Fragment code, do I need to have?
EasyTracker.getInstance().setContext(this.getActivity());
Do I need to call EasyTracker.getInstance().setContext in Fragment?
Not necessarily. It depends on where you are using the EasyTracker in your Fragment. If your Activity's onStart() method has been called before you use the EasyTracker, then you will be fine and EasyTracker will use the Activity's Context.
However, if your Fragment uses the EasyTracker before the Activity's onStart() finishes (for example in onCreateView() or the Fragment's onStart()), then the EasyTracker will not have a Context yet and you will get an exception.
Related
I have a BaseFragment which within it's onCreateView method, creates a MyObject class. Both of these are inside a ViewPager.
Two different fragments extends from the BaseFragment - FragmentA, FragmentB.
This means FragmentA and FragmentB both have their own instances of the MyObject object.
Within the BaseFragment, I call myObject.initialise(); on the MyObject object from the onStart(); method and cleanUp(); from the onStop();
#Override
public void onStart()
{
super.onStart();
myObject.initialise();
}
#Override
public void onStop()
{
myObject.cleanUp();
super.onStop();
}
Again - this lives inside the BaseFragment so both FragmentA and FragmentB have this in their lifecycle.
The initialise(); function and cleanUp(); functions look like this:
#Override
public void initialise()
{
BusManager.register(this);
}
#Override
public void cleanUp()
{
BusManager.unregister(this);
}
FragmentA will generally close first and it successfully unregisters. When FragmentB closes however, it crashes because it think this was not registered.
I checked the memory address of this and it appears that it tries to unregister the same thing twice.
Missing event handler for an annotated method. Is class com.example.app.MyObject registered?
Why is it doing this? I have made sure that MyObject is a new instance.
For the comment above, note that onDestroy() is not necessary called:
https://developer.android.com/reference/android/app/Activity.html#onDestroy()
You should not count on that for Otto's register / unregister call.
In regarding to Subby's question: I've had scenarios where onStart() / onStop() being called twice. What I ended up is placing a try-catch block. Definitely not a clean solution, but that's how I do before finding out why the lifecycle is messed up.
I tried several times to invoke Resume method of MainActivity from the Fragment,
calling simply onResume(); nothing in result.
code for resume method
protected void onResume() {
all.clear();
outgoing.clear();
incoming.clear();
getFromSdcard();
super.onResume();
}
I want to call this method from fragment.
Enhancing #cricket_007 response :
You can invoke onResume from the parent Activity, but just like you have seen, onResume has protected access blocking you from calling it.
There is a small visibility workaround that allows you to do it.
1 - Implement this method on your activity
public void myOnResume(){
this.onResume();
}
2 - Then on your fragment you can invoke
public void myFragmentMethod(){
// make sure to double check casts (to YourActivity) like these before invoking
((YourActivity) getActivity()).myOnResume();
}
Conclusion and recommendation : Even though it is not recommended that you implement it this way, it can be done like I said.
In my opinion, what you should do is :
1 - Have all the functionalities of your onResume() method inside a proper method of your own (you name it!) like :
public void clearData() {
all.clear();
outgoing.clear();
incoming.clear();
getFromSdcard();
}
2 - Then you could just separate all these functionalities from onResume() and still have them invoked like
protected void onResume() {
super.onResume();
clearData();
}
3 - Invoke it on your fragment like (previously shown)
public void myFragmentMethod(){
// make sure to double check casts (to YourActivity) like these before invoking
((YourActivity) getActivity()).clearData();
}
Let me know how it went.
Regards,
You are calling the Fragments onResume()
You can try getActivity().onResume(), but you really should make a method to do whatever code you need rather than explicitly call lifecycle methods.
Create an Interface
interface OnParentActivityResumed {
fun onActivityResumed()
}
implement the interface in the fragment
class MyFragment: Fragment(), OnParentActivityResumed{
override fun onActivityResumed() {
//[YOUR CODE WHEN PARENT ACTIVITY RESUMED]
}
}
on parent activity onResume add
override fun onResume() {
super.onResume()
myFragment.onActivityResumed()
}
I know to pass back something from a fragment to its calling activity you can use onAttach which has the "activity" parameter. You can set the activity to variable and call an interface on it later. So passing data from the fragment back to the activity. All great.
I would like to do the same thing but this time i have a standard fragment and I want to call a DialogFragment and then have the DialogFragment call back to the original fragment but I can't use onAttach is wants a Activity.
Anyone know the best way of doing this ?
Thanks
Obviously you could just make things public in your activity and set them from your fragment. But then you have to keep references to your activity, and possibly have unwanted public variables and/or setters.
You could use EventBus and you would not need any of that.
In your activity you need to register an event
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(MessageEvent event){
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
Then you can simply call your event from your fragment or anywhere you like,
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
Some more information on EventBus can be found here
And another possibly useful tutorial.
One way to contact another fragment from there is to access it in the implemented method in your Activity:
//In your Activity...
#Override
public void callbackFromFragmentA(){
FragmentB fragment = (FragmentB) getFragmentManager.findFragmentById(android.R.id.content);
if (fragment != null) {
fragment.callFragmentMethod();
}
}
I have a custom component which extends LinearLayout, I need to execute certain statements when Layout is destroyed or removed. (or about to be removed)
One way is to check for onPause() or onDestroy() of an activity and call methods of the custom component. But I want to remove that overhead from the activity.
So that custom component itself can handle when layout is detached. But I dint find the suitable method to override (to detect the event) when layout is removed. Is there a way to handle this, or we need to use onPause() and onResume() method of activity ?
I had success overriding the onAttachedToWindow() and onDetachedFromWindow() methods:
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// View is now attached
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// View is now detached, and about to be destroyed
}
You can have your custom view listen to its own eventss. I suggest using View.OnAttachStateChangeListener and listening to onDetach event.
#Override
void onViewDetachedFromWindow(View v) {
doCleanup();
}
It is dangerous to rely on the "destruction" of a layout to execute statements, as you're not directly in control of when that happens. The accepted way and good practice is to use the activity's lifecycle for that.
But if you really want to tie your component to that lifecycle, I suggest your component implements an interface (something like Removable), and do something like that in your base activity classe (that all your activities extend):
protected Set<Removable> myRemovableItems = new HashSet<Removable>();
#Override
public void onPause() {
super.onPause();
for (Removable removable : myRemovableItems) {
removable.remove();
}
}
The interface:
public interface Removable {
void remove();
}
Then each time you add one of your custom component from an activity, you add the component to the internal set of Removable of the activity, and its remove method will be automatically called each time the activity is paused.
That would allow you to specify what to do when onPause is called within the component itself. But it wouldn't ensure it's automatically called, for that you'll have to do it in the activity.
Note: you can use onStop instead of onPause depending on when you want the removal to occur.
I am trying to use flurry for my android app. It says that i should put flurry code in onStart() and onStop() methods. I dont have these methods in my code. I have two activities and both use onCreate() and onDestroy() methods only. Can i put flurry code in that? Will there be any problem with it?
onStart() and onStop() are methods that handle part of an activity lifecycle, so you can add them to your activities without any problem.
#Override
protected void onCreate(...) {
super.onCreate(...);
...
}
#Override
protected void onStart() {
super.onStart();
FlurryAgent.onStartSession(this, "your_key");
}
#Override
public void onStop()
{
super.onStop();
FlurryAgent.onEndSession(this);
}
onStart and onStop are existing methods on an Activity, just like onCreate. If you want to add functionality at these points of the activity lifecycle, you can override them just like you did for onCreate.
public class MyActivity extends Activity {
#Override
protected void onStart() {
super.onStart();
FlurryAgent.onStartSession(this, "FLURRYKEY");
}
#Override
public void onStop()
{
FlurryAgent.onEndSession(this);
super.onStop();
}
}
onCreate and onDestroy are not an appropriate pair of methods to use for Flurry session tracking because onDestroy is not guaranteed to be called. See the documention on onDestroy. You can end up with situations where the app gets killed by the system and Flurry will think the session is still going.
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.