IllegalStateException in NavigationComponent - java

I use Navigation Component from Jetpack in my app. I have 2 fragments, e.g. FirstFragment and SecondFragment and I have navigation in navigation graph from the first to second. Everything works correctly this way. I want to add child fragment to FirstFragment. So in onCreateView method of FirstFragment class I added the line
getChildFragmentManager().beginTransaction().add(R.id.fragment_container, new SimpleFragment()).commit();
This way I have an inner fragment in FirstFragment. Navigation to SecondFragment from FirstFragment still works correctly, but when I press the back button in SecondFragment I get this error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.abc.def, PID: 28856
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:4937)
at android.view.ViewGroup.addView(ViewGroup.java:4768)
at android.view.ViewGroup.addView(ViewGroup.java:4708)
at android.view.ViewGroup.addView(ViewGroup.java:4681)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1353)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1642)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1736)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1800)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3096)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3050)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2688)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1369)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2633)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2377)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2333)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2230)
at androidx.fragment.app.FragmentManager$3.run(FragmentManager.java:414)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
I get this error if I either press the back button or call navController.navigateUp() or navController.popBackStack(). If I remove the line
getChildFragmentManager().beginTransaction().add(R.id.fragment_container, new SimpleFragment()).commit();
from FirstFragment I have no error, so this means that there is a problem with child fragment manager, right? What is wrong here?

If I understand this correctly without knowing what you have without looking at your layout of "fragment_container" tells me that its type of ViewGroup which can have only one child at this point if you don't provide more information to it.
What that means is fragment_container already has a child and which you need to remove before you add your SimpleFragment.
Lets assume you have your first layout of fragment something like this
<someView>
<fragment_container/> // hear you are loading your first fragment and trying load the SimpleFragment as well which is causing problem.
</someView>
what you need is
<someView>
<fragment_container/> only load First Fragment "first_fragment_layout.xml"
</someView>
And in layout of First fragment
first_fragment_layout.xml
<someView>
<viewBlasBla/>
<viewBlasBla/>
<fragment_container/> load SimpleFragment here
</someView>
as you can see, you are indeed trying to do nested fragment which is not a Good Practice. try to avoid this if possible :).
you can reach me here

The problem was in SimpleFragment. I was keeping reference to the root view of that fragment (had View mRootView field), and didn't recreate it in case it wasn't null.

Related

How to navigate between child Fragments?

I understand how to navigate between fragments using Jetpack's Navigation Component, but I haven't been able to find is how to navigate from one child fragment to another child fragment.
The following is what I've done so far:
https://pastebin.com/dNQ0Ep4S the code example is pretty big so sum it up, I'm trying to do is" A>B and Ba>Bb". Ba is a fragment inside of fragment B. I'm not sure how to set up the nav graph for something like that
The navigation works until the home fragment. The bot nav just doesn't seem to work. It always displays the pending layout. Another thing I tried was setting the nav graph of the home to the same one used for the login and adding the pending and history fragments to the nav file without any actions. But the home loads the login, the tabs work, but they're replacing the home fragment instead of being placed in the home nav host.
Update
I managed to find the problem, but I'm stuck trying to find a solution.
So B seems to be getting the navhost for A when I setup the botnavview to the navcontroller. So calling NavController navController = NavHostFragment.findNavController(this); from B returns the navhost of A. I'm at a lost here. If I do this NavController navController2 = Navigation.findNavController(currentActivity, R.id.homeNavHostFragmentContainer); (homeNavHostFragmentContainer being the navhostfor B) still returns the navhost for A. For some reason, I can't get a reference to B's navhost.
Usually we use: NavigationUI with jetpack, i recommend this, https://developer.android.com/guide/navigation with nav_graph.xml with NavigationDirections such as:
val direction = FirstFragmentDirections.actionSecondFragment()
Navigation.findNavController(requireView()).navigate(direction)
Or you can use non-jetpack way, i do not recommend, but depending on your UI you may need it:
fun displayChildFragment(frameId: Int, fragment: Fragment) {
requireActivity().supportFragmentManager?.let {
val transaction = it.beginTransaction()
//transaction.setTransition(TRANSIT_FRAGMENT_OPEN)
transaction.replace(frameId, fragment).commit()
}
}
My problem was that I misunderstood how NavHostFragment.findNavController() functions. Fragment B is not a navhost is just a regular Fragment. The navhost for B is a child of B. The argument for findNavController() has to be a NavHostFragment not a regular Fragment. So by passing, this (being B), it wasn't getting a NavFragment, just a regular Fragment. I thought the method would have extracted the navhost from whatever fragment was passed. Guess the documentation caused a bit of confusion. To get the correct navhost, I had to get the navhost from the fragment manager like so getChildFragmentManager().findFragmentById(navHostResId) (in my case, navHostResId was the id of the fragment container in B). Then everything worked beautifully.

FragmentManager tries to find the old package name of the project and gives "No view found for fragment"

In my activity page, I have a Button to call a Fragment. FragmentManager tries to call that fragment's newInstance function.
It used to work well but from some point in the project, I needed to change its name to something else because its name was testObjectBlaBla and I needed to release it to Play Store so I changed its package name. But now it gives
java.lang.IllegalArgumentException: No view found for id 0x7f0900d0
(com.myblabla.example:id/fragment_container) for fragment
MarkerSpecification_Vehi{18103143 #0 id=0x7f0900d0 BLANK_FRAGMENT}
I tried to change the package name back to the old one but still but I can't change the name every time I want to go live.
MarkerSpecification_Acco fragment =MarkerSpecification_Acco.newInstance();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_right,R.anim.exit_to_right,R.anim.enter_from_right,R.anim.exit_to_right);
transaction.addToBackStack(null);
transaction.add(R.id.fragment_container,fragment,"BLANK_FRAGMENT").commit();
Not sure if this is the true piece because exception not giving any error in my own code but in fragmentManager.java class instead. Probably bacause trying to search the old package name com.myblabla.example instead of com.project.project. But I think it is the only place where the code tries to find a fragment.
How about you change the calling of the fragment to this:
Fragment frag = new MarkerSpecification_Acco();
Also check in your XML File if your container reference has changed to your new Fragment name.

Not able to intent to next layout

i'm working on my project and i created an interface of my app.
now i want that when ever i click in image view of Automation i go to my next layout. So i tried to write this code
the layout in which i want to move after clicking Automation is this :
But when i'm running app it's saying
Application error
Unfortunately,animation(name of my project) has stopped.
Logcat:
Caused by: java.lang.NullPointerException
at com.example.animation.dashboard.onCreate(dashboard.java:25)
at android.app.Activity.performCreate(Activity.java:5122)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2277)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2365) 
at android.app.ActivityThread.access$600(ActivityThread.java:156) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:153) 
at android.app.ActivityThread.main(ActivityThread.java:5336) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600) 
at dalvik.system.NativeStart.main(Native Method) 
What's mistake i'm making here ? i'm new to android so kindly help me out here.
Your view variable is not defined and you are trying to use it as it is null. But on the another hand, I dont think you need this, just go with findViewById without this view
It looks like view_rooms is not an activity - the second argument in your intent needs to be the context of the destination.
So if you want to go to new activity change your intent like this:
startActivity(new Intent(dashboard.this, SecondActivity.class));
You are using this in the dashboard activity line number 25
imgauto = view.findViewById(R.id.autoimg)
while your variable view is empty you have not assigned it something and also you are in activity so use it directly like this
imgauto = findViewById(R.id.autoimg)
try this and i am sure it will work perfectly.

Fragment declared target fragment that does not belong to this FragmentManager

I have made an activity A which has a fragment X in it. In fragment X, EditText item has on click event which opens fragment Y. This fragment displays a list of names. I press a name in the list, fragment Y closes and sends the selected name of to fragment X EditText. Here's the code I wrote:
YFragment y = new YFragment();
y.setTargetFragment(x.class, code);
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame, y)
.addToBackStack(null)
.commit();
In fragment Y I have the code to send the data but the problem is in this block of code above. If I comment out the setTargetFragment line the code will work but no use as data will not be sent. If I run the app this error occurs:
java.lang.IllegalStateException: Fragment y{46d3d31 #3 id=0x7f090069}
declared target fragment x{e2c16 #0 id=0x7f090104
android:switcher:2131296516:0} that does not belong to this
FragmentManager!
To use setTargetFragment(), both the new Fragment and the target Fragment must be hosted within the same FragmentManager. The most common case where this would not happen is if you are using Activity.getSupportFragmentManager() or Fragment.getFragmentManager() alongside Fragment.getChildFragmentManager().
In my solution, replace
getChildFragmentManager()
with
Activity.getSupportFragmentManager() or Fragment.getFragmentManager()
that worked for me. Thank Mr.Ben P
To new users where the "getFragmentManager" only work for it but don't want use deprecated method, the method "getParentFragmentManager" work too.

Android replace fragment doesn't hide underlying fragment

I have the following problem:
My app consists of several fragments that are dynammicly added. There is one fragment with a push button and an textedit (called 'fragA').
If I click the push button I want to show an different fragment with some text (called 'fragB'). I do this with the following code (in fragA class):
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment howFragment = new HowFragment();
FragmentTransaction transaction = null;
transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.flQuestion, howFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
Now the problem is this:
When i push the button on fragA the fragment (fragB) is created and show on the screen but when I push on the location where the pushbutton was on fragA it makes an new fragment (fragB). Also if i push where the textedit on fragA was located it opens an keyboard on fragB..
It looks like FragB is just overlaying fragA without replacing it.
I also want to achieve that when i swype to the next fragment that fragB is removed and fragA is just showed normally (state when not pressed button)
Update #
When trying to add and remove this is the following logcat output:
FATAL EXCEPTION: main
java.lang.IllegalArgumentException: No view found for id 0x7f090015 (com.example.eindwerkappv1:id/flQuestion) for fragment HowFragment{419c93c8 #3 id=0x7f090015}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:903)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4441)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:823)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
at dalvik.system.NativeStart.main(Native Method)
I would guess your fragA fragment is defined in your XML layout?
According to the documentation, this is what happens when you use the <fragment> tag:
the system inserts the View returned by the fragment directly in place
of the element.
This is why you cannot remove the previous fragment, as it does not exist.
If you want to changes fragment from code, you have to add the first fragment from code too.
You need to use a container like a FrameLayout, and add the first fragment to this container in the onCreate() of your activity, using FragmentTransaction.add().
Then FragmentTransaction.replace() method should work.
So why don't you just call the .remove() on the EditText Fragment and .add() the new TextView Framgent instead on osing the .replace()
do some thing like this:
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(addCommentFragment)
.add(R.id.containerForFragments, commentFragment, "comment"+
String.valueOf(numOfComments)).commit();
this worked for me.
I found the solution now.
I still use the replace method but I had to catch the ontouch event in the new fragment:
Fragment over another fragment issue
See previous link for the answer

Categories