How to get LifecycleOwner in a Fragment? - android

I need to get the LifecycleOwner to pass it in my FirestoreRecyclerViewOption but Fragment doesn't implement Lifecycle.
So, how to get that?
My Fragment implements LifecycleOnwer as shown in the following code example,
public class ListRestFragment extends Fragment implements LifecycleOwner
after in the onCreateMethod,
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
and to finish
#Override
public void onStart() {
super.onStart();
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
}
#NonNull
#Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
I follow this example
but it doesn't work
Attempt to invoke virtual method 'androidx.lifecycle.Lifecycle$State androidx.lifecycle.Lifecycle.getCurrentState()' on a null object reference
I need it to edit My FirestoreRecyclerViewOption and setLifeCycleOwner because it is always null and I have an NullPointer everytime.

In fragments you can use getViewLifecycleOwner() method to get the lifeCycleOwner.

Update: Actually it is better to use getViewLifeCycleOwner if you are using views in your observers. Because the view might not exist when the LiveData gets updated and you want to change the view(e.g. changing visibility of a view) which causes crashes.
The fragment itself is the LifecycleOwner you are looking for. You can use keyword "this" as a reference to the fragment.
Read this: "Lifecycle
is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state."
And:
"LifecycleOwner is a single method interface that denotes that the class has a Lifecycle."

Related

Can you access a ViewModel from a custom class (non-activity/fragment)

I am creating a Listener class that a couple instances of a custom button in different Activities/Fragments are using. This class has listener methods that will update the respective ViewModel for that Activity/Fragment.
How do you define a ViewModel in a non-activity/fragment class? The documentation says to implement ViewModelStoreOwner, but I'm not really sure on how and what I should be implementing. I'm assuming if I don't implement it correctly, I'll have some sort of memory leak...
public class Listeners implements View.OnClickListener, ViewModelStoreOwner {
#NonNull
#org.jetbrains.annotations.NotNull
#Override
public ViewModelStore getViewModelStore() {
return // what do I do here, and how do I tell it to close the scope appropriately
// when the context is destroyed?
}
// Implement OnClick...
}
Am I just trying to abstract too much here? Does Android really just revolve around Activities and Fragments thus requiring me to have annoyingly long files? The above class is my attempt to reduce redundant implementations of a button listener between two activity/fragments
EDIT:
Is it wrong to just pass the store owner of the activity that this listener instance will eventually reside in? For example:
// Custom class constructor
public Listeners(ViewModelStoreOwner storeOwner) {
mModel = new ViewModelProvider(storeOwner).get(Model.class);
}
// Calling/parent activity/fragment/context
Listeners listeners = new Listeners(this);
mButton.setOnClickListener(listeners);
Unless someone posts an answer to this that says otherwise (and that this is a bad idea), I ended up utilizing the latter solution I updated my question with.
I passed the store owner into the custom Listener class as a parameter, then used this value to initialize my ViewModelProvider inside the custom class.
I believe this is safe, since the class is instantiated within the scope of that parent Fragment/Activity anyway.
So for instance, if you were calling this class from an activity/fragment:
// Calling from Activity
Listeners listeners = new Listeners(this);
// Calling from Fragment
Listeners listeners = new Listeners(requireActivity());
And the relevant class definition:
public Listeners(ViewModelStoreOwner storeOwner) {
mModel = new ViewModelProvider(storeOwner).get(Model.class);
}

When does a LifecycleRegistry instance start listening to LifecycleOwner's lifecycle changes?

I've started learning architecture components, but can't find one thing.
LifecycleFragment just creates a new LifecycleRegistry object, which does not start observing the fragment's lifecycle.
I guess the LifecycleRegistry object starts listening to the fragment's lifecycle when we, for example, put it into LiveData.observe() as first param, but I haven't found any proof of this in source code.
Question: When and how does a LifecycleRegistry object start to observe a fragment's lifecycle and refresh LifecycleRegistry.mState?
There is a ContentProvider called LifecycleRuntimeTrojanProvider that is merged into the app's AndroidManifest.xml. In its onCreate method it initializes a singleton called LifecycleDispatcher, which is responsible for updating all LifecycleRegistry instances.
LifecycleDispatcher uses the Application.registerActivityLifecycleCallbacks method that has been around since API 14 to get notified when a new activity is created. At this point it injects an instance of ReportFragment into the activity. The ReportFragment uses the Fragment lifecycle callbacks to update the activity's LifecycleRegistry if necessary, like this:
#Override
public void onStop() { // Showing onStop as example
super.onStop();
dispatch(Lifecycle.Event.ON_STOP);
}
private void dispatch(Lifecycle.Event event) {
if (getActivity() instanceof LifecycleRegistryOwner) {
((LifecycleRegistryOwner) getActivity()).getLifecycle().handleLifecycleEvent(event);
}
}
If the new activity is a FragmentActivity, the LifecycleDispatcher calls FragmentManager.registerFragmentLifecycleCallbacks to get notified of the activity's fragments lifecycle events. It relays the onFragmentCreated, onFragmentStarted and onFragmentResumed callbacks to the LifecycleRegistry in case the fragment is a LifecycleRegistryOwner, in the same way as before.
The onFragmentPaused, onFragmentStopped, and onFragmentDestroyed callbacks are called after the corresponding callbacks are called on the fragment, but the LifecycleObserver callbacks must be called before. So whenever a fragment is created, the LifecycleDispatcher injects an instance of LifecycleDispatcher.DestructionReportFragment into it. The DestructionReportFragment's lifecycle callbacks are used to update the registry for the pause, stop and destroy events.
I can't link to the code because it hasn't been released yet, but you can browse it in Android Studio after you add the library to your project.
As Mordag said, as of now, both the LifecycleActivity and LifecycleFragment are not yet implemented. In their documentation Google says:
Any custom fragment or activity can be turned into a LifecycleOwner by implementing the built-in LifecycleRegistryOwner interface (instead of extending LifecycleFragment or LifecycleActivity).
However, that is only half the story, because naturally you are using these Lifecycle Aware components to be able to react to your Activity/Fragment lifecycles and with their code snippet it just doesn't work, because initialising a LifecycleRegistry with the Activity/Fragment like this
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
only gets you a Lifecycle in the INITIALIZED state.
So, long story short, in order for this to work right now (BEFORE their 1.0-release) it is you who have to implement the Lifecycle of the Activity/Fragment that implements the LifecycleRegistry. So, for each callback of the Activity/Fragment you need to do this:
public class ScoreMasterFragment extends Fragment
implements LifecycleRegistryOwner {
private LifecycleRegistry lifecycle;
#Override
public LifecycleRegistry getLifecycle() {
return lifecycle;
}
public ScoreMasterFragment(){
lifecycle = new LifecycleRegistry(this);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//more code here
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
#Override
public void onStart() {
super.onStart();
//more code here
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
}
#Override
public void onResume() {
super.onResume();
//more code here
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
#Override
public void onPause() {
super.onPause();
//more code here
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
#Override
public void onStop() {
super.onStop();
//more code here
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
}
#Override
public void onDestroy() {
super.onDestroy();
//more code here
_lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
This will likely be in the code of the future LifecycleActivity and LifecycleFragment, but until then, if you put your Activities/Fragments observing some LifecycleAware object (like LiveData) you will have to do this.
In the case of LiveData, because it will not notify its observers unless they are at least in the STARTED state and in other cases because other LifecycleAware components cannot react to a Lifecycle if its only state is INITIALIZED.
The LifecycleFragment and LifecycleActivity are currently not fully implemented. Those classes will be implemented when the lib is reaching 1.0-release. Currently you can use those LifecycleRegistry to observe LiveData objects. Those objects are based on a future result which could e.g. be an object from your database.
The official documentation can be found here: https://developer.android.com/topic/libraries/architecture/index.html
Official statement regarding the two classes you mentioned:
Lifecycle Fragment and ActivityCompat in the Support Library do not
yet implement LifecycleOwner interface. They will when Architecture
Components reaches 1.0.0 version.
LifecycleActivity ,LifecycleFragment and LifecycleRegistryOwner interface are deprecated in API level 1.0.0. Use android.support.v7.app.AppCompatActivity and android.support.v4.app.Fragment instead of it.
Official documentation here LifecycleActivity LifeCycleFragment

Dynamically change ViewpagerIndicator Fragment Content Android

I am working on an application using viewpagerindicator.
In my main activity that has the viewpagerindicator, I spin off a thread that does some computation and updates a an instance variable mString of the activity. I want to update a fragment in the viewpagerindicator with the mString. However, I can't seem to figure out the best way to reach the fragment.
Does anyone know of any good samples that do something similar to this?
Create a callback object in your Fragment, register it with your FragmentActivity. If mString is already set in FragmentActivity then you can return it immediately via the callback, otherwise, when the computation thread finishes, it can return the string via the callback. The callback method should do whatever the Fragment needs to do with the string, e.g. set the text of a TextView.
E.g. create an interface called DynamicDataResponseHandler as follows:
public interface DynamicDataResponseHandler {
public void onUpdate(Object data);
}
Then in your Fragment, implement that interface as follows:
private class MyStringDataResponseHandler implements DynamicDataResponseHandler {
#Override
public void onUpdate(Object object) {
mYourTextView.setText((String)object);
}
}
Your Fragment can then instantiate a MyStringDataResponseHandler object in its onCreate, pass that to the FragmentActivity via a method in the FragmentActivity like:
private MyStringDataResponseHandler mMyStringDataResponseHandler;
public void registerMyStringDataResponseHandler (DynamicDataResponseHandler callback) {
mMyStringDataResponseHandler = callback;
if(mString != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
}
And wherever in your Handler you obtain the value for mString, do something like this:
if(mMyStringDataResponseHandler != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
Do some reading on the concept of Callbacks to get a better understanding of what I'm doing above and other ways you can use them.
You want to update the UI of a Fragment in ViewPager after it is started, do i make it clear?
Ok, in this situation
You should add a public method in your custom Fragment.
Find the Fragment in your Activity.
Invoke the method after your calculation is done.
The question is same with this one.

How to pass reference to an observer to a Fragment

I have following problem:
I have a MenuListFragment class which derives from class Fragment. MenuListFragment has a reference to an observer. Observer is informed when user pressed a row in a ListView.
How can I pass observer to object of Fragment class. Currently I do it by MenuListFragment constructor.
public MenuListFragment(MenuListObserver observer) {
mObserver = observer;
}
Unfortunately my app crashes when I rotate the phone. I know this is because of not having default constructor, but what can I do??

Call Activity Method From Fragment

I'm dealing with fragments.
I have an Activity and different fragments.
Each fragment need the access to a Class(call it X) that allow it to access a database, but, because I have a lot of fragments, I don't want to create a different instance of the Class X in every fragment as I think it will require lots of memory.
So how can I do?
I wrote something like this (with a getter), but it doesn't work!
public class MyActivity {
private ClassX classx;
.....
public ClassX getClassX() {
return classx;
}
.....
}
But than, how can I call it from the fragment?
From the fragment call your activity's method
((MyActivity ) getActivity()).getClassX() ;
This is a little bit more of a Java question and android.
If you looking at accessing the database, look at creating a database singleton.
So something like:
public class Database {
// This starts off null
private static Database mInstance;
/**
* Singleton method, will return the same object each time.
*/
public static final Database getInstance() {
// First time this method is called by Database.getInstance() from anywhere
// in your App. It will create this Object once.
if(mInstance == null) mInstance = new Database();
// Returns the created object from a statically assigned field so its never
// destroyed until you do it manually.
return mInstance;
}
//Private constructor to stop you from creating this object by accident
private Database(){
//Init db object
}
}
So then from your fragments and activities you can then place the following field in your class's (Better use use a base activity and fragment to save you repeating code).
public abstract class BaseFragment extends Fragment {
protected final Database mDatabase = Database.getInstance();
}
Then your concrete fragments can extend your BaseFragment e.g. SearchListFragment extends BaseFragment
Hope this helps.
Worth reading about singletons and database
Regards,
Chris
Define an interface called Callbacks (or something else if you want). In it, have a public method called getClassX(). Then make your Activity implement the Callbacks interface.
In your Fragments, in onAttach, store a reference to a Callbacks object (i.e. your activity via something like:
if(activity instanceof Callbacks)
mCallbacks = (Callbacks)activity;
This will guarantee that the Fragments are able to call the function. (in case you want to reuse the fragments later in another app)
Then in your Activity, in onCreate(), create an instance of ClassX. In your getClassX() method, just return a reference to it.
When you want a reference to it from your Fragments, call mCallbacks.getClassX() and you should be sorted.
You can use a static object in your activity, and use it from the fragment, or call the getActivity() method in your fragment to access the whole activity objects/methods

Categories

Resources