Hello im trying to navigate between some fragments with addToBaackStack but having issues with it ,
Ok i will explain it in detail so there should be no confusuion
1 :- I have only one activity (main activity) which consist of all the other fragments and a fragment container to hold the fragments in it , i have implemented bottom navigation in the main activity ,where the bottom navigation have 5 main fragments home,following,upload,notification and profile my issues is related to the profile fragment
2 :- In the profile fragment i have some buttons like edit profile button which opens edit profile fragment but now when i presse back it should navigate back to the profile fragment which it is not doing ,its is navigating to the last fragment of the bottomnavigation (which can be any other of the main fragments for eg if my last fragment is following fragment then when i press back from the edit profile fragment it goes to the following fragment )but this not happens if i put a back arrow icon in edit profile fragment then when i click the back arrow it perfectly navigate me to the profile fragments as it is not related to addToBackStack
It shows that the issue is related with my bottom navigation but i dont know how to exactly fix it
Prifile_Fragment.java
editProfileButton.setOnClickListener(v -> {
Fragment edit_profile = new Edit_Profile();
assert getFragmentManager() != null;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, edit_profile);
transaction.addToBackStack(null);
transaction.commit();
});
MainActivity.java // where the bottom navigation is implemented
public class MainActivity extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
Deque<Integer> integerDeque = new ArrayDeque<>(4);
boolean flag = true;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setContentView(R.layout.activity_main);
Window window = this.getWindow();
window.setStatusBarColor(this.getResources().getColor(R.color.black));
bottomNavigationView = findViewById(R.id.bottom_navigation_view);
integerDeque.push(R.id.nav_home);
loadFragments(new Home_Fragment());
bottomNavigationView.setSelectedItemId(R.id.nav_home);
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
int id = item.getItemId();
if (integerDeque.contains(id)) {
if (id == R.id.nav_home) {
integerDeque.size();
if (flag) {
integerDeque.addFirst(R.id.nav_home);
flag = false;
}
}
integerDeque.remove(id);
}
integerDeque.push(id);
loadFragments(getFragment(item.getItemId()));
return false;
}
);
}
#SuppressLint("NonConstantResourceId")
private Fragment getFragment(int itemId) {
switch (itemId) {
case R.id.nav_home:
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
case R.id.nav_following:
bottomNavigationView.getMenu().getItem(1).setChecked(true);
return new Following_Fragment();
case R.id.nav_upload:
bottomNavigationView.getMenu().getItem(2).setChecked(true);
return new Upload_Fragment();
case R.id.nav_notification:
bottomNavigationView.getMenu().getItem(3).setChecked(true);
return new Notification_Fragment();
case R.id.nav_profile:
bottomNavigationView.getMenu().getItem(4).setChecked(true);
return new Profile_Fragment();
}
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
}
public void loadFragments(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName())
.commit();
}
}
#Override
public void onBackPressed() {
integerDeque.pop();
if (!integerDeque.isEmpty()) {
loadFragments(getFragment(integerDeque.peek()));
} else {
finish();
}
}
}
Have you consider to use popBackStack ? You can try this.
#Override
public void onBackPressed() {
final FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
finish();
}
}
Related
i have four fragments Home, Warning, Donate, and About, Home is the first one shown on launch, what i need is that when users are on any of these fragments (Donate, About, and Caution), and when they go back to the Home fragment using backstack only, I want to show an interstitial ad before showing the home fragment.
I don't want to show the ad when the home fragment launch for first time
Main Activity
public class MainActivity extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
Deque<Integer> integerDeque = new ArrayDeque<>(3);
boolean flag = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Window window = this.getWindow();
window.setStatusBarColor(this.getResources().getColor(R.color.black));
bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setItemIconTintList(null);
integerDeque.push(R.id.home_icon);
loadFragments(new Home_Fragment());
bottomNavigationView.setSelectedItemId(R.id.home_icon);
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
int id = item.getItemId();
if (integerDeque.contains(id)) {
if (id == R.id.home_icon) {
integerDeque.size();
if (flag) {
integerDeque.addFirst(R.id.home_icon);
flag = false;
}
}
integerDeque.remove(id);
}
integerDeque.push(id);
loadFragments(getFragment(item.getItemId()));
return true;
}
);
}
#SuppressLint("NonConstantResourceId")
private Fragment getFragment(int itemId) {
switch (itemId) {
case R.id.home_icon:
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
case R.id.guide_icon:
bottomNavigationView.getMenu().getItem(1).setChecked(true);
return new Cuation_Fragment();
case R.id.donate_icon:
bottomNavigationView.getMenu().getItem(2).setChecked(true);
return new Donate_Fragment();
case R.id.about_icon:
bottomNavigationView.getMenu().getItem(3).setChecked(true);
return new About_Fragment();
}
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
}
public void loadFragments(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName())
.commit();
}
}
#Override
public void onBackPressed() {
integerDeque.pop();
if (!integerDeque.isEmpty()) {
bottomNavigationView.setSelectedItemId(integerDeque.peek());
} else {
finish();
}
}
}
I'm using 4 fragments and the MainActivity (which contains the bottom nav) but now because of a particular payment gateway issue with one of the fragments I have changed that fragment into an activity, but as the bottom nav has 3 fragments in it don't know how do add an activity in it, and I also don't want to change all the 3 remaining fragments into activity just to make it work with bottom nav
Files
MainActivity,Home_Fragment,Caution_Fragment,Donate_Fragment // this is the fragment i changed into activtiy// and About_Fragment
is there any way to add an activity in a bottom navigation view that already contains fragments
if you want to view the Donate_Fragment(Activity) code please tell me
I will add it
MainActivity.java
public class MainActivity extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
Deque<Integer> integerDeque = new ArrayDeque<>(3);
boolean flag = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Window window = this.getWindow();
window.setStatusBarColor(this.getResources().getColor(R.color.black));
bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setItemIconTintList(null);
integerDeque.push(R.id.home_icon);
loadFragments(new Home_Fragment());
bottomNavigationView.setSelectedItemId(R.id.home_icon);
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
int id = item.getItemId();
if (integerDeque.contains(id)) {
if (id == R.id.home_icon) {
integerDeque.size();
if (flag) {
integerDeque.addFirst(R.id.home_icon);
flag = false;
}
}
integerDeque.remove(id);
}
integerDeque.push(id);
loadFragments(getFragment(item.getItemId()));
return true;
}
);
}
#SuppressLint("NonConstantResourceId")
private Fragment getFragment(int itemId) {
switch (itemId) {
case R.id.home_icon:
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
case R.id.guide_icon:
bottomNavigationView.getMenu().getItem(1).setChecked(true);
return new Cuation_Fragment();
case R.id.donate_icon:
bottomNavigationView.getMenu().getItem(2).setChecked(true);
return new Donate_Fragment();
case R.id.about_icon:
bottomNavigationView.getMenu().getItem(3).setChecked(true);
return new About_Fragment();
}
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
}
public void loadFragments(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName())
.commit();
}
}
#Override
public void onBackPressed() {
integerDeque.pop();
if (!integerDeque.isEmpty()) {
bottomNavigationView.setSelectedItemId(integerDeque.peek());
} else {
finish();
}
}
}
I have a bottom navigation bar that contains 4 fragments and when a tab is selected a new instance of that fragment is loaded.
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = HomeFragment.newInstance();
break;
case R.id.navigation_cards:
fragment = CardsFragment.newInstance();
break;
case R.id.navigation_deals:
fragment = DealsFragment.newInstance();
break;
case R.id.navigation_settings:
fragment = SettingsFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
fragmentTransaction.commit();
}
return true;
}
};
Now in my HomeFragment there is a RecyclerView that On Item Select it opens a new Fragment:
myViewHolder.cardView.setOnClickListener(view -> {
System.out.println("clicked");
Fragment fragment = new TargetDetailsFragment();
FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.content, fragment).addToBackStack(null);
ft.commit();
});
I want to add a back button to the TargetDetails Fragments that takes you back to the home page when selected and I attempted doing that by implementing OnBackStackChangedListener in the Main activity
#Override
public void onBackStackChanged() {
shouldDisplayHomeUp();
}
public void shouldDisplayHomeUp(){
//Enable Up button only if there are entries in the back stack
boolean canback = getSupportFragmentManager().getBackStackEntryCount()>0;
getSupportActionBar().setDisplayHomeAsUpEnabled(canback);
}
#Override
public boolean onSupportNavigateUp() {
//This method is called when the up button is pressed. Just the pop back stack.
getSupportFragmentManager().popBackStack();
return true;
}
}
but the problem is when I click on it its reloads the HomeFragment Again but I simply want it to go back to the saved instance of that Fragment
Here is my code that I have used for the ViewPager, the idea is to see if the current page number is 0 than to proceed super.onBackPressed(); otherwise go to the previous fragment:
#Override
public void onBackPressed() {
if(vpPager.getCurrentItem()!=0) {
vpPager.setCurrentItem(vpPager.getCurrentItem()-1, true);
} else {
super.onBackPressed();
}
}
By adding below code in your Activity.
The fragment back stack can be managed.
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
Hello #Bolu Okunaiya i think you should try this it will help you to manage backstack to desired fragment without loading same fragment again.
For Stop loading previous fragment you should use "add" instead of "replace" with your FragmentTransaction
Inside your MainActivity
#Override
public void onBackStackChanged() {
//shouldDisplayHomeUp();
Fragment currentFragment = getActivity().getFragmentManager()
.findFragmentById(R.id.fragment_container);
if (currentFragment instanceof TargetDetails) {
Log.v(TAG, "your current fragment is TargetDetails");
popBackStackImmediate(); //<<<< immediate parent fragment will open,which is your HomeFragement
}
}
To use popBackStackImmediate() you need to *replace FragmentA with FragmentB and use addToBackstack() before commit().
I have created a tabbed activity inside a navigation drawer activity. I have linked the lists inside the navigation drawer with individual fragments. I also used the command ft.addToBackStack(null) before ft.commit(). It was perfectly fine and I was able to use it to close the fragments inside the navigation drawer. now I have created webviews inside the fragments of the tabbed activity (home page). I added the onBackPressed to go back inside the webview and now the addToBackStack method stopped working.
For the navigation drawer fragments,
private void dispaySelectedScreen(int id) {
Fragment fragment = null;
switch (id) {
case R.id.fragment1:
fragment = new Fragment1();
break;
case R.id.fragment2:
fragment = new Fragment2();
break;
case R.id.fragment3:
fragment = new Fragment3();
break;
case R.id.fragment4:
fragment = new fragment4();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack(null);
ft.commit();
}
onBackPressed Method
#Override
public void onBackPressed() {
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (sWebView.canGoBack()) {
sWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (dWebView.canGoBack()) {
dWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate());
}
Please help me out!!!
try this code: override onBackPressed() in your tabbed activity (home page).
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}
I have written a code where I try to navigate in between fragments 1, 2 ,3 ,4. The navigation is like: 1->2->3->4->2.
Each fragment has a button whose onClickListener calls the method in interface which is implemented by the mainactivity, wherein position is passed as parameter.
e.g. onClick on the button in 4th fragment calls the method wherein I pass the position parameter as '2' to call the second fragment.
Now, I have added the transaction 1->2 to the backstack, Using a backstack name "second". When, I try to go from 4>2, I use the function popBackStackImmediate("second", 0). But, the boolean response is false and nothing is popped from the stack.
My questions are :
Why is popBackStackImmediate returning false?
What is the use of second parameter in the same function i.e flag ?
When we add the transaction in the backstack, the transaction is saved and not the fragment. So, where is the fragment object getting saved actually as the backstack saves the transaction?
The MainActivity in my code is :
`
public class MainActivity extends AppCompatActivity implements Frag1.OnFragmentInteractionListener, Frag2.OnFragmentInteractionListener, Frag3.OnFragmentInteractionListener, Frag4.OnFragmentInteractionListener {
LinearLayout layout;
Frag1 frag1;
Frag2 frag2;
Frag3 frag3;
Frag4 frag4;
android.support.v4.app.FragmentTransaction transaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("I", "Main Act");
layout = (LinearLayout) findViewById(R.id.frag);
frag1 = Frag1.newInstance();
transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.add(R.id.frag, frag1, "first");
// frag1 = Frag1.newInstance();
// transaction.add(R.id.frag, frag1, "first1");
// transaction.add(R.id.frag, frag2, "second");
// transaction.add(R.id.frag, frag2, "second");
// transaction.add(R.id.frag, frag3, "third");
// Commit the transaction
// transaction.add(R.id.frag, frag3, "third");
// transaction.replace(R.id.frag, frag2, "second");
transaction.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
// Fragment to activity interface implementation
#Override
public void onFragmentInteraction(int pos) {
if (pos == 2) {
// Fragment f = getSupportFragmentManager().findFragmentByTag("second");
FragmentManager manager = getSupportFragmentManager();
boolean isAvail = manager.popBackStackImmediate("second", 0);
if (isAvail) {
// frag2 = (Frag2) f;
Log.i("MainAct", "Instance of 2 yes");
}else{
transaction = getSupportFragmentManager().beginTransaction();
frag2 = Frag2.newInstance();
Log.i("MainAct", "Instance of 2 No");
transaction.replace(R.id.frag, frag2, "second");
transaction.addToBackStack("second");
transaction.commit();
}
} else if (pos == 3) {
Fragment f = getSupportFragmentManager().findFragmentByTag("third");
transaction = getSupportFragmentManager().beginTransaction();
if (f instanceof Frag3) {
frag3 = (Frag3) f;
Log.i("MainAct", "Instance of 3 yes");
}else{
frag3 = Frag3.newInstance();
Log.i("MainAct", "Instance of 3 No");
}
transaction.replace(R.id.frag, frag3, "third");
transaction.commit();
}
else if (pos == 4) {
Fragment f = getSupportFragmentManager().findFragmentByTag("four");
transaction = getSupportFragmentManager().beginTransaction();
if (f instanceof Frag3) {
frag4 = (Frag4) f;
Log.i("MainAct", "Instance of 4 yes");
}else{
frag4 = Frag4.newInstance();
Log.i("MainAct", "Instance of 4 No");
}
transaction.replace(R.id.frag, frag4, "four");
transaction.commit();
}
}
}`
You are trying to call popBackStackImmediate("second", 0); instead replace the fragment.
Try this,
Create Interface PageTraveller and implement in MainActivity
public interface PageTraveller {
public void openPage(int pageNo);
}
override the method openPage()
#Override
public void openPage(int pageNo) {
android.support.v4.app.Fragment fragment;
switch (pageNo){
case 1:
fragment = getSupportFragmentManager().findFragmentByTag("fragmentOne");
fragmentManager.beginTransaction().replace(R.id.pageContainer,fragment).addToBackStack("fragmentOne").commit();
break;
case 2:
fragment = getSupportFragmentManager().findFragmentByTag("fragmentTwo");
if (fragment instanceof FragmentTwo)
fragmentTwo = (FragmentTwo)fragment;
else
fragmentTwo = new FragmentTwo();
fragmentManager.beginTransaction().replace(R.id.pageContainer,fragmentTwo).addToBackStack("fragmentTwo").commit();
break;
case 3:
fragment = getSupportFragmentManager().findFragmentByTag("fragmentThree");
if (fragment instanceof FragmentTwo)
fragmentThree = (FragmentThree)fragment;
else
fragmentThree = new FragmentThree();
fragmentManager.beginTransaction().replace(R.id.pageContainer,fragmentThree).addToBackStack("fragmentThree").commit();
break;
case 4:
fragment = getSupportFragmentManager().findFragmentByTag("fragmentFour");
if (fragment instanceof FragmentTwo)
fragmentFour = (FragmentFour)fragment;
else
fragmentFour = new FragmentFour();
fragmentManager.beginTransaction().replace(R.id.pageContainer,fragmentFour).addToBackStack("fragmentFour").commit();
break;
}
}
Create First fragment FragmentOne
public class FragmentOne extends Fragment{
PageTraveller pageTraveller;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View viewOne = inflater.inflate(R.layout.fragment_one,null);
Button btnOne = (Button)viewOne.findViewById(R.id.text1);
btnOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pageTraveller.openPage(2);
}
});
return viewOne;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
pageTraveller = (PageTraveller) context;
}
}
in XML fragment_one add
<Button
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:text="Fragment 1"/>
Create FragmentTwo, FragmentThree, FragmentFour same way as above.
but in your FragmentFour call pageTraveller.openPage(2);
For more reference try 1. go back to the previous fragment in the backstack
Fragments official Android Developer website
Its work for me, try it may help you.