I have ActionBar Tabs setup. It consists of 4 tabs. Everything is fine until I navigate away from TabbedFragment and returning back.
I create tabs like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActionBar actionBar = getActionBar();
tabs = Lists.newArrayList();
tabs.add(new TabDefinition<>("Tab 1"));
tabs.add(new TabDefinition<>("Tab 2"));
tabs.add(new TabDefinition<>("Tab 3"));
tabs.add(new TabDefinition<>("Tab 4"));
for (TabDefinition tab : tabs) {
actionBar.addTab(actionBar.newTab()
.setText(tab.text)
.setTag(tab.tag)
.setTabListener(this));
}
}
And initialize adapter like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.paging_tab_container, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewPager = (ViewPager) view.findViewById(R.id.pager);
viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {
#Override
public Fragment getItem(int position) {
return tabs.get(position).fragment;
}
#Override
public int getCount() {
return tabs.size();
}
});
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
viewPager.setCurrentItem(getActionBar().getSelectedNavigationIndex(), true);
}
When returning back to TabbedFragment selected tab and 1 next to it would not have any content. Just empty view. But if I select current + 2 fragment content is loaded. And then returning to that first fragment content is reloaded.
For example I have A, B, C, D tabs. Before leaving TabbedFragment I had selected tab A.
When returning to TabbedFragment I still am at tab A, but it's empty. So is tab B.
But when selecting tab C it is created and loaded. Returning to tab A it is recreated.
What could be the problem here?
After a while ran into the same problem again, so updating this question.
If you're using FragmentStatePagerAdapter you should provide FragmentManager via getChildFragmentManager() instead of getFragmentManager(). See Issue 55068: ViewPager doesn't refresh child fragments when back navigation via backstack
Okay so When using a FragmentStatePagerAdapter your fragments will be destroyed when you navigate anymore than one fragment Away since by default offScreenPageLimit is set to 1 by default just as mentioned above.
Typically this Class is used for an activity that has a very large set of Fragments, i.e have to scroll through a large amount of views. If your application does not need more than say 3-4 tabs I would suggest using FragmentPagerAdapter instead, and then specifying your offScreenPageLimit to something like 3, so if you get to the 4th Tab, all 3 tabs before will still be in memory.
Here is some Sample Code for a project on github that i created illustrating how to dynamically load the fragments if you don't want to add this offScreenPageLimit.
https://github.com/lt-tibs1984/InterfaceDemo/blob/master/src/com/divshark/interfacedemo/InterfaceDemoMain.java
Walk through all this code in this Class, and you will see how I'm dynamically loading the fragments, each time my ViewPager is slid over. Most notably at the bottom.
You can download this code, and use it as a test base for what you want to do.
Try adding the setOffScreenPageLimit(2) in the onCreate() method for the viewPager and notice the different behavior. To check the behavior, edit the text in fragment 1. Navigate Away and navigate back, with this set or not. You will see when it is set, the fragment's text remains what you change it to, since the fragment is never recreated.
Please provide additional questions if you have them.
GoodLuck
UPDATE
private static final String [] fragmentClasses = {"com.example.project.YourFragment1","com.example.project.YourFragment2","com.example.project.YourFragment3"};
viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {
#Override
public Fragment getItem(int position) {
Fragment fragmentAtPosition = null;
// $$$$ This is the Important Part $$$$$
// Check to make sure that your array is not null, size is greater than 0 , current position is greater than equal to 0, and position is less than length
if((fragmentClasses != null) && (fragmentClasses.length > 0)&&(position >= 0)&& (position < fragmentClasses.length))
{
// Instantiate the Fragment at the current position of the Adapter
fragmentAtPosition = Fragment.instantiate(getBaseContext(), fragmentClasses[position]);
fragmentAtPosition.setRetainInstance(true);
}
return fragmentAtPosition;
}
#Override
public int getCount() {
return fragmentClasses.length;
}
});
The problem exists in the Fragments you use as tabs, I think. They seem to not show anything when they are resumed (see Fragment lifecycle). The "weird" issue that only the currently selected +/-1 tab is empty, is because the offScreenPageLimit of your ViewPager is 1 by default. All tabs above this threshold are re-created.
Therefore, increasing the value will -- in your case -- cause all your tabs to appear empty after resuming. Check in your Fragment code which lifecycle methods you use to inflate your layout, set adapters and so forth, because that's what's causing your trouble.
I guess this happens because while loading fragment android loads current and current+1, if you debug you would not see onPause getting called for the immediate next fragment.
You can reload content programmatically in onTabChanged() method of TabHost.OnTabChangeListener.
After doing much research, this worked for me.
I have a complex layout with 3 tabs in a fragment, that gets switched out for other fragments. I realized that the ViewpagerAdapter will retain state, even if you press the home button. My problem was switching back and forth would null out the child fragment UI view elements and crash. The key is to not new out your ViewPagerAdapter. Adding the null check for the Adapter worked for me. Also, be sure to allocate setOffscreenPageLimit() for your needs. Also, from what I understand setRetainInstance(true); should not be used for fragments that have UI, it is designed for headless fragments.
In the fragment that holds your Tabs:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_tab, container, false);
tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
viewPager = (ViewPager) view.findViewById(R.id.viewPager);
//Important!!! Do not fire the existing adapter!!
if (viewPagerAdapter == null) {
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
viewPagerAdapter.addFragments(new AFragment(), "A");
viewPagerAdapter.addFragments(new BFragment(), "B");
viewPagerAdapter.addFragments(new CFragment(), "C");
}
//Allocate retention buffers for three tabs, mandatory
viewPager.setOffscreenPageLimit(3);
tabLayout.setupWithViewPager(viewPager);
viewPager.setAdapter(viewPagerAdapter);
return view;
}
Or more simply when navigating back to tabbedfragment (assuming you use an intent and the fragment is within an activity) use:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
This keeps the original activity and moves it to the top of the stack rather than recreating it, thus you never need to recreate the viewPager.
I have a Fragment (I'll call it pagerFragment) that is added to the backstack and is visible. It holds a viewPager with a FragmentPagerAdapter. The FragmentPagerAdapter holds (let's say) two fragments: A and B.
First adding of the fragments works great.
Fragment A has a button that once clicked, adds a fragment (C) to the backstack.
The problem is this: if I add that fragment (C), and then click back, the pagerAdapter is empty, and I cannot see any fragments inside.
If I use a hack, and destroy the children fragments (A and B) in the pagerFragments onDestroyView(), this solves the problem, although I don't wan't to use this hack.
Any ideas what the issue could be?
I had the same problem. The solution for me was simple:
in onCreateView I had:
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
.getSupportFragmentManager());
where SectionPageAdapter is something like this:
class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}
after changing getSupportFragmentManager to
mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
it started working!
It sounds like you are using nested fragments since your ViewPager is inside a PagerFragment. Have you passed getChildFragmentManager() to the constructor of your FragmentPagerAdapter? If not you should.
I don't think you need a FragmentStatePagerAdapter, but I would give that a shot since it handles saving and restoring Fragment state. The fact that your onDestroyView() hack works makes me think that you may want a FragmentStatePagerAdapter.
It could also have something to do with the way the FragmentPagerAdapter adds Fragments. The FragmentPagerAdapter doesn't add Fragments to the backstack. Imagine if you had a 10+ pages added in your ViewPager and the user swiped through them. The user would need to hit back 11 times just to back out of the app.
It may also be related to this post: Nested Fragments and The Back Stack.
Also I'm not sure what you are adding the Fragment C to. Are you adding it to the same container as the ViewPager?
Well at least you have a few options to investigate. In these situations I like to debug down into the Android SDK source code and see what's causing the behaviour. I recommend grabbing the AOSP source and adding frameworks/support and frameworks/base as your SDK sources. That's the only true way to understand what is happening and avoid making random changes until things work.
Use getChildFragmentManager() instead of getSupportFragmentManager().
It will work fine.
I just faced the problem in our project as well. The root cause is the way the the FragmentPagerAdapter works:
The FragmentPagerAdapter just detaches a Fragment he does not currently need from its View but does not remove it from its FragmentManager. When he wants to display the Fragment again he looks if the FragmentManager still contains the Fragment using a tag that is created from the view id of the ViewPager and the id returned by the adapters getItemId(position) call. If he finds a Fragment he just schedules an attach of the Fragment to its View within the updating transaction of the FragmentManager. Only if he does not find a Fragment this way he creates a new one using the adapters getItem(position) call!
The problem with a Fragment containing a ViewPager with a FragmentPagerAdapter is, that the contents of the FragmentManager is never cleaned up when the containing Fragment is put to the back stack. If the containing Fragment comes back from the back stack it creates a new View but the FragmentManager still contains the fragments that were attached to the old view and the attach of an existing fragment does not work anymore.
The easiest way to get rid of this problem is to avoid nested fragments. :)
The second easiest way is as already mentioned in other posts to use the ChildFragmentManager for the FragmentPagerAdapter as this one gets properly updated during the life cycle of the container fragment.
As there are projects (as my current one) where both options are not possible, I have published here a solution that works with an arbitrary FragmentManager by using the hashCode of the sub fragments as the item id of the fragment at that position. It comes at the price of storing all fragments for all positions within the adapter.
public class MyPagerAdapter extends FragmentPagerAdapter {
private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
}
#Override
public Fragment getItem(int position) {
return getSubFragmentAtPosition(position);
}
#Override
public int getCount() {
return COUNT;
}
#Override
public long getItemId(int position) {
return getSubFragmentAtPosition(position).hashCode();
}
//The next three methods are needed to remove fragments no longer used from the fragment manager
#Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
cleanupTransaction = fragmentManager.beginTransaction();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
cleanupTransaction.remove((Fragment) object);
}
#Override
public void finishUpdate(ViewGroup container) {
super.finishUpdate(container);
cleanupTransaction.commit();
}
private Fragment getSubFragmentAtPosition(int position){
if (subFragments[position] == null){
subFragments[position] = ...;
}
return subFragments[position];
}
}
I had same problem, just set adapter twice at once and that's all.
Example code :
private fun displayImg(photo1:String, photo2:String){
val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!!
val arr = ArrayList<String>()
arr.add(photo1)
arr.add(photo2)
pager.adapter = AdapterImageView(fm, arr ,arr.size)
pager.adapter = AdapterImageView(fm, arr ,arr.size)
}
Currently, with a FragmentActivity, I toggle among 2 type of Fragments using the following code.
private void toggle() {
Fragment oldFragment = getSupportFragmentManager().findFragmentById(R.id.content);
Fragment fragment = null;
if (oldFragment instanceof ColorFragment) {
fragment = new ViewPagerFragment();
} else {
fragment = new ColorFragment(android.R.color.black);
}
getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
}
2 Fragments are being toggle.
ColorFragment - A simple fragment which fill up its background with solid black color.
ViewPagerFragment - A fragment contains ViewPager. User can swipe between a purple color fragment, and a blue color fragment.
The code which responsible for swiping purple and blue color fragments are as below.
private static class MyFragmentPagerAdapter extends FragmentPagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 2;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ColorFragment(android.R.color.holo_purple);
default:
return new ColorFragment(android.R.color.holo_blue_bright);
}
}
}
However, I encounter the weird behavior during toggling.
Black color fragment was shown.
Toggling.
View pager, which can swipe between purple and blue fragments shown.
Toggling.
Black color fragment was shown.
Toggling.
Nothing shown, as MyFragmentPagerAdapter's getItem is not being triggered.
I think my situation is similar to FragmentPagerAdapter getItem is not called
However, I prefer not to use FragmentStatePagerAdapter, because of the cost of potentially more overhead when switching between pages.
Any workaround to overcome this problem?
I include a complete workable source code to demonstrate this problem : https://www.dropbox.com/s/jok9tz5ktvfcteo/viewpagerbug.zip
Any workaround to overcome this problem?
I've downloaded your code and the problem appears because you don't handle those Fragments right. Most precisely you use nested Fragments in the ViewPager based Fragment and for that ViewPager you create the adapter like this:
MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getFragmentManager());
Instead, you should be using getChildFragmentManager() to bind the nested fragments:
MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());
Also, you shouldn't pass data through a constructor to a Fragment as that data will not survive a configuration change and bad things will start to appear. Use a Bundle instead.
Global working tested solution.
getSupportFragmentManager() keeps the null reference some times and View pager does not create new fragment instance.Since it finds reference to same fragment. So to over come this use getChildFragmentManager() solves problem in simple way.
Don't
new PagerAdapter(getSupportFragmentManager(), fragments);
Do
new PagerAdapter(getChildFragmentManager() , fragments);
Simple use FragmentStatePagerAdapter instead of FragmentPagerAdapter
or
you can use new MyFragmentPagerAdapter(this.getChildFragmentManager())
Hope it will help you :)
In my case I was correctly calling
MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());
but then in the nested fragment I was trying to replace the container fragment with another one by using:
getFragmentManager()
You need to go to the activity and call
getActivity().getSupportFragmentManager();
In my cases it worked after add this to my FragmentPagerAdapter:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
and I also used getChildFragmentManager() like Luksprog said
Firstly, I know these subjects have been created a lot of time on stackoverflow, but I don't have found the solution to my problems. Secondly, I'm french, so my english is not perfect, sorry per advance and tell me if you don't understand something. And to finish this introduction, it's the first time that I'm dealing with fragments, so, sorry if there is something that I don't have well understand !
I have three buttons, that allow to switch between three fragments.
Inside one of these fragments, I have a view pager with two fragments. For the moment, each fragments (there are 5), only contains a TextView.
I'm using the latest version of android-support-v4 (I have read a lot of subject in stackoverflow that say that the latest version of support solve the "Recursive entry to executePendingTransactions" error that I have).
My two problems :
When I click two times in one button, I have an IllegaleStateException "can't change tag of fragment". I was able to fix that by creating a new fragment on onButtonSelected method, but I don't want to recreate fragment each time, for memory reasons and for functional reasons : fragment have to keep her state. This problem is not my main problem, indeed, i know that to disable the button when user is already on fragment is possible, but it's strange to have an exception when this management is not done, no ?.
When I go out from the fragment with the view pager, and I go back to this fragment, I have an IllegalStateException "Recursive entry to executePendingTransactions". I can fix this by setting my adapter on an handler, or use FragmentStatePagerAdapter instead of FragmentPageAdapter (see Display fragment viewpager within a fragment), but even if my application don't crash, when I go back to my fragment with the view pager, the view pager has disapear !
Can you help me ?
Java source code is bellow, layout source code is, I think, useless.
MainActivity :
public class MainActivity extends SherlockFragmentActivity{
private SherlockFragment fragmentOne, fragmentTwo, fragmentThree;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this.fragmentOne = new fragmentOne();
// this.fragmentTwo = new fragmentTwo();
// this.fragmentThree = new fragmentThree();
// Call new or instanciate ? What's the correct way ?
this.fragmentOne = (SherlockFragment) SherlockFragment.instantiate(this, FragmentOne.class.getName());
this.fragmentTwo = (SherlockFragment) SherlockFragment.instantiate(this, FragmentTwo.class.getName());
this.fragmentThree = (SherlockFragment) SherlockFragment.instantiate(this, FragmentThree.class.getName());
// Add fragment
FragmentTransaction transaction = (
this.getSupportFragmentManager().beginTransaction()
);
transaction.add(
R.id.tab_fragment,
this.fragmentOne,
this.fragmentOne.toString()
);
transaction.commit();
}
public void onButtonSelected(View v){
switch (v.getId()){
case R.id.button_one_tab:{
showFragment(this.fragmentThree);
break;
}
case R.id.button_two_tab:{
showFragment(this.fragmentOne);
break;
}
case R.id.button_three_tab:{
showFragment(this.fragmentTwo);
break;
}
default:{
break;
}
}
}
public void showFragment(SherlockFragment fragmentToShow){
FragmentTransaction transaction = (
this.getSupportFragmentManager().beginTransaction()
);
transaction.replace(R.id.tab_fragment, fragmentToShow, fragmentToShow.toString());
transaction.commit();
}
}
Fragment two and three only inflate a layout that only contains a TextView.
Fragment one (note that i'm using a DirectionalViewPager - a lib - instead of a ViewPager):
public class FragmentOne extends SherlockFragment{
private FragmentOneAdapter fragmentOneAdapter;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set up the pager
final DirectionalViewPager pager = (DirectionalViewPager)getActivity().findViewById(R.id.pager);
if (this.fragmentOneAdapter== null){
this.fragmentOneAdapter= new FragmentOneAdapter (getActivity().getSupportFragmentManager());
}
pager.setAdapter(fragmentOneAdapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_landing_page, container, false);
}
FragmentOneAdapter :
public class FragmentOneAdapter extends FragmentPagerAdapter{
private ArrayList<SherlockFragment> fragmentsList;
public FragmentOneAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
SherlockFragment fragmentFour = new FragmentFour();
SherlockFragment fragmentFive = new FragmentFive();
this.fragmentsList = new ArrayList<SherlockFragment>();
this.fragmentsList.add(fragmentFour);
this.fragmentsList.add(fragmentFive);
}
#Override
public Fragment getItem(int position) {
return this.fragmentsList.get(position);
}
#Override
public int getCount() {
return this.fragmentsList.size();
}
}
Thanks per advance for your help !
I have solved my problem !
I have simply replace getSupportFragmentManager() on FragmentOne to getChildFragmentManager(). Then, I have edited my onButtonSelected's method by creating a new instance of fragment each time instead of using my three different instances (if I don't do that, I have an exception : java.lang.IllegalStateException: Activity has been destroyed).
I have still a problem with this solution : I lose the state of each fragment each time I'm switching between fragmentOne, fragmentTwo and fragmentThree. Do you have a solution for that ?
I have a fragment I am trying to add into a view.
FragmentManager fragMgr=getSupportFragmentManager();
feed_parser_activity content = (feed_parser_activity)fragMgr
.findFragmentById(R.id.feedContentContainer);
FragmentTransaction xaction=fragMgr.beginTransaction();
if (content == null || content.isRemoving()) {
content=new feed_parser_activity(item.getLink().toString());
xaction
.add(R.id.feedContentContainer, content)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(null)
.commit();
Log.e("Abstract", "DONE");
}
When this code is executed I get the following error in debug..
java.lang.IllegalArgumentException: No view found for id 0x7f080011
for fragment feed_parser_activity{41882f50 #2 id=0x7f080011}
feed_parser_activity is a Fragment that is set to Fragment layout in xml.
I am using a FragmentActivity to host the Fragment Layout holding the feed_parser_layout.
Am I coding this correctly above?
I was having this problem too, until I realized that I had specified the wrong layout in setContentView() of the onCreate() method of the FragmentActivity.
The id passed into FragmentTransaction.add(), in your case R.id.feedContentContainer, must be a child of the layout specified in setContentView().
You didn't show us your onCreate() method, so perhaps this is the same problem.
This error also occurs when having nested Fragments and adding them with getSupportFragmentManager() instead of getChildFragmentManager().
The solution was to use getChildFragmentManager()
instead of getFragmentManager()
when calling from a fragment. If you are calling the method from an activity, then use getFragmentManager().
That will solve the problem.
Another scenario I have met.
If you use nested fragments, say a ViewPager in a Fragment with it's pages also Fragments.
When you do Fragment transaction in the inner fragment(page of ViewPager), you will need
FragmentManager fragmentManager = getActivity().getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
getActivity() is the key here.
...
I had this problem (when building my UI in code) and it was caused by my ViewPager (that showed Fragments) not having an ID set, so I simply used pager.setID(id) and then it worked.
This page helped me figure that out.
In my case I was trying to show a DialogFragment containing a pager and this exception was thrown when the FragmentPagerAdapter attempted to add the Fragments to the pager. Based on howettl answer I guess that it was due to the Pager parent was not the view set in setContentView() in my FragmentActivity.
The only change I did to solve the problem was to create the FragmentPagerAdapter passing in a FragmentMager obtained by calling getChildFragmentManager(), not the one obtained by calling getFragmentManager() as I normally do.
public class PagerDialog extends DialogFragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.pager_dialog, container, false);
MyPagerAdapter pagerAdapter = new MyPagerAdapter(getChildFragmentManager());
ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(pagerAdapter);
return rootView;
}
}
This exception can also happen if the layout ID which you are passing to FragmentTransaction.replace(int ID, fragment) exists in other layouts that are being inflated. Make sure the layout ID is unique and it should work.
With Nested fragments
For me by using getChildFragmentManager() instead of getActivity().getSupportFragmentManager() resolved crash
java.lang.IllegalArgumentException: No view found for id
An answer I read on another thread similar to this one that worked for me when I had this problem involved the layout xml.
Your logcat says "No view found for id 0x7f080011".
Open up the gen->package->R.java->id and then look for id 0x7f080011.
When I had this problem, this id belonged to a FrameLayout in my activity_main.xml file.
The FrameLayout did not have an ID (there was no statement android:id = "blablabla").
Make sure that all of your components in all of your layouts have IDs, particularly the component cited in the logcat.
I got this error when I upgraded from com.android.support:support-v4:21.0.0 to com.android.support:support-v4:22.1.1.
I had to change my layout from this:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
To this:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/container_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</FrameLayout>
So the layout MUST have a child view. I'm assuming they enforced this in the new library.
I know this has already been answered for one scenario, but my problem was slightly different and I thought I'd share in case anybody else is in my shoes.
I was making a transaction within onCreate(), but at this point the view tree has not been inflated so you get this same error. Putting the transaction code in onResume() made everything run fine.
So just make sure your transaction code runs after the view tree has been inflated!
I was facing a Nasty error when using Viewpager within Recycler View.
Below error I faced in a special situation.
I started a fragment which had a RecyclerView with Viewpager (using FragmentStatePagerAdapter). It worked well until I switched to different fragment on click of a Cell in RecyclerView, and then navigated back using Phone's hardware Back button and App crashed.
And what's funny about this was that I had two Viewpagers in same RecyclerView and both were about 5 cells away(other wasn't visible on screen, it was down). So initially I just applied the Solution to the first Viewpager and left other one as it is (Viewpager using Fragments).
Navigating back worked fine, when first view pager was viewable . Now when i scrolled down to the second one and then changed fragment and came back , it crashed (Same thing happened with the first one). So I had to change both the Viewpagers.
Anyway, read below to find working solution.
Crash Error below:
java.lang.IllegalArgumentException: No view found for id 0x7f0c0098 (com.kk:id/pagerDetailAndTips) for fragment ProductDetailsAndTipsFragment{189bcbce #0 id=0x7f0c0098}
Spent hours debugging it. Read this complete Thread post till the bottom applying all the solutions including making sure that I am passing childFragmentManager.
Nothing worked.
Finally instead of using FragmentStatePagerAdapter , I extended PagerAdapter and used it in Viewpager without Using fragments. I believe some where there is a BUG with nested fragments. Anyway, we have options. Read ...
Below link was very helpful :
Viewpager Without Fragments
Link may die so I am posting my implemented Solution here below:
public class ScreenSlidePagerAdapter extends PagerAdapter {
private static final String TAG = "ScreenSlidePager";
ProductDetails productDetails;
ImageView imgProductImage;
ArrayList<Imagelist> imagelists;
Context mContext;
// Constructor
public ScreenSlidePagerAdapter(Context mContext,ProductDetails productDetails) {
//super(fm);
this.mContext = mContext;
this.productDetails = productDetails;
}
// Here is where you inflate your View and instantiate each View and set their values
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.product_image_slide_cell,container,false);
imgProductImage = (ImageView) layout.findViewById(R.id.imgSlidingProductImage);
String url = null;
if (imagelists != null) {
url = imagelists.get(position).getImage();
}
// This is UniversalImageLoader Image downloader method to download and set Image onto Imageview
ImageLoader.getInstance().displayImage(url, imgProductImage, Kk.options);
// Finally add view to Viewgroup. Same as where we return our fragment in FragmentStatePagerAdapter
container.addView(layout);
return layout;
}
// Write as it is. I don't know much about it
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
/*super.destroyItem(container, position, object);*/
}
// Get the count
#Override
public int getCount() {
int size = 0;
if (productDetails != null) {
imagelists = productDetails.getImagelist();
if (imagelists != null) {
size = imagelists.size();
}
}
Log.d(TAG,"Adapter Size = "+size);
return size;
}
// Write as it is. I don't know much about it
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
Hope this was helpful !!
Just in case someone's made the same stupid mistake I did; check that you're not overwriting the activity content somewhere (i.e. look for additional calls to setContentView)
In my case, due to careless copy and pasting, I used DataBindingUtil.setContentView in my fragment, instead of DataBindingUtil.inflate, which messed up the state of the activity.
I had the same issue but my issue was happenning on orientation change. None of the other solutions worked. So it turns out that I forgot to remove setRetainInstance(true); from my fragments, when doing a two or one pane layout based on screen size.
My mistake was on the FragamentTransaction.
I was doing this t.replace(R.layout.mylayout); instead of t.replace(R.id.mylayout);
The difference is that one is the layout and the other is a reference to the layout(id)
This happens when you are calling from a fragment inside another one.
use :
getActivity().getSupportFragmentManager().beginTransaction();
I had this same issue, let me post my code so that you can all see it, and not do the same thing that I did.
#Override
protected void onResume()
{
super.onResume();
fragManager = getSupportFragmentManager();
Fragment answerPad=getDefaultAnswerPad();
setAnswerPad(answerPad);
setContentView(R.layout.abstract_test_view);
}
protected void setAnswerPad(AbstractAnswerFragment pad)
{
fragManager.beginTransaction()
.add(R.id.AnswerArea, pad, "AnswerArea")
.commit();
fragManager.executePendingTransactions();
}
Note that I was setting up fragments before I setContentView. Ooops.
This page seems to be a good central location for posting suggestions about the Fragment IllegalArgumentException. Here is one more thing you can try. This is what finally worked for me:
I had forgotten that I had a separate layout file for landscape orientation. After I added my FrameLayout container there, too, the fragment worked.
On a separate note, if you have already tried everything else suggested on this page (and the entire Internet, too) and have been pulling out your hair for hours, consider just dumping these annoying fragments and going back to a good old standard layout. (That's actually what I was in the process of doing when I finally discovered my problem.) You can still use the container concept. However, instead of filling it with a fragment, you can use the xml include tag to fill it with the same layout that you would have used in your fragment. You could do something like this in your main layout:
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="#layout/former_fragment_layout" />
</FrameLayout>
where former_fragment_layout is the name of the xml layout file that you were trying to use in your fragment. See Re-using Layouts with include for more info.
I fixed this bug, I use the commitNow() replace commit().
mFragment.getChildFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment_container,fragment)
.commitNowAllowingStateLoss();
The commitNow is a sync method, the commit() method is an async method.
I use View Binding in my project and was inattentive to add setContentView() after inflating ActivityHelloWorldBinding class:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHelloWorldBinding.inflate(layoutInflater)
// Add this line.
setContentView(binding.root)
}
In my case I had a SupportMapFragment in a recycler view item (I was using the lower overhead "liteMode" which makes the map appear as non-interactive, almost like a static image). I was using the correct FragmentManager, and everything appeared to work fine... with a small list. Once the list of items exceeded the screen height by a bit then I started getting this issue when scrolling.
Turned out, it was because I was injecting a dynamic SupportMapFragment inside a view, which was inside another fragment, to get around some issues I was having when trying to declare it statically in my XML. Because of this, the fragment placeholder layout could only be replaced with the actual fragment once the view was attached to the window, i.e. visible on screen. So I had put my code for initialising the SupportMapFragment, doing the Fragment replace, and calling getMapAsync() in the onAttachedToWindow event.
What I forgot to do was ensure that my code didn't run twice. I.e. in onAttachedToWindow event, check if my dynamic SupportMapFragment was still null before trying to create a new instance of it and do a Fragment replace. When the item goes off the top of the RecyclerView, it is detached from the window, then reattached when you scroll back to it, so this event is fired multiple times.
Once I added the null check, it happened only once per RecyclerView item and issue went away! TL;DR!
This issue also happens when you don't put <include layout="#layout/your_fragment_layout"/> in your app_bar_main.xml
use childFragmentManager instead of activity!!.supportFragmentManager
I encountered this problem when I tried to replace view with my fragment in onCreateView(). Like this:
public class MyProjectListFrag extends Fragment {
private MyProjectListFragment myProjectListFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FragmentManager mFragmentManager = getFragmentManager();
myProjectListFragment = new MyProjectListFragment();
mFragmentManager
.beginTransaction()
.replace(R.id.container_for_my_pro_list,
myProjectListFragment, "myProjectListFragment")
.commit();
}
It told me
11-25 14:06:04.848: E/AndroidRuntime(26040): java.lang.IllegalArgumentException: No view found for id 0x7f05003f (com.example.myays:id/container_for_my_pro_list) for fragment MyProjectListFragment{41692f40 #2 id=0x7f05003f myProjectListFragment}
Then I fixed this issue with putting replace into onActivityCreated(). Like this:
public class MyProjectListFrag extends Fragment {
private final static String TAG = "lch";
private MyProjectListFragment myProjectListFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater
.inflate(R.layout.frag_my_project_list, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
FragmentManager mFragmentManager = getFragmentManager();
myProjectListFragment = new MyProjectListFragment();
mFragmentManager
.beginTransaction()
.replace(R.id.container_for_my_pro_list,
myProjectListFragment, "myProjectListFragment")
.commit();
}
You have to return a view in onCreateView() so that you can replace it later
You can put any operation towards this view in the following function in fragment liftcycle, like onActivityCreated()
Hope this helps!
In my case this exception was thrown when I used different ids for the same layout element (fragment placeholder) while having several of them for different Build Variants. For some reason it works perfectly well when you are replacing fragment for the first time, but if you try to do it again you get this exception.
So be sure you are using the same id if you have multiple layouts for different Build Variants.
I was having this problem. In my case I have forgotten to add FrameLayout in my Xml File, after adding frame layout, my problem has been solved.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/wraper"
android:layout_above="#id/wraper"/>
If you are trying to replace a fragment within a fragment with the fragmentManager but you are not inflating the parent fragment that can cause an issue.
In BaseFragment.java OnCreateView:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.replace(R.id.container, new DifferentFragment())
.commit();
}
return super.onCreateView(inflater, container, savedInstanceState);
Replace super.onCreateView(inflater, container, savedInstanceState);
with inflating the correct layout for the fragment:
return inflater.inflate(R.layout.base_fragment, container, false);
I've had the same problem when was doing fragment transaction while activity creation.
The core problem is what Nick has already pointed out - view tree has not been inflated yet. But his solution didn't work - the same exception in onResume, onPostCreate etc.
The solution is to add callback to container fragment to signal when it's ready:
public class MyContainerFragment extends Fragment {
public static interface Callbacks {
void onMyContainerAttached();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d(TAG, "--- onAttach");
((Callbacks) activity).onMyContainerAttached();
}
//... rest of code
}
And then in activity:
public class MainActivity extends Activity
implements MyContainerFragment.Callbacks
{
#Override
public void onMyContainerAttached() {
getFragmentManager()
.beginTransaction()
.replace(R.id.containerFrame, new MyFragment())
.commit();
}
//...
}
In my case, i was using a fragment class file to declare a listview adapter class.
I just used a different file for the public adapter class and the error was gone.
It happens also when you have two views in two fragments with the same ids