Accessing the Activity from a Fragment - android

I'm trying to change the activity title from a fragment (in this case, it's an android.support.v4.app.Fragment). To this end, I save the activity in an attribute on the fragment when onAttach() is called on the fragment. According to the docs, onAttach() should be called before onCreateView(), which I'm using to request some data used to fill up the view. When I kick off the thread for the network retrieval, I want to indicate that in the title, so I'm trying to call this.activity.setTitle() from the Fragment. However, that keeps throwing a NullPointerException. What am I missing here?

You can access the Activity in a Fragment using getActivity(). It can be called safely as soon as onActivityCreated() was called on the Fragment. Before that, it might not be there or might not have been fully initialized yet.
If your thread starts before that, just note the fact somewhere in your Fragment and only change the title after onActivityCreated was called.

Nowadays you can call requiredActivity() too that return FragmentActivityobject and if fragment doesn't come from an Activity, method throws a IllegalStateException

Related

Is there any misunderstanding about the onActivityCreated fragment callback?

onActivityCreated seems to mean "This fragment callback is executed just after the activity has been... created... I mean, just after the fragment is correctly attached to the activity. There, you can safely call getActivity, it won't return null, except if the activity is null for some special reason".
However, I've seen that the fragment callback onAttach is called even after OnCreate, it means that the fragment has been attached to the activity, which has been created.
The complete workflow for a fragment (and for a fragment dialog, which is frequently left behind) is: onAttach -> onCreate -> onCreateView -> onActivityCreated. So in each of these 4 methods (perhaps not onAttach I don't know), the activity is normally not null and attached to the fragment.
So my question is: why does the callback onActivityCreated since the activity is, in fact, already created and attached to the fragment 3 callbacks ago???
So basically in onAttach() we get confirmation is that activity is attached to my fragment, I can use getActivity() to fetch things like resources like
getActivity().getResources.getDrawable(R.drawable.abc)
but Suppose if You want to fetch the views inflated in activity's xml like If you want to access
getActivity().findViewById(R.id.Myelement)
You might get null here, so OnActivtyCreated() ensures that activity's view is inflated, You can access activity's views now (Activity's view has been created (onActivityCreated))

Fragmentation, onRestart(), and Null Pointers -- What am I doing wrong?

I have 3 fragments that are contained within the main activity via a ViewPager. What I'm trying to do is allow myself to call methods on objects of those fragment classes from different lifecycle callbacks in the main activity, namely onRestart(), so that I can refresh their content via a backend call. To be more specific, one of the fragments contains a "live feed" of images that people are posting, and the user gets to this posting activity via one of the fragments.
Right now, the problem I'm trying to solve is that when a user goes to this posting activity and puts up a picture, the live feed in the fragment they come back to isn't getting refreshed. To do this, I would need to call my backend and UI update methods in that fragment from the main activity's onRestart().
But I'm running into these null pointer exceptions -- here's what the code looks like in the fragment:
public void refreshUI(){
activity = getActivity();
appContext = ThisApp.appContext();
view = getView();
peopleHeader = (TextView) view.findViewById(R.id.people_header);
peopleLinearLayout = (LinearLayout) view.findViewById(R.id.local_people_linearlayout);
..... (various other instantiations)... }
The NPEs are coming either from getActivity() or some of the UI instantiations. I call this code from onActivityCreated() and it works as expected. However, if I try to call this code again on my fragment object from onRestart(), I crash.
What's happening? Can't figure out why this would go bad on me.
Thanks so much.
When your Activity is destroyed and recreated, your Fragments are also destroyed and recreated with it. You can have a look at the Fragment/Activity lifecycle explanation here.
What this means is that the reference you keep disappears, the Fragment is there but it is another object. You need to get a reference to this new object.
You can check this answer on how to do that. It explains getting references to Fragments created by a ViewPager adapter.

what is the different between onCreate() and onCreateView() lifecycle methods in Fragment?

I don't know when to use onCreate() or onCreateView().
I have used onCreate() and onCreateView() lifecycle methods.
I think onCreate() for Activity and onCreateView() for Fragment. But I am not sure. Can I use onCreate() LifeCycle method in Fragment? I hope somebody can help me!
onCreate is called on initial creation of the fragment. You do your non graphical initializations here. It finishes even before the layout is inflated and the fragment is visible.
onCreateView is called to inflate the layout of the fragment i.e graphical initialization usually takes place here. It is always called some time after the onCreate method.
Activity lifecycle explained - http://developer.android.com/reference/android/app/Activity.html
Fragment lifecycle explained - http://developer.android.com/guide/components/fragments.html#Creating
Detailed lifecycle diagram - https://github.com/xxv/android-lifecycle
From documents :
onCreate
Called when the activity is starting.
This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, using findViewById(int) to programmatically interact with widgets in the UI, calling managedQuery(android.net.Uri, String[], String, String[], String) to retrieve cursors for data being displayed, etc.
You can call finish() from within this function, in which case onDestroy() will be immediately called without any of the rest of the activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
Link to documentation of onCreate
onCreateView
Called to have the fragment instantiate its user interface view. This is optional, and non-graphical fragments can return null (which is the default implementation). This will be called between onCreate(Bundle) and onActivityCreated(Bundle).
If you return a View from here, you will later be called in onDestroyView() when the view is being released.
Link to documentation of onCreateView

Beste practices with SetRetainInstanceState?

I'm currently having issues with fragment lifecycle management.
Should the activity the fragment is hosted in be recreated I have set SetRetainInstanceState(true) to keep the fragment instance alive.
However, this had lead to some strange behaviour regarding my views. Sometimes I get memory leak warnings concerning a few fragment views and nullpointer exceptions to the activity context.
Wanting to make sure the fragment instance is retained properly: what are best practices regarding the retaining of a fragment (what to keep, what to destroy)?
SetRetainInstanceState(true) makes sure Android retains the fragment while the activity is being recreated. Therefore the activity the fragment was first attached to is not longer there after activity recreation and the fragment is attached to a new activity instance.
To make sure this goes well keep the following things in mind:
Do not keep a reference to the attached activity in your fragment unless absolutely necessary. Use the getActivity() method instead which will always return the currently attached fragment (or null if nothing is attached).
If you absolutely have to have a "permanent reference" to the currently attached activity (in which you might want to rethink your design) make sure to update this reference in the onAttach and onDetach methods.
Make sure you retain no object that was initialized using the activity as a context (usually views, adapters and such). To do this, override the Fragments onDestroyView() method that gets called just before activity recreation. Here you can dispose of the views and adapters the fragment still has a active reference to (usually just setting their reference to null should be enough). You can then recreate the fragment's views and adapters using the new context in the onCreateView call.

onAttach activity is null

In creation of a fragment, I encountered getActivity() to be null.
So to narrow down the problem, I kept a local copy of activity in onAttach(Activity activity), which by definition is when it is attached to an activity.
However, I logged the activity in onAttach, and it is still null.
I'm only running into this problem in 2.3.6 and below.
Is this a known problem with support package?
The series of methods called to bring a fragment up to resumed state are:
onAttach(Activity) called once the fragment is associated with its activity.
onCreate(Bundle) called to do initial creation of the fragment.
onCreateView(LayoutInflater, ViewGroup, Bundle) creates and returns the view hierarchy associated with the fragment.
onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
onViewStateRestored(Bundle) tells the fragment that all of the saved state of its view hierarchy has been restored.
onStart() makes the fragment visible to the user (based on its containing activity being started).
onResume() makes the fragment interacting with the user (based on its containing activity being resumed).
The bold method should be the one where getActivity doesn't return null anymore.
the onAttach method should not be used to call methods of the activity object, It should be used to initialise callback interfaces. An example of these interfaces can be found here.
This problem is because of the support package it means the fragment are from android 3.0 and up that is API level 11 and UP so for sure you will face app crash for android 2.3.6 gingerbird
this.getActivity();

Categories

Resources