I have 3 Fragments A, B and C. When I press a button in fragment A, I have to navigate to fragment B (to initialize it) which should implicitly navigate to fragment C. Meanwhile, it should not be added to backstack, so that when I return back from fragment C, it should directly come back to fragment A. Can someone tell how to do this?
I have tried not adding it to the backstack, but it doesn't work out. It throws NullPointerException while coming back.
final int fragId = manager
.beginTransaction()
.replace(R.id.main_container, fragment, MAIN_FRAGMENT_TAG )
.commitAllowingStateLoss();
if you pass argument correctly to your fragment, when pop from backStack this bundle restore well!
public class HomeProfileFragment extends Fragment {
public static HomeProfileFragment newInstance(String name){
Bundle args = new Bundle();
args.putString("ARG_NAME",name);
HomeProfileFragment fragment = new HomeProfileFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String name = getArguments().getString("ARG_NAME");
}
}
and just use replace for adding to backStack:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frag_container, fragment, fragment.getClass().getSimpleName())
.addToBackStack(fragment.getClass().getSimpleName()).commit();
and implement onBackPressed() :
#Override
public void onBackPressed() {
if (fragmentManager.getBackStackEntryCount() > 0)
fragmentManager.popBackStack();
else
super.onBackPressed();
}
Related
I have recently just learnt how to use a fragment manager to send data between two fragments as shown in the codes below:
My First fragment that I am sending the data from:
history_fragment fragment = history_fragment.newInstance(InputValue1, InputValue2, InputValue3, InputValue4);
getFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, fragment).commit();
The Fragment that is receiving the data:
public static history_fragment newInstance(String InputValue1, String InputValue2, String InputValue3, String InputValue4) {
history_fragment fragment = new history_fragment();
Bundle args = new Bundle();
args.putInt("Value1", Integer.parseInt(InputValue1));
args.putInt("Value2", Integer.parseInt(InputValue2));
args.putInt("Value3", Integer.parseInt(InputValue3));
args.putInt("Value4", Integer.parseInt(InputValue4));
fragment.setArguments(args);
return fragment;
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView value1 = view.findViewById(R.id.Value1);
if ( getArguments() != null) {
Value1 = getArguments().getInt("Value1");
}
value1.setText(String.valueOf(Value1));
}
My code is not fully complete but the main problem am I trying to solve is that whenever I go back to my first fragment, the application crashes. I know that the problem is due to the transaction ".replace()", but how should I stop the transaction before returning back to the first fragment?
I have been struggling to implement a super simple app layout, where my MainActivity opens Fragment#1 in its onCreate method, then the Fragment#1 opens Fragment#2 when an item is clicked.
As of right now, when I open Fragment#1 from my MainActivity, I add Fragment#1 to the BackStack. After opening Fragment#2, when I hit the back button the first click does nothing, then the second click sends me all the way back to my login page, skipping past Fragment #1 and MainActivity.
How can I make it so when I hit the back button on Fragment#2, it opens Fragment#1 back up?
(MainActivity opens Fragment#1)
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
SearchListFragment fragment = new SearchListFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment_container, fragment);
transaction.addToBackStack(TAG);
transaction.commit();
}
}
(Fragment#1 opens Fragment#2)
public class SearchListFragment extends Fragment {
public void viewResults(SearchModel search) {
Bundle args = new Bundle();
args.putString("ID", search.getId());
ResultsFragment fragment = new ResultsFragment();
fragment.setArguments(args);
FragmentTransaction transaction = getParentFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment_container, fragment);
transaction.commit();
}
}
EDIT
I should have mentioned that I have tried to handle the back press event myself. I tried adding this to my MainActivity but it did not change the behavior:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getSupportFragmentManager().popBackStack();
}
}
onCreate with
Kotlin
val backpress = requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, true) {
// Handle the back button event
}
Java
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
#Override
public void handleOnBackPressed() {
// Handle the back button event
}
});
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
You can provide your back operations in the relevant sections.
getSupportFragmentManager().beginTransaction().replace(R.id.frag_frame, fragment).addToBackStack("text").commit();
I'm struggling with the changing of a fragment from another fragment. In my main_activity i have a layout-file with a bottomnavigationview and a framelayout for the content on the page. The changing from fragment to fragment on the navigationview workes fine, but if i access a new "subfragment" from a fragment, the new fragment is transparent.
Any suggestions? code below from my fragment and my mainactivity.
MainActivity parentActivity = (MainActivity) getActivity();
parentActivity.switchContent(new VisArrangementInfo(), data, true);
switchContent inside MainActivity:
public void switchContent(final Fragment fragment, Bundle data, final Boolean addToBackStackOption){
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
}
The id content_frame is the id for the layoutfile for my MainActivity. the bottomnavigationview and the framelayout is in this file. the ID for the framelayout is "main_frame".
After my understanding i would want to change the "main_frame" and not the "content_fram" since it's here the main-content is supposed to be. When i do that i can't find the layout for the fragment i try to open at all. Is it because i'm trying to replace the framelayout instead of the whole layout?
In your Fragment A define an interface.
public interface FragmentEventListener {
void onFragmentChangeEvent(Fragment newFragment);
}
private FragmentEventListener listener;
public void setEventListener(FragmentEventListener listener) {
this.listener = listener;
}
In your fragment, when you want to change the fragment, call the method.
if (listener != null) {
listener.onFragmentChangeEvent(FragmentB);
}
In your main activity, implement FragmentEventListener, so you can switch to Fragment B from MainActivity.
public class MainActivity implements FragmentA.FragmentEventListener {
...
...
fragmentB.setEventListener(this); // here identify the listener.
....
#Override
public void onFragmentChangeEvent(Fragment newFragment) {
switchContent // Switch to Fragment B here
}
In the first time use add instead of replace:
public void switchContent(final Fragment fragment, Bundle data, final Boolean addToBackStackOption){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
}
I find myself switching between a lot of Fragments in my card game app.
When my user creates a deck he goes through the following fragments:
Deck List Fragment (Click on 'New Deck') -> Class Selection Fragment (Mage, Warrior etc.) -> Name Selection Fragment -> Back to Deck List Fragment with our new deck listed.
I do this in order to have a smooth deck creation process but here are my two questions:
1) Is it recommended to use more Fragments than required if it makes the UX better and smoother?
2) Note that I do the following in order to switch Fragment:
Fragment fragment = new MyFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Set argument(s) - Not all fragments set arguments
Bundle args = new Bundle();
args.putString("deckName", deckName);
fragment.setArguments(args);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Instead of having similar methods from one Fragment to the other, I wish to create a generic method that takes a variable amount of parameters and the type of Fragment to create and switches to said Fragment.
But I can't seem to figure out how to do it.
Please excuse this lengthy post, and thank you.
Check out my code :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
replaceFragment(new HomeFragment());
}
public void replaceFragment(final Fragment fragment) {
getFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, fragment.getClass().getSimpleName())
.commit();
}
public void addFragment(final Fragment fragment) {
final Fragment hideFragment = getFragmentManager().findFragmentById(R.id.container);
getFragmentManager()
.beginTransaction()
.add(R.id.container, fragment, fragment.getClass().getSimpleName())
.hide(hideFragment)
.addToBackStack(hideFragment.getClass().getSimpleName())
.commit();
}
}
Call above methods in Fragment :
final HomeFragment homeFragment = new HomeFragment();
final Bundle bundle = new Bundle();
bundle.putString("KEY","VALUE");
homeFragment.setArguments(bundle);
((MainActivity) getActivity()).addFragment(homeFragment);
I want to remove a fragment and show a toast when I click a textView. My code shows the toast, but doesn't remove the fragment.
My method:
public void hide(View view) {
My_frag myFrag= new My_frag();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.remove(myFrag);
transaction.commit();
Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_LONG)
.show();
}
My_frag class:
public class My_frag extends android.support.v4.app.Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.my_frag_layout, container, false);
}
}
At some point you must create and add the Fragment correct? You are re-creating the fragment in your hide(...) method so you are trying to remove something that has never been added. Sure you may have added an instance, but not the instance you are trying to remove.
Instead, create a global variable Fragment fragToRemove in your Activity. When you create the fragment (that is where ever you do transaction.add(fragToRemove = new My_Frag);) you will hold an instance. then change your transaction.remove(myFrag) to transaction.remove(fragToRemove) and it should work just fine.
Take the instance of Fragment Transaction other than that was taken while adding fragment to activity and call remove method on that and pass the same instance of Fragment which was used at the time.
Example:
public class MainActivity extends AppCompatActivity {
FragmentTransaction fragmentTransaction;
BlankFragment blankFragment;
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.activity_button);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
blankFragment=new BlankFragment(); //Fragment instance
fragmentTransaction.add(R.id.main_layout,blankFragment).commit();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.remove(blankFragment).commit(); //created different
}
});
}
In the same way you can do in fragments also and can also remove fragment X on the click of component of fragment X.