Parent fragment to Child Fragment communication - java

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

Related

Getting the Activity inside Adapter in Android

I am trying to access the activity on which my Imageview is, so I can use the URL of an Image of type SVG and display it to the user using the GlideToVectorYou library.
GlideToVectorYou.justLoadImage(activity, IMAGE_URI, targetImageView)
But when I try to get access to the activity using R.layout.activityname, a syntax error appears.
this is the code that I'm using
Uri myurl = Uri.parse(match.getFlag());
GlideToVectorYou.justLoadImage(R.layout.item_basketball, myurl, iv_location);
Thank you!
R.layout.item_basketball is just an integer ID for your activity layout - not the activity instance itself. If you want the activity in your adapter you would need to pass it in when you construct the adapter and save it as a class member (example below), or check if your adapter base class already can provide it via getActivity() or getContext() or a similar method.
class MyAdapter(private val activity: Activity) : BaseAdapter() {
fun someMethod() {
// then you can access "activity" in your adapter methods
GlideToVectorYou.justLoadImage(activity, IMAGE_URI, targetImageView)
}
}
and when you create it in your Activity, you would just do something like this
val adapter = MyAdapter(this)
You need a activity reference. R.layout.somethinghere is the layout reference.
On your adapter constructor add a activity parameter and use it inside the adapter.
If you call adapter constructor from an activity, just pass "this" as parameter. If call from a fragment, use "requireActivity" (if using kotlin) or analogous method (getActivity, for example) if using Java

How to store all child fragment classes to the parent class' instance

I'm working on a "home feed"-like feature where there's a main Fragment with several other fragments added to its layout, making up the content page. I'd like the main fragment class to be able to instanstiate all the fragment classes that inherit from a certain parent fragment class. This way the code would be more dynamic instead of adding a bunch of <fragment> tags to my xml files.
I'm kinda stuck on making up a decent architecture. How would you go on about doing this?
UPDATE:
Here's what I'm basically trying to do, but don't know how:
public class FeedFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View parentView = inflater.inflate(R.layout.fragment_home, container, false);
// Get fragments and dynamically add them to
// the FeedFragment's layout
getEntryFragmentsList();
// ...
return parentView;
}
}
public abstract class FeedEntryFragment extends Fragment {
// Somehow add fragment to list of entry fragments
}
public class TestFragment extends FeedEntryFragment {
// Already added to list of entry fragments
}
I don't think that possible to decrease the count of xmls by inheritance. I think you should try to split your xml configurations and use some <merge> or <include> to build the full one from the parts.
May be I can provide more help if you will describe your problem in more details.
You should use FrameLayout to add fragment(s) dynamically by using the FragmentTransaction.
You can also use a ViewPager with tabs or bottom tabs to show multiple fragments. Please check sample from my Dynamic Support library for the complete code.
Abstract fragments
DynamicFragment - Abstract base fragment from the Dynamic support library.
DynamicViewPagerFragment - Abstract fragment which extends the DynamicFragment to implement the ViewPager functionality.
Implementation
HomeFragment - Sample fragment extends the DynamicFragment to implement the home screen.
SettingsFragment - Sample fragment extends the DynamicViewPagerFragment to implement the settings functionality using multiple fragments inside a view pager.
Tutorial Implementation
This better suits your need. TutorialActivity returns a list of fragments to be displayed inside a ViewPager.
DynamicSimpleTutorial generates a DynamicTutorialFragment according to the supplied parameters.

Send Object created from MainActivity to Fragments TabbedView [duplicate]

This question is mostly to solicit opinions on the best way to handle my app. I have three fragments being handled by one activity. Fragment A has one clickable element the photo and Fragment B has 4 clickable elements the buttons. The other fragment just displays details when the photo is clicked. I am using ActionBarSherlock.
The forward and back buttons need to change the photo to the next or previous poses, respectively. I could keep the photo and the buttons in the same fragment, but wanted to keep them separate in case I wanted to rearrange them in a tablet.
I need some advice - should I combine Fragments A and B? If not, I will need to figure out how to implement an interface for 3 clickable items.
I considered using Roboguice, but I am already extending using SherlockFragmentActivity so that's a no go. I saw mention of Otto, but I didn't see good tutorials on how to include in a project. What do you think best design practice should be?
I also need help figuring out how to communicate between a fragment and an activity. I'd like to keep some data "global" in the application, like the pose id. Is there some example code I can see besides the stock android developer's information? That is not all that helpful.
BTW, I'm already storing all the information about each pose in a SQLite database. That's the easy part.
The easiest way to communicate between your activity and fragments is using interfaces. The idea is basically to define an interface inside a given fragment A and let the activity implement that interface.
Once it has implemented that interface, you could do anything you want in the method it overrides.
The other important part of the interface is that you have to call the abstract method from your fragment and remember to cast it to your activity. It should catch a ClassCastException if not done correctly.
There is a good tutorial on Simple Developer Blog on how to do exactly this kind of thing.
I hope this was helpful to you!
The suggested method for communicating between fragments is to use callbacks\listeners that are managed by your main Activity.
I think the code on this page is pretty clear:
http://developer.android.com/training/basics/fragments/communicating.html
You can also reference the IO 2012 Schedule app, which is designed to be a de-facto reference app. It can be found here:
http://code.google.com/p/iosched/
Also, here is a SO question with good info:
How to pass data between fragments
It is implemented by a Callback interface:
First of all, we have to make an interface:
public interface UpdateFrag {
void updatefrag();
}
In the Activity do the following code:
UpdateFrag updatfrag ;
public void updateApi(UpdateFrag listener) {
updatfrag = listener;
}
from the event from where the callback has to fire in the Activity:
updatfrag.updatefrag();
In the Fragment implement the interface in CreateView do the
following code:
((Home)getActivity()).updateApi(new UpdateFrag() {
#Override
public void updatefrag() {
.....your stuff......
}
});
To communicate between an Activity and Fragments, there are several options, but after lots of reading and many experiences, I found out that it could be resumed this way:
Activity wants to communicate with child Fragment => Simply write public methods in your Fragment class, and let the Activity call them
Fragment wants to communicate with the parent Activity => This requires a bit more of work, as the official Android link https://developer.android.com/training/basics/fragments/communicating suggests, it would be a great idea to define an interface that will be implemented by the Activity, and which will establish a contract for any Activity that wants to communicate with that Fragment. For example, if you have FragmentA, which wants to communicate with any activity that includes it, then define the FragmentAInterface which will define what method can the FragmentA call for the activities that decide to use it.
A Fragment wants to communicate with other Fragment => This is the case where you get the most 'complicated' situation. Since you could potentially need to pass data from FragmentA to FragmentB and viceversa, that could lead us to defining 2 interfaces, FragmentAInterface which will be implemented by FragmentB and FragmentAInterface which will be implemented by FragmentA. That will start making things messy. And imagine if you have a few more Fragments on place, and even the parent activity wants to communicate with them. Well, this case is a perfect moment to establish a shared ViewModel for the activity and it's fragments. More info here https://developer.android.com/topic/libraries/architecture/viewmodel . Basically, you need to define a SharedViewModel class, that has all the data you want to share between the activity and the fragments that will be in need of communicating data among them.
The ViewModel case, makes things pretty simpler at the end, since you don't have to add extra logic that makes things dirty in the code and messy. Plus it will allow you to separate the gathering (through calls to an SQLite Database or an API) of data from the Controller (activities and fragments).
I made a annotation library that can do the cast for you. check this out.
https://github.com/zeroarst/callbackfragment/
#CallbackFragment
public class MyFragment extends Fragment {
#Callback
interface FragmentCallback {
void onClickButton(MyFragment fragment);
}
private FragmentCallback mCallback;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1
mCallback.onClickButton(this);
break;
case R.id.bt2
// Because we give mandatory = false so this might be null if not implemented by the host.
if (mCallbackNotForce != null)
mCallbackNotForce.onClickButton(this);
break;
}
}
}
It then generates a subclass of your fragment. And just add it to FragmentManager.
public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction()
.add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
.commit();
}
Toast mToast;
#Override
public void onClickButton(MyFragment fragment) {
if (mToast != null)
mToast.cancel();
mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
mToast.show();
}
}
Google Recommended Method
If you take a look at this page you can see that Google suggests you use the ViewModel to share data between Fragment and Activity.
Add this dependency:
implementation "androidx.activity:activity-ktx:$activity_version"
First, define the ViewModel you are going to use to pass data.
class ItemViewModel : ViewModel() {
private val mutableSelectedItem = MutableLiveData<Item>()
val selectedItem: LiveData<Item> get() = mutableSelectedItem
fun selectItem(item: Item) {
mutableSelectedItem.value = item
}
}
Second, instantiate the ViewModel inside the Activity.
class MainActivity : AppCompatActivity() {
// Using the viewModels() Kotlin property delegate from the activity-ktx
// artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.selectedItem.observe(this, Observer { item ->
// Perform an action with the latest item data
})
}
}
Third, instantiate the ViewModel inside the Fragment.
class ListFragment : Fragment() {
// Using the activityViewModels() Kotlin property delegate from the
// fragment-ktx artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by activityViewModels()
// Called when the item is clicked
fun onItemClicked(item: Item) {
// Set a new item
viewModel.selectItem(item)
}
}
You can now edit this code creating new observers or settings methods.
There are severals ways to communicate between activities, fragments, services etc. The obvious one is to communicate using interfaces. However, it is not a productive way to communicate. You have to implement the listeners etc.
My suggestion is to use an event bus. Event bus is a publish/subscribe pattern implementation.
You can subscribe to events in your activity and then you can post that events in your fragments etc.
Here on my blog post you can find more detail about this pattern and also an example project to show the usage.
I'm not sure I really understood what you want to do, but the suggested way to communicate between fragments is to use callbacks with the Activity, never directly between fragments. See here http://developer.android.com/training/basics/fragments/communicating.html
You can create declare a public interface with a function declaration in the fragment and implement the interface in the activity. Then you can call the function from the fragment.
I am using Intents to communicate actions back to the main activity. The main activity is listening to these by overriding onNewIntent(Intent intent). The main activity translates these actions to the corresponding fragments for example.
So you can do something like this:
public class MainActivity extends Activity {
public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
public static final String INTENT_ACTION_SHOW_BAR = "show_bar";
#Override
protected void onNewIntent(Intent intent) {
routeIntent(intent);
}
private void routeIntent(Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case INTENT_ACTION_SHOW_FOO:
// for example show the corresponding fragment
loadFragment(FooFragment);
break;
case INTENT_ACTION_SHOW_BAR:
loadFragment(BarFragment);
break;
}
}
}
Then inside any fragment to show the foo fragment:
Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
There is the latest techniques to communicate fragment to activity without any interface follow the steps
Step 1- Add the dependency in gradle
implementation 'androidx.fragment:fragment:1.3.0-rc01'

Call getFragmentManager() without extending Fragment

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

Android: how can fragment take a global variable of Activity

I have an activity with a global variable int x, how can a fragment get the current value of variable x of its activity ?
Either set the var as public static, or use
((MyActivity)getActivity()).getX()
Using a public static variable isn't the best way to communicate between an activity and a fragment. Check out this answer for other ways:
The Android documentation recommends using an interface when the Fragment wants communicate with the Activity. And when the Activity wants to communicate with the Fragment, the Activity should get a reference to the Fragment (with findFragmentById) and then call the Fragment's public method.
The reason for this is so that fragments are decoupled from the activity they are in. They can be reused in any activity. If you directly access a parent Activity or one of its global variables from within a fragment, you are no longer able to use that fragment in a different Activity.
Kotlin version:
(activity as MyActivity).x
***In your Activity
==================
Bundle args = new Bundle();
args.putInt("something", Whatever you want to pass);
fragA.setArguments(args);
In your Fragment
==================
Bundle args = getArguments();
//whatever you want to get ,get it here.
//for example integer given
int index = args.getInt("index", 0);

Categories

Resources