It seems to me that there must be a bug in the Android Fragments demo.
As background, Fragments are apparently sometimes instantiated by the Android OS and thus need a public no-arg constructor:
All subclasses of Fragment must include a public empty constructor.
The framework will often re-instantiate a fragment class when needed,
in particular during state restore, and needs to be able to find this
constructor to instantiate it. If the empty constructor is not
available, a runtime exception will occur in some cases during state
restore.
But the NewsReader demo from the official Android training on Fragments constructs the HeadlinesFragment class and configures it with setOnHeadlineSelectedListener(this) from NewsReaderActivity.onCreate().
If the Android OS re-instantiates this fragment, the mHeadlineSelectedListener field will be null because HeadlinesFragment doesn't save or restore its state. It can't anyhow, because I believe it's impossible to persist a reference to an Activity.
Furthermore, I noticed that the Fragment documentation states:
It is strongly recommended that subclasses do not have other
constructors with parameters, since these constructors will not be
called when the fragment is re-instantiated; instead, arguments can be
supplied by the caller with setArguments(Bundle) and later retrieved
by the Fragment with getArguments().
On the other hand, it seems they perform instantiation and configuration (sort-of) correctly in the preceding FragmentBasics example. I say "sort of" because for some reason they directly instantiate the HeadlinesFragment rather than via SupportFragmentManager, as is done in the NewsReader demo. Regardless, they don't make the apparent mistake of calling a setter in HeadlinesFragment from MainActivity, but instead let HeadlinesFragment take responsibility for finding the OnArticleSelectedListener, where it does so during onAttach().
Is this a bug in the NewsReader example or am I missing something? In the meantime, I've submitted an Android documentation issue.
Related
When I checked lifecycle of fragment I found something that I do not understand.
FragmentHostCalback
Fragments may be hosted by any object; such as an Activity. In order to host fragments, implement FragmentHostCallback, overriding the methods applicable to the host.
Question
Where created FragmentHostCallback in Fragment?
I think FragmentHostCallback created at onInflate or onAttach. However, I couldn't find any code related to creating FragmentHostCallback there.
Fragments themselves don't host Fragments - as mentioned, it is an Activity or equivalent object that creates a FragmentHostCallback object. For example, FragmentActivity contains its own implementation of FragmentHostCallback called HostCallbacks.
You never interact with this object directly, rather, the FragmentHostCallback is passed to the FragmentController.createController(), which is what FragmentActivity, in this case, uses to trigger lifecycle changes and other signals from the Activity to the FragmentManager that you actually interact with.
The activity is protected for encapsulation within the framework package android.app and subclasses according to this link so why are fragments lifecycle methods having a public access modifier?
put simply, that's because your activity (internally not by you) calls the functions like onCreateView()
or in a more abstract and reasoning explanation, because an activity can contain fragments and for fragment-activity communication.
public methods are needed to access functionalities like, findFragmentById(),
an activity can exist as an independent entity. the context is present which is a primary requirement for performing an US related operation in android. a fragment does not have a context of its own(the getActivity() method provides context in a fragment)
from the documentation
Though a Fragment's lifecycle is tied to its owning activity, it has its own wrinkle on the standard activity lifecycle. It includes basic activity lifecycle methods such as onResume(), but also important are methods related to interactions with the activity and UI generation.
EDIT:going by the similar methodology of the answer you linked, fragments (for backward compatibility) are also present as android.support.v4.app.Fragment . But the Activity class is only in android.app.So in order to ensure backward compatibility,the public methods are present in this case
I have an activity with a pager and a FragmentStatePagerAdapter inside (I need to swipe across many pages). As we all know, this adapter creates 3 fragment instances at a time, the one to be displayed, the previous and next ones.
My activity was working really nice using a fragment with only one constructor: it received 1 parameter. When testing, I started to get the infamous message:
Unable to instantiate fragment: make sure class name exists, is public,
and has an empty constructor that is public
The funny part is that this message only shows up right after orientation change, but the app just works if orientation remains still. So,
Why does it work when orientation does not change?
Why does it fail when orientation is changed?
What are the differences in activity an fragment life cycles when orientation changes vs activity just created?
Thanks a lot
is empty constructor really required?
Yes.
Why does it work when orientation does not change?
Because Android is not trying to recreate your fragments.
Why does it fail when orientation is changed?
Because Android is recreating your fragments.
When a configuration change occurs (e.g., orientation change), by default Android destroys and recreates your activity, and also destroys and recreates the fragments in that activity. The "recreates the fragments" part is why you need the zero-argument public constructor on your fragments. It is also used in other cases, such as with a FragmentStatePagerAdapter.
Or, to quote the documentation:
All subclasses of Fragment must include a public empty constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore, and needs to be able to find this constructor to instantiate it. If the empty constructor is not available, a runtime exception will occur in some cases during state restore.
The document of Fragment says:
All subclasses of Fragment must include a public empty constructor.
The framework will often re-instantiate a fragment class when needed,
in particular during state restore, and needs to be able to find this
constructor to instantiate it. If the empty constructor is not
available, a runtime exception will occur in some cases during state
restore.
http://developer.android.com/reference/android/app/Fragment.html
But this class doesn't have a empty constructor. Why doesn't this class have empty constructor?
https://github.com/google/iosched/blob/master/Wearable/src/main/java/com/google/samples/apps/iosched/iowear/fragments/SubmitFragment.java
Because its super class (the class it extends) has a constructor which is public, therefore it's by all the subclasses.
Because it won't be able to be easily recreated by the container in a Fragment transaction, these managed classes are encoraged to keep the default constructor. For instance, restoring the state of a fragment, which is performed automatically.
It is not forbidden by the structure, you can add other constructors if you want, for instance, for using them during Unit Tests, but ensure the keep the public default constructor available at application runtime.
Apparently, this code is wrong. But I don't know a lot about wearable-like device. Maybe the SDK work differently with wear-device.
The problem with no-empty constructor only appear when the system kill(save) an Activity and recreate it. It would like to create an instance of the Fragment but can't.
Given:
From a fragment, you can always call getActivity() to get a reference to the activity in context.
And of course, you can you can cast this instance to a strong type (like MainActivity) to get references to public properties and public methods on the activity.
My Question:
Is this bad form? Should it be avoided?
Specifically, should references to properties and methods on an activity be acquired via interfaces?
Or is it standard practice to expose public properties and methods to fragments from an activity?
should references to properties and methods on an activity be acquired via interfaces?
It helps future-proof your code, if the fragment might be hosted by some other activity later on (e.g., one activity used in a phone-sized form factor, a different activity used in a tablet-sized form factor). It is not that difficult to set up a contract interface.
is it standard practice to expose public properties and methods to fragments from an activity?
This seems to be the same question you just asked. Though note that whether they need to be public, or can remain package-private, depends on whether they are in the same package.
If I misinterpreted this second question, I apologize, but you might want to clarify it a bit.