problem with fragments placed in a package - android

I'm having a problem, with fragments, after inserting them into a package, when I instantiate an object I get FragmentAssumiPersonaleBinding, I do not understand why it comes out this way, when I do the replace of the fragment it gives me error. I tried to remove the fragments from the package but from the same problem, while with the previous fragments this thing does not happen and work normally.
public void navigaNavigationBar(){
NavigationBarView navigationBarView = findViewById(R.id.bottomNavigationView);
navigationBarView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
//Quando viene cliccato sulla navigationBar viene preso l'id dell'item cliccato
switch (item.getItemId()){
case R.id.navigation_bar_acquisisci_lavoro:
FragmentAssumiPersonaleBinding fragmentAssumiPersonaleBinding = new FragmentAssumiPersonaleBinding();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.FrameLayout_home_azienda,fragmentAssumiPersonaleBinding);
transaction.addToBackStack(null);
transaction.commit();
return true;
case R.id.navigation_bar_assumi_personale:
case R.id.navigation_bar_home_azienda:
return true;
case R.id.navigation_bar_gestisci_azienda:
}
return false;
}
});
}
I'm also not understanding how to manage the click of the navigation bar, because I tried to use navigationBarView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() but it does not work, while the other method with the navigationBarView is deprecated, although it is not deprecated on the documentation, but I have not found an alternative. thank you :)
I wanted to add that the fragmentbinding I did not call it so but it is written automatically so, and the error is in fragmentAssumiPersonaleBinding because required a type of Fragment not a FragmentBinding
I solved the problem, practically when you create a new package, rightly the fragment ends up in the new package, which is completely separate from the main package, so when you try to create the object you call it object name + binding and in the case of fragment s they give problems. I solved by deleting the class from the project folder, if you do it from the IDE it doesn't solve the problem, I put the class in the same package manually and it works. Anyway this forum is absurd, I can not post an answer

Related

How to save fragment state : Bottom Navigation View with fragments android

Im creating a app with three sections home,color,profile I'm using bottom navigation view with fragments to achieve this.
App UI
Here is my code:
Main Activity on create method:
final HomeFragment homeFragment = new HomeFragment();
final ColorFragment colorFragment = new ColorFragment();
final ProfileFragment profileFragment = new ProfileFragment();
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment active = homeFragment;
switch (item.getItemId()){
case R.id.action_home:
active = homeFragment;
break;
//return true;
case R.id.action_color:
active = colorFragment;
break;
case R.id.action_profile:
active = profileFragment;
break;
default:
active = homeFragment;
break;
}
//Loading the fragment on click
fragmentManager.beginTransaction().replace(R.id.fragment_container,active).commit();
return true;
}
});
Im using fragment manager to load the fragment in my Main Activity which comes with below problem.
1.It reloads the fragment each time I click on the bottom navigation icon.(Im getting data from firebase this will be costly )
I have read many articles regarding this,i found solutions like below:
Using hiding the fragments on creation of activity
fragmentManager.beginTransaction().add(R.id.fragment_container, profileFragment, "3").hide(profileFragment).commit();
fragmentManager.beginTransaction().add(R.id.fragment_container, colorFragment, "2").hide(colorFragment).commit();
fragmentManager.beginTransaction().add(R.id.fragment_container,homeFragment, "1").commit();
Above solution loads all the fragments on the creation of activity which isn't a efficient scnario
Using NavHost :
It refresh the fragment every time.
This also not working for me.
Please Help:
What I want to acheive:
1.The fragment should only load when I click on the icon for the first time.
2.All the fragments should not load at the time of activity creation.
3.When I revist the fragment It should not load again, I should stay at previous state ex. scrolled till 25th card
//Its should be like playstore,youtube where when we click on icon it loads the data, when we revisit the state will be there.
You either need to use extension function provided by Google for BottomNavigationView or use a ViewPager/ViewPager2 to have each fragment have it's own back stack and going back to exact same fragment instead of creating root fragment over and over again. Both solutions require you to have NavHostFragment as root of each tab. You can check out the samples in this repo.
You can either use a FragmentPagerAdapter or ViewPager2. I refer you to two answers for a similar question:
1- FragmentPagerAdapter
2- ViewPager2

Do fragments need to be always recreated when exchanging the fragment?

Is it really necessary to always recreate fragments when navigating the bottom nav menu like in this code?
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_favorites:
selectedFragment = new FavoritesFragment();
break;
case R.id.nav_search:
selectedFragment = new SearchFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();
return true;
}
};
I would rather like to create all my Fragments once in onCreate of the surrounding MainActivity and store them there as member variables. Then i could in the onNavigationItemSelected just use the references to my fragments instead of creating new fragments.
Is it okay to do it as described and not use the code above? Or could doing it as described cause complications somewhere?
Actually, creating them on create would be the best way. Also, sometimes people tend to add a lot of initializations on their on create and in the long run ur app might use too much memory when initializing the fragments every time you need them.
You would have to be responsible for saving your fragments state, so on recreation, your data would be readily available. You could try something like this
https://proandroiddev.com/fragments-swapping-with-bottom-bar-ffbd265bd742
Although there are many approaches you could attempt.
You could create all the fragments at once and swap them with your bottom navigation. But I wouldn't recommend that for obvious navigation and performance reasons.

Correct Activity/Fragment Architecture for Android Bottom Navigation View

I would like to get some input on the best way to structure my app's architecture when using Android's Bottom Navigation View.
Currently I define my BottomNavigationView in my MainActivity. It looks something like this.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNavigationView = (BottomNavigationView)findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.action_home:
selectedFragment = HomeFragment.newInstance();
break;
case R.id.action_search:
selectedFragment = SearchFragment.newInstance();
break;
case R.id.action_message:
selectedFragment = MessageFragment.newInstance();
break;
case R.id.action_profile:
selectedFragment = ProfileFragment.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, HomeFragment.newInstance());
transaction.commit();
}
The problem is that once I click on one tab, it opens up a fragment, and I would like to have those Fragments open up other Fragments/Activities (i.e:
I open the profile tab (`ProfileFragment` loads)
I click on a button from `ProfileFragment`, and from this the `SignUpFragment` or `SignUpActivity` loads
After running into many bugs, I've researched on how to architect my app, but i've found mixed results. Would anyone know the correct way of using a BottomNavigationView with Fragments, and in those fragments I can load more Activities/fragments. A huge thanks in advance.
Every approach depends on the project and what you pretend to achieve. I had to code a Bottom Navigation app that works with over 20 Bottom Navigation layouts, meaning one single Activity. The process you wish to achieve is pretty much the same of setting the desired fragment in the desired tab on tab selected, the difference is that, instead of taping on a tab, you will tap on a button inside a fragment, which you will replace with the new desired fragment.
tap tab -> replace fragment -> button click inside fragment -> replace fragment -> and so on.
Since you are using replace, you will have to carefully handle your onBackPress event, since I'm assuming that on every back press you wish to go back to the previous fragment. Myself, I've implemented an interface in the Main Activity that listens to the visible fragment onBackPress.

Navigation drawer implementation with list fragments

I want to implement a navigation drawer with multiple listfragments, how can i do this? I spent time searching online but couldnt find anything related to it. Any help would be appreciated!
When implementing the NavigationDrawer, use its onDrawerItemSelected method to switch Fragments:
#Override
public void onDrawerItemSelected(final int pos) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (pos) {
case 0:
fragment = new ListFragmentOne();
break;
case 1:
fragment = new ListFragmentTwo();
break;
case 2:
fragment = new ListFragmentThree();
break;
}
// content_frame is a FrameLayout inside the layout of your activity - this is where the fragment will be put
getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
mDrawerList.setItemChecked(pos, true);
// do stuff like closing the drawer...
}
I am not sure though if the NavigationDrawer even supports ListFragments. If not, simply use normal Fragments containing a ListView.

OnOptionsItemSelected in activity is called before onOptionsItemSelected in fragment. Other way possible?

I have an activity which can contain several fragments. Each of the fragments can have their own menu entries in the ActionBar. This works fine so far and each item is clickable and performs the desired action.
My problem is the following. In the MainActivity I declared the following lines to intercept calls to the HomeIcon of the ActionBar:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
clearBackStack();
setHomeFragment();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I declared it in the Activity because I wanted that every Fragment should call this so that I don't have to catch the android.R.id.home case in each fragment.
In one Fragment I am using setDisplayHomeAsUpEnabled(true), so that I get the little arrow left of the ActionBar Icon. When the HomeIcon is clicked in this fragment I don't want to set the HomeFragment, I want to set the Fragment which was last displayed. So I have a onOptionsItemSelected - Method in the Fragment:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
setLastFragment();
return true;
...
However this does not work the way I wanted it to work. The Activity's onOptionsItemSelected is called first, catches the MenuItem and redirects to the HomeFragment. With the other MenuItems declared in other fragments i can check the see the same behaviour. Activity is called first, doesn't catch the MenuItem (default case) and then redirects to super.onOptionsItemSelected(item).
So it seems that this is the case how Android handles the Menu Clicks. First Activity, then Fragment. Is there a way to change this? I don't want to put the android.R.id.home-case in every fragment and handle it there. Is there a nicer way to do this?
I just encounter this problem, and I have made it work using following code.
In the activity's onOptionsItemSelectedfunction, add:
if (id == android.R.id.home){
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if(null != currentFragment && currentFragment.onOptionsItemSelected(item)){
return true;
}
}
And in the fragment's onOptionsItemSelected method, you handle the corresponding things.
In this way, if the fragment has any things to do for the menu item, it will do it and return true to stop any other process.
And if the fragment does not have anything to do with this item, it will return false or call super.onOptionsItemSelected method which may eventually return false to let others process it.
According to the developers reference,
"Return false to allow normal menu processing to proceed, true to consume it here."
So I would try returning 'false' by default in the Activity's implementation of onOptionsItemSelected(), this way the event will pass on to the Fragment's implementation if it is not caught.
Not sure if it's possible. In the official docs available here:
http://developer.android.com/guide/topics/ui/actionbar.html#ActionEvents
There is a note, that states the following:
[...] However, the activity gets a chance to handle the event first, so the system first calls onOptionsItemSelected() on the activity, before calling the same callback for the fragment.
You can do as #Surely written, it's great idea, but in that case you will call onOptionsItemSelected on fragment without knowing which fragment it is, and you should override onOptionsItemSelected method in all your fragments.
If you only want to call this method for particular fragments, you should find them by tag, which you used when adding them:
case android.R.id.home:
Fragment frag = getSupportFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
if(frag != null && frag.isVisible() && frag.onOptionsItemSelected(item)) {
return true;
Tag is specifying like this:
fragmentManager.beginTransaction()
.add(containerId, fragment, FRAGMENT_TAG)

Categories

Resources