Load a single Fragment with different arguments in navigation drawer - java

Suppose I have a navigation drawer which contains three menu item i.e cat1, cat2, and cat3. Whenever a user clicks on this it will open a Fragment which will fetch the data from the web server and parse the JSON data and show into recycler view.
Now my question is.
Do I need to create separate fragments for each menu item of navigation drawer i.e cat1, cat2 and cat3? Or I can use one fragment and pass an argument like this
http://example.com?cat=1 to that fragment and load the recycler view item?
So which procedure should I follow to achieve this goal, separate fragment for each menu item or a single fragment? Thanks.

If you want to fetch data every time you click on a category, it's better to have one fragment and make it call the API. But if you use three fragments, it reduces number of API calls in addition to faster switching between categories. However, there is a trade-off between them. Also in second case, you should care about updating contents that is fetched from API every time.

You should definitely use a single fragment and avoid some boilerplate code. Here is a how you should do it:
public class CategoryFragment extends Fragment {
public static CategoryFragment newInstance(int categoryId) {
CategoryFragment fragment = new CategoryFragment();
Bundle extras = new Bundle();
extras.putInt("categoryId", categoryId);
fragment.setArguments(extras);
return fragment;
}
...
// Determine which category you're on
private int getCategoryId() {
return getArguments().getIntExtra("categoryId", 1);
}
}
And to instantiate your fragment you can simply use:
// Construct a cat2 fragment
CategoryFragment categoryFragment = CategoryFragment.newInstance(2);

You should use only one fragment in this case this is how you can reuse design and code by using just one fragment for each category cat1, cat2, cat3.
You can pass category id to the fragment via a bundle. check this tutorial

Related

Android, how to obtain state in activity from fragment

I am following the one activity/ many fragment approach for this application. From the picture, you can see there is a main activity with a toolbar spinner with sorting preferences. The option selected by the user will dictate how the recyclerView sort itself.
My question is, what is the best approach for fragment to obtain the information about what the user has selected in the toolbar spinner while keeping separation of concern?
Here is how the activity gets notified of user event in the spinner:
#Override
public void onSortMenuItemClicked(MenuItem id) {
mFragmentScreenNavigator.swapToJobRequestFragment(mUserProfilePersistence.getUserProfile().getEmail());
}
Once the user has selected a sorting preference, I have a navigator that navigates to the recyclerView fragment
Basically, what I want to achieve is instead of 'telling' the fragment what the sorting preference is, is there a way for the fragment to 'go out' and get that information? thank you
You could use ViewModel for the purpose of communication between Activity and Fragment. To make it work you also can use LiveData to observe for variable changes and updating if it happens.
1) Don't forget to add corresponding dependencies.
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
2) Create a class that extends from ViewModel. In this class, we have MutableLiveData object that allows up to work with LiveData. Probably it's better to use Integer type so you could change it like id.
public class ExampleViewModel extends ViewModel {
private MutableLiveData<String> sortingMode = new MutableLiveData<>();
public LiveData<String> getSortingMode() {
return sortingMode;
}
public void setSortingMode(String mode) {
sortingMode.postValue(mode);
}
}
2) Get a reference to your ViewModel inside Activity so you could update the value with sorting mode from (I believe) your options menu
ExampleViewModel viewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
3) To change the value you simply need to call your ViewModel method that will update the value o variable depending on item/id/title (whatever sounds better for you).
viewModel.setSortingMode("Example Mode");
4) Get the Activity ViewModel inside Fragment
ExampleViewModel viewModel = ViewModelProviders.of(getActivity()).get(ExampleViewModel.class);
5) Subscribe to LiveData object to observe value changes
viewModel.getSortingMode().observe(this, new Observer<String>() {
#Override
public void onChanged(String s) {
// Provide needed logic depending on sorting preferences
}
});
It's just a little example of how it works. Architecture Components are really powerful so I strongly recommend you to read about it.
Result (Green sector is Fragment inside Activity, they both are observing):
link

How to access a Viewpager's Fragment method?

I have a nested Fragment with a Viewpager inside of it. I'm trying to access a method (using MainActivity) in one of the Viewpager's Fragments, but I only get the last Viewpager Fragment or can't access methods when I use
ProfileFragment f = (ProfileFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentLayout);
...
Fragment f = v.getChildFragmentManager().findFragmentById(R.id.pager);
// Doesn't even work when I use findFragmentByTag("TAG")
where 'fragmentLayout' is the container for my Fragment Transactions inside activity_main.xml. (Currently ProfileFragment inside)
Here is how I nested my Fragments/xml:
MainActivity
- fragmentLayout
- ProfileFragment (or LoginFragment/ChatFragment/ShopFragment/etc)
- xml items
- viewPager
- Fragment1
- Fragment2 // can't access methods in here from MainActivity
- navigationTabs
I tried getting the Viewpager & PageAdapter from ProfileFragment and it shows the correct number of fragments, but I can't seem to access the methods.
Would an interface be something to look into? Or is there an easier way? Thank you.
String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
return fragment;
((YourFragment)fragment).methodName();
Try this
There are 2 simple ways to do it:
Store your Fragment1 and Fragment2 in your ProfileFragment, then when you need to call there's function, just call fragment1.doSomeThing() from your ProfileFragment. This approach is ok when your ViewPager's adapter dont have too many fragments (in this case, you should use WeakReference to avoid OOM when storing your fragments`.
Using EventBus (or LocalBroadCastReceiver, but I prefer EventBus). Then you can call your doSomeThing() function from anywhere, with the call like below:
EventBus.getDefault().post(new CallYourFunctionObject(int value)
None of the solutions worked for me & I had trouble implementing an interface with my nested fragments.
I ended up putting the methods in MainActivity which was the easiest solution for me.
I can also access the nested fragment views directly from MainActivity with
TextView tv1 = findViewById(R.id.exampleid);

Android Display 2 fragments inside another one

I've got an Application with a MainActivity with a Navigation Drawer MenĂ¹.
Inside the MainActivity View I've got a Frame layout which takes the whole space.
When the user select something from the menĂ¹ I call a method which handle the fragments transaction inside the Frame Layout.
My MainActivity is the Fragment manager and from here i can handle all the changes I want and i can handle the communications between the fragments.
Here's the problem:
In one of my Fragment i'd like to show 2 new fragments, one with a PieChart and one with the data.
I could have done only one Fragment with all inside its view but i'd like to use a modular managing way.
So, first of all i created 1 fragment, the Container one (we can call it A).
In its view i put the fragment B and fragment C, directly from Xml.
In fragment B i've got the PieChart, HERE i call the methods to download data from a database, and then i put this data inside the chart.
I wrote a simple Interface which contains a method which is called when the user interact wich the chart; it build an object whith the selected data.
My target is to send this data to Fragment A and then pass them to Fragment C, so that the user can see what is he selecting.
In Fragment A i've Implemented the Fragment B inteface, then i set up this code inside OnAttach of B:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
Interface = (InterfaceB) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement InterfaceB");
}
}
Everithing seems to works, but in the moment tha Fragment A is created, OnAttach of B is called, and the context which arrives refers to MainActivity and not to Fragment A.
This causes a Crash.
Fragment is not an instance of Context, so it is impossible to pass it to onAttach(Context Context) anyway.
There are two ways how you can do what you want.
1) Use onAttachFragment(Fragment fragment) inside fragment A, and catch events when fragments B and C are attached;
2) Use getParentFragment() inside fragments B and C, to access A.

What's the right way to inflate a fragment from another fragment?

I've been doing it like this for a while, is it the right way?
Activity:
public void toSettings(){
Fragment_Settings frag = new Fragment_Settings();
fm.beginTransaction()
.replace(R.id.mainContainer, frag)
.addToBackStack(null)
.commit();
}
In some listener in another fragment:
((Activity_Main)getActivity()).toSettings();
You don't need .addToBackStack(null) Just delete that piece and your fragment will not be added to backstack. I would also suggest adding a TAG to the replace method just in case you want to retrieve the fragment later. Something like this .replace(R.id.mainContainer, frag, TAG).
It seems correct but i have some suggestions.
If you wanna back previous fragment from Fragment_Settings use add method instead of replace and addToBackStack("tag of Fragment_Settings") instead of addToBackStack(null).
newInstance pattern is more preferred than Fragment_Settings frag = new Fragment_Settings();. You can see some explanations about that.
http://www.androiddesignpatterns.com/2012/05/using-newinstance-to-instantiate.html
Creating a Fragment: constructor vs newInstance()
To avoid code repetition when navigating between fragments you can use a manager class provides organizing add, replace or pop processes.
Here is my navigation manager class.

Best way access activities from fragments

So currently I have a application with different activities, and I use buttons to navigate between activities. I later decided that I should add the navigation drawer and use fragments instead. So one of my fragments has a bunch of fields that the user fills out that I need to pass onto the next fragment. So my question is, Do I keep all the work in activities and call the activity from the fragment? Or do I just include all he java in my activity in the java for the fragment? For the most part I am taking the fields from the first fragment, and I'd like to pass the values to the next fragment so it can handle some calculations.
final EditText FinalPriceText = (EditText) v.findViewById(R.id.editTextPrice);
final EditText TradeInPriceText = (EditText) v.findViewById(R.id.editTextTrade);
i.putExtra("FinalAutoPrice", FinalAutoPriceText.getText().toString());
i.putExtra("TradeInPrice", TradeInPriceText.getText().toString());
startActivity(i);
As far as calculations go, if you are going to use them a lot and they have nothing to do with the activity or android lifecycle I would separate them out into a different class and then you can call them from anywhere.
If they do rely on the activity you could still separate them out but pass a reference to the activity when doing your calculations. You can get the parent activity by calling this.getActivity() from any fragment
You can cast this.getActivity() to whatever the parent activity is and you can call the methods from that object as well. This works fine but your fragment will only work with the activity you specify and it can get sloppy if you are not careful.
Otherwise put them in the fragment where you need them. I would consider this least recommended if you need to use calculations anywhere else in the app. Duplicate code is just asking for bugs in the future.
As far as passing data, create a static instance method in fragment2 and pass it what you need there.
For example
public Fragment2 extends Fragment {
public static fragment2 newInstance(MyData myDataIPass) {
Fragment2 fragment = new Fragment2();
Bundle args = new Bundle();
args.putInt("someInt", myDataIPass.someInt);
fragment.setArguments(args);
return fragment;
}
}
Call this new instance method when creating your fragment transaction like this
FragmentManager fm = getActivity().getFragmentManager();
fm.beginTransaction()
.replace(R.id.container, Fragment2.newInstance(MyData myDataIPass))
.commit();
Well, you have mainly two options here:
use Intent.putExtra() with fragments. Just like Activities, you
can use this method with Fragments as well. See the following links
for the implementation in Fragments
this
this
The other option is to use SharedPreferences and store data as key value pairs from one fragment, and can be accessed from any other activity/fragments. See this nice tutorial to understand better!
You have a special callback in Fragment to get Activity.
It is called:
#Override
public void onAttach(Context context) {
super.onAttach(context);
YourActivity activity = (YourActivity) context;
}

Categories