hello great community I have an app in which I am using bottom navigation with 4 fragments. to move to the last fragment the user must be logged in so when a new user open the app and tap on item 4 a login activity open.
the problem is when I backpress from login activity it moves me to the home fragment 1 which is ok but the state of the bottom navigation item doesn't changes the fragment 4 remain highlighted. so how to manage it that when I return back from the login activity the home fragment item should be highlighted.
[
this is my BottomNAvigation main activity
public class Bottom_Nav extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {
SparseArray<Fragment> myFragments;
String user_type;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom__nav);
SharedPreferences sharedPreferences = getSharedPreferences("DataStore", Context.MODE_PRIVATE);
user_type = sharedPreferences.getString("user_type", "");
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
Nav_Helper.disableShiftMode(bottomNavigationView);
//make array to avoid re creating of fragments
myFragments = new SparseArray<Fragment>();
//loading the default fragment
loadFragment(new HomeFragment());
//getting bottom navigation view and attaching the listener
bottomNavigationView.setOnNavigationItemSelectedListener(this);
}
private void loadFragment(Fragment fragment) {
//switching fragment
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
fragmentTransaction.commit();
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
int id = item.getItemId();
if (id == R.id.navigation_home) {
fragment = new HomeFragment();
myFragments.put(1, fragment);
loadFragment(fragment);
} else if (id == R.id.navigation_use) {
getFragmentManager().popBackStack();
switch (user_type) {
case "detailer":
fragment = new Detailer_Zone();
myFragments.put(4, fragment);
loadFragment(fragment);
break;
case "customer":
fragment = new Customer_Zone();
myFragments.put(4, fragment);
loadFragment(fragment);
break;
case "empty":
Intent intent = new Intent(this, Login_Activity.class);
startActivity(intent);
break;
}
}
else if (id == R.id.navigation_search) {
// get cached instance of the fragment
fragment = myFragments.get(2);
// if fragment doesn't exist in myFragments, create one and add to it
if (fragment == null) {
fragment = new SearchFragment();
myFragments.put(2, fragment);
}
loadFragment(fragment);
} else if (id == R.id.navigation_map) {
// get cached instance of the fragment
fragment = myFragments.get(3);
// if fragment doesn't exist in myFragments, create one and add to it
if (fragment == null) {
fragment = new MapsActivity();
myFragments.put(3, fragment);
}
loadFragment(fragment);
}
return true;
}
Case for Login:
case "empty":
Intent intent = new Intent(this, Login_Activity.class);
startActivityForResult(intent , 101);
break;
Login activity:
When user click on back button execute below code.
setResult(RESULT_CANCELED);
finish();
Handle case in Bottom_Nav activity :
// This method is called when the second activity finishes
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// check that it is the SecondActivity with an OK result
if (requestCode == 101) {
if (resultCode == RESULT_CANCELED) {
onNavigationItemSelected(menuItem)
}
}
}
Try this work around. Replace your case "empty": with this:
case "empty":
bottomNavigationView.setSelectedItemId(R.id.navigation_home);
Intent intent = new Intent(this, Login_Activity.class);
startActivity(intent);
break;
Tell me if this works.
Related
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();
}
}
I have a bottom activity with 3 menus (Fragment). Home , News and Settings. In Setting there is another menus (ListView) . Profil, About and Contact Us.
If you click Profil it will open new activity (Profil.Class) .
My question is how can I open recent tab (Setting), because now if I click back button and back arrow from toolbar it will open My bottom activity with home fragment instead of settings framgent. I trying to send putExtra(); from my SettingFragment but its not working . how can I achieve that?
So here is my MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = getSupportActionBar();
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
Intent intent = getIntent();
Integer tabtoOpen = intent.getIntExtra("Tab",0);
Log.d("TABB", tabtoOpen.toString());
if(tabtoOpen == 0){
fragment = new MainFragment();
}else if(tabtoOpen == 1){
fragment = new NewsFragment();
}else if(tabtoOpen == 2){
fragment = new SettingsFragment();
}
loadFragment(fragment);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle("Home | " +getString(R.string.app_name));
fragment = new MainFragment();
loadFragment(fragment);
return true;
case R.id.navigation_news:
toolbar.setTitle("News | " +getString(R.string.app_name));
fragment = new NewsFragment();
loadFragment(fragment);
return true;
case R.id.navigation_setting:
fragment = new SettingsFragment();
loadFragment(fragment);
toolbar.setTitle("Setting | " +getString(R.string.app_name));
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
and here is my profil
public void onBackPressed() {
Intent i = new Intent(this, Activity_main.class);
i.putExtra("Tab", 2);
this.startActivity(i);
}
And you can set whichever navigation item you'd like to be selected using setSelectedItemId().
else if(tabtoOpen == 2){
navigation.setSelectedItem(R.id.navigation_setting);
}
I have a DrawerMenuActivity suppose "AA" and it has 3 fragments "A", "B" and "C" as it's menu. Fragment "A" is my default screen. Now i have navigated to the fragment "B" which has listview items and each item click will open another new activity "AB". In AB there will be a button and that button click will open another activity "AC". so Basically the flow is as follows,
From AA(DrawerMenuActivity) -> "A" fragemnt -> "B" or "C" fragments -> AB(Activity) -> AC(Activity)
Now what i want to do is to return to fragment "B" from the Activity "AC".
I have replaced the fragments of Activity "AA" like this,
in OnCreate(),
if (savedInstanceState == null) {
A fragment = new A();
replaceFragment(fragment, false, Constants.HOME_FRG_TAG);
Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
if (getIntent().getStringExtra("FROM AC") != null) {
updateDisplay(1);
}
}
};
handler.postDelayed(runnable, 10);
}
and for replacing fragments,
public void updateDisplay(int position) {
Fragment fragment = null;
String tag = null;
switch (position) {
case 0:
clearStack();
mDrawerLayout.closeDrawer(mDrawerList);
break;
case 1:
fragment = new B();
tag = "B";
break;
case 2:
fragment = new C();
tag = "C";
break;
default:
break;
}
if (fragment != null) {
replaceFragment(fragment, true, tag);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
Log.e("Activity", "Error in creating fragment");
}
}
replaceFragment() function,
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
if (backStackTag) transaction.addToBackStack(null);
transaction.commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
and clearStack(),
public void clearStack() {
FragmentManager fm = AA.this.getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
in AC Activity i have tried to come back to fragment "B" like this,
Intent in = new Intent(AC.this, AA.class);
in.putExtra("FROM AC", "from ac");
startActivity(in);
now this does what i intend to do but the problem is when it is loading fragment "A" opens for a brief time and then it comes back to the fragment "B".
How Do i navigate to fragment "B" from Activity "AC" properly?? please any help would be appreciated...!!
First when you go from AB to AC start it as with startActvityForResult, and make sure you don't pass the clear backstack flags. Do it just like this:
public static final int REQ_CODE = 1;
Intent in = new Intent(this, AB.class);
startActivityForResult(in, REQ_CODE);
So the backstack is not cleared. When replacing the fragments in AA do it like this:
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.container, fragmentB).commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
And when you want to get back from activity AC, set the result to RESULT_OK if you want to navigate back to AA or RESULT_CANCELED if not.
setResult(Activity.RESULT_OK);
finish();
In AB, override the onActivityResult method so it sends you back to AA:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQ_CODE) {
if (resultCode == RESULT_OK) {
finish();
}
}
}
so if RESULT_OK is passed, it will go back to AA where the activity was still in onStop() and the state was saved. Also make sure to init your views in onCreate and not in onStart.
Use startActivityForResult to pass params from AC to AA.It's a little complicated.EventBus may be helpful to you.
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.
I'm using NavigationDrawer with some fragments, the problem is when I'm in a fragment and hit the back button, it makes the app close, then I have to open it again, put my username and password all over again to use the app, how can I prevent that from happen?
public class NavigationMain extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
}
public void setFragmentList(int posicao) {
Fragment fragment = null;
switch (posicao) {
case 0:
fragment = new MainFragment();
break;
case 1:
fragment = new MensagensFragment();
break;
case 2:
fragment = new EscolasFragment();
break;
case 3:
fragment = new AutorizadasFragment();
break;
case 4:
fragment = new CadastroFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
navigationAdapter.resetarCheck();
navigationAdapter.setChecked(posicao, true);
layoutDrawer.closeDrawer(linearDrawer);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
}
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
I think you missed to add the fragment transaction in your back stack. Try the following:
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null).commit();