Call getFragmentManager() without extending Fragment - java

I have a class that is handling a database in my Android app. When the database changes, I'd like to update the fragment displaying the information from the frogment. My approach has been to give the fragment a tag and then find the fragment with the following code:
FragmentManager manager = getFragmentManager();
Fragment fragment = manager.findFragmentByTag("Schedule");
if (fragment instanceof ScheduleFragment){
ScheduleFragment fr = (ScheduleFragment)fragment;
fr.scheduleUpdated();
}
However, as long as my database class is not an extension of Fragment, the compiler refuses to recognise getFragmentManager(). To me it makes no sense to extend Fragment, as the database class is no fragment, but a simple helper class to manage the database. Is it possible to get a reference to my fragment without extending Fragment? Or is this bad practice and should be done in another way?
Also, is it possible to get a reference to the fragment from a static method?

try using a localBroadcast manager. when database changes laumch a Broadcast intent. registere this in "Schedule" Fragment and you can handle the database changes.
Refer to this link for more about LocalBroadcast Manager
how to use LocalBroadcastManager?
http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html

Related

Does findFragmentById take in a FrameLayout rather than a Fragment?

I'm new to the concept of Fragments
In the video I was watching, they used this piece of code:
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.my_container);
if(fragment == null){
fragment = new FragmentMain();
fragmentManager.beginTransaction()
.add(R.id.my_container, fragment)
.commit();
}
To create a Fragment via java.
In findFragmentById they passed in a FrameLayout(my_container) rather than a Fragment. I read in the docs that you can pass in a container id, but it confuses me how it will initialize it as a Fragment. How does this work?
Should I use FragmentManager? I read in the docs that it's deprecated.
Thanks!
In findFragmentById they passed in a FrameLayout(my_container) rather than a Fragment. I read in the docs that you can pass in a container id, but it confuses me how it will initialize it as a Fragment. How does this work?
You can think of the container as of a placeholder that can hold a fragment at a time; initially it has no fragment and in this case the if(fragment == null) will be met, so you can do a fragment transaction (So, the container layout now is replaced by a fragment view, which is another xml layout assigned to this particular fragment and returned by its onCreateView() callback.onCreateView() is one of fragment's lifecycle callbacks that get called by the system until the fragment is fully visible to the user in the placeholder.
Later on when you want this placeholder to hold another fragment, you can do the transaction again where it repeats the same thing with the new fragment, the placeholder will show up the layout of the new fragment, and the lifecycle methods of this fragment will get called
Should I use FragmentManager? I read in the docs that it's deprecated.
FragmentManger (from android.app package) and its getFragmentManager() are deprecated, and you should use FragmentManager (from androidx.fragment.app package) and getSupportFragmentManager() instead like you already did.
For more info you can have a look to FragmentManager doc and Fragment lifecycle.
It will look into the container with the given ID and give you the Fragment that is currently inside. At no point does findFragmentById initialize a Fragment, it will only look through existing ones, as the name suggests.
You should not use the native FragmentManager on new versions of Android, as it has been deprecated, but the FragmentManager from the AndroidX Fragment library, providing the same functionality.
See also: https://developer.android.com/guide/fragments/fragmentmanager

Passing data between Parent fragment and Child fragment

I'm struggling with a communication between 2 or more fragments
My application architecture looks like this:
MainActivity (Menu Drawer)
----> MealsFragment
----> ProfileFragment
----> StatsFragment
----> SportFragment
----> ContactUsFragment
(By clicking on menu drawer main_container is replaced with selected Fragment)
Earlier, I had single activities instead of fragments but I have read that I need to convert them into Fragments to correctly implement menu drawer (so I did it).
The problem is each of the activities had its own child-activities which were communicating with parents with using onActivityResult. Now I don't know how to do it with fragments.
The scenario is like this:
Open MealsFragment from MainActivity (it works)
Open AddMealFragment from MealsFragment (with data from MealsFragment), fill the form and then return all information provided there by user to MealsFragment
Use received data for further actions
I have already seen posts recommending using settargetFragment() and getTargetFragment() but I don't know how to do it and - what is more important - I don't know how to receive the data afterwards
I hope you are aware of how to do Fragment transactions, i.e. using Fragment Manager class to add or remove fragments from the backstack. If you don't know then it's a good idea to learn that first.
Now that you know how to add or remove fragments, passing data among them is a simple thing of all of that in fragment's Bundle that you can access in the receiver fragment. Here's an example:
class ConversationFragment : Fragment() {
companion object {
const val JOB_REQUEST_ID = "jobRequestId"
#JvmStatic
fun newInstance(jobRequestId: String) =
ConversationFragment().apply {
arguments = Bundle().apply { putString(JOB_REQUEST_ID, jobRequestId) }
}
}
}
In order to create ConversationFragment, I expose a newInstance method that the FragmentManager or any other entity can use to create one. However, they would need to pass a JOB_REQUEST_ID in order to create one. I simply put this id in a Bundle and pass it on to the fragment as its argument. On the receiver side(fragment), you can get a handle to this bundle and retrive the value:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
jobRequestId = it.getString(JOB_REQUEST_ID)
}
}

How to get onNewIntent() in a Navigation Fragment

I want to use Navigation component in my android project, in order to achieve this, I have refactored my app to be fragment-based, but it raises a problem that I don't know how to pass onNewIntent() in my MainActivity to my Navigation Fragments.
So MainActivity is a NavHost, to make it simple, saying that I have a fragment as the start destination, how can I get onNewIntent() inside this fragment from MainActivity?
UPDATE
Also, is there a way to get the reference of the current presented fragment, like the one currently held by NavHost?
On new intent , you can do something like
val navigationController = nav_host_fragment.findNavController()
if (navigationController.currentDestination?.id == R.id.fragmentA) {
(nav_host_fragment.childFragmentManager.fragments[0] as FragmentA).doSomething()
}
Here you can pass any values to the function doSomething()
You can use in MainAcitivy class this:
private Fragment fragment;
fragment = new FragmentTry();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentid, fragment)
.commit();

Parent fragment to Child Fragment communication

I have been searching and haven't found the best way for nested fragments to communicate with parent fragment. The Android documentation states that:
All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
Suppose I have a Gallery app, there is a ViewPagerFragment (parent) and ImageFragment(child) that is used to show images full screen when they are clicked. I need to pass an ArrayList of Files from my parent fragment to the child fragment. What is a proper way to do it?
1) Create a getter for the ArrayList in parent fragment and use the getParentFragment() in a child fragment to access this method?
2) Implement an interface and go through the Activity, but how will I locate the child fragment from the Activity if it doesn't have an ID?
3) Or use this in parent fragment:
ChildFragment fragment =(ChildFragment)getChildFragmentManager().findFragmentById(R.id.child_fragment_id);
And just use a setter in child fragment.
But again how do I get the ID of the childFragment?
Thanks everyone in advance
If you want to communicate with your child Fragment to your parent Fragment you can use getParentFragment() method from your child fragment.
Example
public class ExampleParentFragment extends Fragment {
public int getCount() {
return 10;
}
}
public class ChildFragment extends Fragment {
void doAction() {
Fragment parentFragment = getParentFragment();
if(parentFragment instanceof ExampleParentFragment) {
int count = ((ExampleParentFragment) parentFragment).getCount();
}
}
}
I understand that the Fragment to Fragment communication through the activity is for sibling fragments which are coordinated by the same activity.
In this case the siblign fragments are coordinated by a parent fragment, so I would say that the communication should be managed by the parent fragment.
If you are working directly with the fragments then you do that using the ChildFragmentManager().
If you are working with a ViewPager you pass the ChildFragmentManager to the ViewPager insted of passing it the FragmentManager.
If you have to pass a List, I think the easiest is for the ChildFragment to request it when it is ready to receive it by calling a method on the ParentFragment. It can allways get its instace with getParentFragment().
I am not sure where is the safest place to call getParentFrament() to get the list but you can try in onCreateView() ,in onActivityCreated(), o in onResume().
To call the method that returns the list, you can cast the parent Fragment to the specific Fragment class you have extended, or else you can define an interface with the method that returns the List and make your extended parent Fragment implement it.
Then in the child Fragment, you refert to the parent by the interface to call the method and get the list.
Data should be passed to fragments using Bundle as arguments. So just pass the Arraylist(serialized or otherwise) to your child fragment when launching it

Passing a query to a loader manager in a fragment from an activity

I am using a LoaderManager in a fragment that populates a ListView with data from an SQLLite database using a SimpleCursorAdapter..
public class TimelineFragment extends ListFragment implements LoaderCallbacks { }
This fragment is "displayed" because it is referenced in the xml of the main activity.
Everything is working well, with the notifyChange in the ContentProvider CRUD actions reflecting any additions or deletions (actual CHANGES to the database).
I wish to implement a user based query function, but am having a great deal of trouble working out how to access the LoaderManager from within the MainActivity.
I need to send an sql selection string to the LoaderManager to requery the database. How do i do this from within the MainActivity?
Any help would be greatly appreciated...
I made a workaround. I brought the fragment code to the main activity code. This avoided the referencing issue I had as the loader was local to the class.
Probably not best practice but as a hack it worked...
You could send a query from a loader callback onCreateLoader(int id, final Bundle args).
You can see onCreateLoader takes a Bundle arg.
In an activity you initialise a loader with
getSupportLoaderManager().initLoader(ID_LOADER,bundle,this);
You pass into a bundle arguments you need to query sqllitedatabase
Bundle bundle=new Bundle();
bundle.putInt("pathToUri","someData")
Then in a Loader callback onCreateLoader(int id, final Bundle args)
you can access that "someData"
String uriPath=bundle.getInt("pathToUri")+"";
Then you create URI :
Uri selectQueryUri=CONTENT_URI.buildUpon().appendPath(uriPath).build();
and create a query:
getContentResolver().query(selectQueryUri,........)
dataProvider implements the query.
Don't forget to add a Bundle arg in a restartLoader as well.
If instead you pass in null the app will crash.
getSupportLoaderManager().restartLoader(ID_LOADER, bundle, this);

Categories

Resources