I have a parent activity that stores several fragments, in the activity's onCreate I launch the first fragment
FatherFragment fatherFragment = new FatherFragment ();
RegisterActivity.this.getSupportFragmentManager (). BeginTransaction ().add (R.id.fragmentContainer, parentFragment, "RegisterParentFragment").commit ();
In the application the fragment is displayed correctly, but this fragment has a button that calls another fragment to replace it
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments (bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment, "mapaFragment")
.commit();
The problem resides in that, when making the fragment change (which if it is done) the onCreate method of the parent activity is launched again and shows me the first fragment over of the fragment that has just changed.
I have to assume that it is the view that is running again, but I would like to know if someone could help me find the solution to this problem.
I add that it is a series of steps between fragments and every time I switch, the same problem reappears.
Greetings and thanks for your time. Sorry for bad english.
Adding onClick method.
btnSgtPadre.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
guardarPersona(objPersona);
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}
});
Try this code :
in your Activity create method, which will add this fragment :
public void switchToSecondFragment(Object idPersona){
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}
And call it like this :
btnSgtPadre.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
guardarPersona(objPersona);
((<YourActivityName>) getActivity()).switchToSecondFragment(idPersona);
}
});
Most likely reason could be : App is restarting due to crash. Sometimes we don't get logs as well if app restarts.. try this and let me know.
Crash reason :
replace() method finds the ID inside your current fragment's layout, as you are passing "R.id.fragmentContainer", and your current fragment doesn't contain this "id", so you might me getting crash that this doesn't contain this id called "R.id.fragmentContainer". So you will have to add this fragment by writing method inside Activity itself.
If you want to confirm , add TryCatch :
try{
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}catch(Exception e){
e.printStackTrace();
}
Something strange is happening..!
So I have an activity with TextView in the center of the toolbar acting as toolbar title, once the activity gets launched, I commit the MainFragment or let's name it Fragment (A).
Inside Fragment (A), I replace it with Fragment (B) when a button
gets clicked.
Inside Fragment (B), I replace it with Fragment (C)
when a button gets clicked.
so in each fragment I access the activity's toolbar text view and change it accordingly using this:
TextView title = getActivity().findViewById(R.id.titleText);
title.setText("Some title");
And it works fine in Fragments (A) & (B), but in (C) it shows the title of Fragment (A)??
I even printed a log inside the onCreateView of each fragment and this is what showed up..!
the last two logs showed at the same time..!?
I/MY_TEST: onCreateView: of Fragment (A)
I/MY_TEST: onCreateView: of Fragment (B)
I/MY_TEST: onCreateView: of Fragment (C)
I/MY_TEST: onCreateView: of Fragment (A)
Update
Here's the full click listener
orderDetailsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
AppCompatActivity activity = (AppCompatActivity) getActivity();
Fragment fragment = new Teacher_Bar_Fragment();
Bundle bundle = new Bundle();
bundle.putInt("index", 1); // I use this to show or hide views
fragment.setArguments(bundle);
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.addToBackStack(null);
ft.commit();
}
});
So, what my problem is that in one fragment(w/i a viewpager, I'll call this Fragment A) I click on this dynamically created button that adds a new fragment(I'll call this Fragment B) in a framelayout which allows me to use PayPal service. On PayPal Activity result, Fragment B communicates with the main Activity via a communicator(an interface class) to call Fragment A to change that text. But I'm getting a null pointer exeception crash.
To be specific:
what I did was that I made a global TextView variable that is initialized on click. I did this b/c I have a list of other things that are dynamically inflated and to avoid the TextView from being initialized with wrong layout I initialized it on click.
bidChange.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
eventListChangeKey = keyVal;
eventListChangeIdx = eventListIdx;
eventBiddingChangeIdx = finalI;
priceToChage = (TextView) biddersLayout.findViewById(R.id.single_list_bidder_bid_price);
Bundle bundle = new Bundle();
bundle.putInt("auctionID", auctionId);
bundle.putInt("dateID", dateId);
bundle.putInt("FromWhere", 2);
Fragment fragment = new Fragment_Home_ItemInfo_Bid();
fragment.setArguments(bundle);
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.container_mainScreen, fragment, "itemInfo_bid")
.addToBackStack(null)
.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
});
In the main activity
public void changeBidderPrice(String s) {
Fragment fragment = viewPagerAdapter.getItem(1);
((Fragment_List) fragment).changePrice(s);
}
is what I do
back in Fragment A
public void changePrice(String val) {
priceToChage.setText(val);
dataMap.get(eventListChangeKey).get(eventListChangeIdx).getBidList().get(eventBiddingChangeIdx).setPrice(val);
}
I've thought this over an over but I just can't figure this out. I've searched for similar cases in StackOverflow but I wasn't able to get a help.
Would the problem be the way I initialize that TextView? or is it the way I'm calling Fragment A from the main activity?
for fragments onViewCreated() is called after onCreateView() and ensures that the fragment's root view is non-null. Any view setup should happen here. E.g., view lookups, attaching listeners.
source : codepath
for activities onCreate()
I am creating tabs in my app using info from
epidemian answer
I created main class which handles tabs, this class extends TabActivity and creates tabs:
Resources res = getResources();
TabHost tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass(this, stackA.class);
spec = tabHost.newTabSpec("tab1").setIndicator("Tab 1",
res.getDrawable(android.R.drawable.ic_menu_search))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, stackB.class);
spec = tabHost.newTabSpec("tab2").setIndicator("Tab 2",
res.getDrawable(android.R.drawable.ic_menu_search))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(0);
Then for every tab is created FragmentActivity and this gives possibility to create stack in every tab. My fragments is created:
protected void navigateTo(Fragment newFragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, newFragment);
ft.addToBackStack(null);
ft.commit();
}
public class fragmentA extends Fragment{
private LinearLayout ll;
private FragmentActivity fa;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fa = super.getActivity();
ll = (LinearLayout) inflater.inflate(R.layout.fragmenta, container, false);
Button next = (Button) ll.findViewById(R.id.button1);
next.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
((ActivityInTab) getActivity()).navigateTo(new fragmentB());
}
});
return ll;
}
}
This is working. What is wrong that when i am at tab 1 and fragment B (first fragment in stack is A), rotate my device and then it go back at fragment A.
epidemian said something about orientations and using setArguments/getArguments, but i am new to android programming so i don't really know how to do that:
Finally, if you need to survive orientation changes, it's important
that your fragments are created using setArguments/getArguments. If
you set instance variables in your fragments' constructors you'll be
screwed. But fortunately that's really easy to fix: just save
everything in setArguments in the constructor and then retrieve those
things with getArguments in onCreate to use them.
int x;
Bundle args = new Bundle();
args.putString("variable", x);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment = Fragment.instantiate(getActivity(), MyFragment.class.getName(), args);
ft.replace(R.id.layout1, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
than in the fragment:
getArguments().getInt("variable");
You can use Fragment.setRetainInstance(true) for this. See this related question.
You can prevent the Activity from beeing destroyed due to orientation change. Add the following line to your manifest of your TabActivity (orientation change + keyboard visibility changes)
android:configChanges="keyboardHidden|orientation"
See here for description.
setArguments/getArguments does not help you here. As he stated you may use it to save instance variables and retrieving them after orientation change. But with the given line above you do not need that because your Activity/Fragments won't get destroyed
I have a fragment inside a group activity and I want to replace it with another fragment:
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
SectionDescriptionFragment bdf = new SectionDescriptionFragment();
ft.replace(R.id.book_description_fragment, bdf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
It works fine when it is done as a seperate project without using activity group, every thing works fine in log cat as control goes inside getview(), but no view is visible, not even any exception arises, I want the book detail fragment to be replaced by section detail fragment.
Xml of book detail fragment has id book_description_fragment and xml for section description fragment has id section_description_fragment.
The above code is in onClick method of an item, I want that when user taps on an item in horizontal scroll view, then the fragment changes.
Fragments that are hard coded in XML, cannot be replaced. If you need to replace a fragment with another, you should have added them dynamically, first of all.
Note: R.id.fragment_container is a layout or container of your choice in the activity you are bringing the fragment to.
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Please see this Question
You can only replace a "dynamically added fragment".
So, if you want to add a dynamic fragment, see this example.
I've made a gist with THE perfect method to manage fragment replacement and lifecycle.
It only replace the current fragment by a new one, if it's not the same and if it's not in backstack (in this case it will pop it).
It contain several option as if you want the fragment to be saved in backstack.
=> See Gist here
Using this and a single Activity, you may want to add this to your activity:
#Override
public void onBackPressed() {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
return;
}
super.onBackPressed();
}
Use the below code in android.support.v4
FragmentTransaction ft1 = getFragmentManager().beginTransaction();
WebViewFragment w1 = new WebViewFragment();
w1.init(linkData.getLink());
ft1.addToBackStack(linkData.getName());
ft1.replace(R.id.listFragment, w1);
ft1.commit();
Use ViewPager. It's work for me.
final ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.vp_pager);
button = (Button)result.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewPager.setCurrentItem(1);
}
});
hope you are doing well.when I started work with Android Fragments then I was also having the same problem then I read about
1- How to switch fragment with other.
2- How to add fragment if Fragment container does not have any fragment.
then after some R&D, I created a function which helps me in many Projects till now and I am still using this simple function.
public void switchFragment(BaseFragment baseFragment) {
try {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
if (getSupportFragmentManager().findFragmentById(R.id.home_frame) == null) {
ft.add(R.id.home_frame, baseFragment);
} else {
ft.replace(R.id.home_frame, baseFragment);
}
ft.addToBackStack(null);
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
enjoy your code time :)
you can use simple code its work for transaction
Fragment newFragment = new MainCategoryFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame_NavButtom, newFragment);
ft.commit();
You Can Use This code
((AppCompatActivity) getActivity()).getSupportFragmentManager().beginTransaction().replace(R.id.YourFrameLayout, new YourFragment()).commit();
or You Can This Use Code
YourFragment fragments=(YourFragment) getSupportFragmentManager().findFragmentById(R.id.FrameLayout);
if (fragments==null) {
getSupportFragmentManager().beginTransaction().replace(R.id.FrameLayout, new Fragment_News()).commit();
}
I change fragment dynamically in single line code
It is work in any SDK version and androidx
I use navigation as BottomNavigationView
BottomNavigationView btn_nav;
FragmentFirst fragmentFirst;
FragmentSecond fragmentSecond;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
fragmentFirst = new FragmentFirst();
fragmentSecond = new FragmentSecond ();
changeFragment(fragmentFirst); // at first time load the fragmentFirst
btn_nav = findViewById(R.id.bottomNav);
btn_nav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch(menuItem.getItemId()){
case R.id.menu_first_frag:
changeFragment(fragmentFirst); // change fragmentFirst
break;
case R.id.menu_second_frag:
changeFragment(fragmentSecond); // change fragmentSecond
break;
default:
Toast.makeText(SearchActivity.this, "Click on wrong bottom SORRY!", Toast.LENGTH_SHORT).show();
}
return true;
}
});
}
public void changeFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout_changer, fragment).commit();
}
In kotlin you can do:
// instantiate the new fragment
val fragment: Fragment = ExampleFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.book_description_fragment, fragment)
transaction.addToBackStack("transaction_name")
// Commit the transaction
transaction.commit()
This will work if you're trying to change the fragment from another fragment.
Objects.requireNonNull(getActivity()).getSupportFragmentManager()
.beginTransaction()
.replace(R.id.home_fragment_container,new NewFragment())
NOTE As stated in the above answers, You need to have dynamic fragments.
You can use fragment-ktx
// If you are in fragmet
childFragmentManager.beginTransaction()
// or if you are in activiry
supportFragmentManager.beginTransaction()
// Create and commit a new transaction
supportFragmentManager.commit {
setReorderingAllowed(true)
// Replace whatever is in the fragment_container view with this fragment
replace<ExampleFragment>(R.id.fragment_container)
}
To replace a fragment with another one do this, Note that R.id.fragment comes from the id that you give to the first tag of the fragment in the XML.
barAudioPlaying.setOnClickListener(view -> {
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment,new HomeFragment())
.commit();