How to pass reference to an observer to a Fragment - android

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??

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);
}

How to update view in a method in called from another class?

In class A a have a method that updates a view.
First I called Class b to download some data, once the data is recieved I call the method in class A.
When the view is updated (when the method is called from class b) the view is throws NPE.
However if the view is updated (when called from its native class (class A)) it works perfectly.
Class A is an activity.
In some cases it reported there is some sort of context problem.
I have tried implementing an interface however even that threw an NPE
How can I fix this problem?
public class A extends activity {
public() {
}
B b = new B();
b.doSomething();
public void myMethod(String string) {
textView.setText(string)
}
}
public class B {
public void doSomething() {
String data = getData;
A a = new A();
a.myMethod(data)
}
}
You should not call new A(). This will not invoke a new Activity with the application lifecycle, and will not provide you a reference to the original Activity that contains the View you are trying to update.
I would recommend A should implement a simple interface YourInterface that contains a void callbackMethod(String data);.
Pass your object A (as this) into B, such as on doSomething(this), changing the signature of doSomething to doSomething(YourInterface callback).
In B you may then call callback.callbackMethod(data), processing data within your Activity A.

when changing singleton fragment, recyclerview has this status?

I'm using singleton fragment. I thought when I call this singleton fragment, the lifecycle methods onCreateView and onActivityCreated will be called only once. But they aren't even though the fragment is singleton, onCreateView and onActivityCreated are called when I call fragment. But I found something strange. That is, the RecyclerView is holding it's position. If I move A frag(using RecyclerView, position at 20) to B frag and redirect to A frag, the A fragment position is 20. Although onCreateView and onActivityCreated are called again, Why the A fragment position is saved?
ps: I know kotlin support singleton class "Objcet". But I'm more comfortable using singleton constructor than object class.
MainActivity
navigation_view.setNavigationItemSelectedListener {
drawerLayout.closeDrawer(GravityCompat.START)
when(it.itemId){
R.id.scheduleFragment->{
changeFragment(scheduleFragment)
}
R.id.noticeFragment->{
changeFragment(NoticeFragment())
}
}
true
}
}
fragment
companion object {
var scheduleFragment: ScheduleFragment? = null
}
fun getInstance(context: Context): ScheduleFragment {
if (scheduleFragment == null) {
scheduleFragment = ScheduleFragment()
}
return scheduleFragment!!
}
Well, it's behaving exactly as expected. The recycler-view's view, position all are members to the fragment instance. So the values remain same as it has only single instance. But the life cycle methods have nothing to do with the fact that the fragment class is singleton. They get called when the specific event happens. For example, when the activity is created then the onActivityCreated method get called by the system and this method calling has nothing to do about the fragment instance creation. Because the fragment instance creation happens earlier when you make an instance of fragment. Now after the use either you want to keep the instance or destroy it, it's your choice. Hope this will clear your confusion. Let me know if you don't understand anything.

How to get LifecycleOwner in a Fragment?

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."

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