Problem:
I have a ContainerFragment in which there is a ViewPager. CameraFragment is being shown in this viewpager. The shutter button is in ContainerFragment and I'm using an interface to receive callback in CameraFragment when shutter button is clicked in order to click picture. When callback is received then I try to capture image and app crashes with error.
Log:
java.lang.IllegalStateException: should never call auto-cleared-value get when it might not be available
at com.example.chat.utils.services.AutoClearedValue.getValue(AutoClearedValue.kt:51)
at com.example.chat.ui.base.BaseFragment.getBinding(BaseFragment.kt:41)
at com.example.chat.ui.camera.camera.CameraFragment.captureImage(CameraFragment.kt:127)
at com.example.chat.ui.camera.camera.CameraFragment.onShutterClicked(CameraFragment.kt:135)
at com.example.chat.ui.camera.camerafragmentcontainer.CameraContainerFragment.handleShutterClick(CameraContainerFragment.kt:94)
Solved this issue. The problem was that when I was initializing the interface I was creating an instance of CameraFragment() and again in viewpager a new instance was being created. so just passed the same instance in viewpager and the problem solved.
Related
I read many threads to this topic but nothing could help me.
I can´t post my code, but i try to explain my situation:
I´m getting an IllegalStateException: can not perform this action after onSaveInstanceState
I have an activity Main (with an DrawerLayout / navigation drawer). In this activity is always 1 fragment. At first there is the fragment WelcomePage.
When the user clicks the fragment gets replaced with new fragment (I call it: FootballClubs). This fragment contains a ViewPager, so it consists of multi pages; each page is a fragment FootballClub. (So the fragment FootballClubs consists of multi pages of one FootballClub fragment). In each FootballClub fragment is a button where the user can click; on click opens a new fragment (I call it NewFragment).
At first, everything is ok and no exception is thrown. I can click the button as often as possible, each time the new fragment is shown correctly without an exception, and onBackPressed I get back to FootballClubs with the ViewPager. But when I turn my smartphone, screen orientation has changed at least one time, I get following exception when I click on the button to open the new fragment (whatever fragment I want to show):
IllegalStateException: can not perform this action after onSaveInstanceState
I replace the fragments WelcomePage/FootballClubs/NewFragment with this code:
protected void replaceSubfragment(int containerID, Fragment newFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(containerID, newFragment);
transaction.commit();
}
The exception is thrown in transaction.commit();
containerID is always the same (FrameLayout in activity layout)
Some additional information:
If I replace
transaction.commit();
with
transaction.commitAllowingStateLoss();
I get this Exception: IllegalStateException: Activity has been destroyed (although I click/do exactly the same)
All fragments gets replaced in my FragmentActivity class Main; When you click on the button, the Subclass of SectionPage gets noticed and calls a listener from FragmentActivity, so that the FragmentActivity can replace the fragments (BaseActivity gives the listener over to FootballClubs fragment, and this gives it over to the Subclass of SectionPage)
Due to the fact that I only replace fragments in my FragmentActivity I don´t use getChildFragmentManager(); (As far as I can remember this didn´t work too)
I know that the activity gets destroyed and recreated by the system when orientation changed, but I can´t do something with this information.. the whole app works perfectly except this button
If I want to show a dialog instead of NewFragment on button click I get an IllegalStateException too
In my FragmentActivity, I have a variable activeModule; here I can check activeModule.isAdded(); When the exception is thrown, isAdded() return false.. So I can check if the error will be thrown or not
I hope I could describe my problem. The screen orientation ruins everything, don´t know why..
If you need further information ask me.. if you need some code pieces maybe I can post something.
Thanks!
When viewpager displays one fragment, it will automatically load the fragment pages around it for performance reasons.
In my fragments, i have recycleviews with a popup menu to delete one item in the list.
I am facing a problem of deleting one item from one fragment, but that item still exists in the other preloaded fragments after I scroll to them.
It works only if I force the viewpager to reload the contents of its fragments by manually scrolling back and forth the fragments.
Is there a way to force reload the preloaded fragments by viewpager?
Your problem can be solved by using Interface. Google suggest using callbacks\listeners that are managed by your main Activity for communicating between fragments.You can use Interface which tells the other fragment to refresh its listview when you delete an item in current fragment.
For an overview http://developer.android.com/training/basics/fragments/communicating.html
Also a good question about this How to pass data between fragments
First create an interface to detect changes in your RecyclerView:
public interface MyRecyclerViewChangeListener(){
void onRecyclerViewDataChanged(int id);
}
Create a static variable in your Fragment or Activity which contains your viewpager:
public static List<MyRecyclerViewChangeListener> mListeners = new ArrayList();
Implement your interface to your ViewPagerFragments and do what you want in method you implemented.
In your fragment's onResume register your listener to mListeners like blow to detect changes:
MyFragmentOrActivity.mListeners.add(this);
And in your fragment's onPause unregister your listener:
MyFragmentOrActivity.mListeners.remove(this);
Finally notify your listeners when your recyclerview data changed:
for(MyRecyclerViewChangeListener listener : mListeners){
listener.onRecyclerViewDataChanged(id);
}
Edit : If you are changing your recyclerview's data after an async task result such as a web api call, you can register your listener in fragment's onCreateView method and un register in onDestroyView method. So you can catch changes in your fragments.
I am not sure if i'm getting your question right but i think this should do it.
YourViewpager.setOffscreenPageLimit(0);
Now the fragment should be destroyed if it is not active and will be recreated if you open it again.So the data change should be recognized.
Hope I could help
Try setting mViewPager.setOffscreenPageLimit(1) such that it will not pre-cache any fragment or you could use FragmentStatePagerAdapter inside viewPager to achieve what you want.
Edit 1:
So Conclusion is :
1) Use local broadcast mechanism to update the fragments present in ViewPager adapter
2) Use handler mechanism to refresh these fragments
3) if you want to blindly update these fragments once they are visible to users then do it inside onPageChangeListener of view pager method.
The answers helped me find the solution.
For future reference, I used a callback every time I used deleteItem(), and took a list of the loaded frags by using the method [FragmentHostingViewPager].getChildFragmentManager().getFragments()
Then I iterated through each fragment as long as each fragment was not null, and called a refresh() method on them.
I have two fragments in app. When user launch the app, in main layout fragment container shows first fragment, when user click on the button, second fragment replaces first fragment.
I want to do this: when app launch, in second fragment loading some text from the GET url request. And when user click on button to show seecond fragment, all text has already been loaded.
How can I do this ?
Maybe, make function "loadContent" in second fragment and when app launches call this function..
Is anybody have any ideas/info about this, please provide me^)
Make the GET call in Activity's onCreate method. Define your own interface which has an abstract getter. Implement the interface on Activity, and override the getter to return GET response.
In fragment onAttach(Activity) initialize interface like :
Interface callback = new Interface(activity);
now get the data, anywhere in fragment lifecycle after onAttach, from callback object like :
callback.getterFunction();
I'm trying to create a ViewPager with six fragments but only 2nd fragment to 5th fragment contain data that I want to show and the first fragment and the last fragment I want to be used to reload the data and set the position to the 2nd fragment again. The overall flow is like this :
1st (reload and go back to 2nd) <- 2nd fragment <-> 5th fragment -> 6th fragment (same with 1st)
what I've tried is I create a callback from the 1st fragment and 6th fragment like this
public static class callbackFragmentLoading implements callbackFragmentLoad {
#Override
public void onLoading() {
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(2,false);
}
}
and I passed the callback to the fragment constructor so I can called the onLoading function in the onActivityCreated. But I everytime I do it the application will be force closed and the logcat shows
recursive entry to executependingtransactions
is there any way to do this? or my method for doing it is wrong?
Thank You
is there any way to do this? or my method for doing it is wrong?
Messing with callbacks between Fragments of a ViewPager isn't probably such a good idea. Instead I would do it like this:
Don't load any data(like with a Loader) in the Fragments from the ViewPager, instead let the FragmentActivity do it(and the Fragments will get it through methods from the Activity).
Your two loading fragments(position 0 and 5) will call in their onResume method a reload action on the parent Activity(like a Loader restart)
At this moment the Activity will load/reload the data and when that finishes it will set the ViewPager to the correct items(either 1 or 4)
in the onResume method of the data fragments you'll refresh the fragment's data(here you may need to use some sort of signaling system because you'll need to duplicate the refresh code in the onCreateView(some fragments may have their view destroyed if they are far apart from the current visible position)).
As I don't know many things about the inner data fragment I've written a basic skeleton sample(without the data loading in the activity).
I have 4 tabs in an Activity.
Each of them is a Fragment. And every Fragment has a ListView.
So, if i change the ListView in Fragment, it must change the ListView in all other Fragments ie.., Tabs.
The problem i face is while creating the interface instance.
It takes it's own onClick() method.
In case i want a callback to the parent activity i could have done that by overriding onAttach. But how to make a callback to a Fragment?
From Developers site:
Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
So, make a callback to the Activity which in turn makes a callback to other fragments??
Thank You
It's pretty simple,all You need is steps below:
1) From onClick method in your first fragment make a function call of activity:
((IYourActivityInterface) getActivty()).activityMethod();
2) In your activity find fragment by tag or id and run it's method:
public void activityMethod(){
Fragment tabFragment = getFragmentManager().findFragmentByTag("second_fragment");
// or Fragment tabFragment = getFragmentManager().findFragmentById(R.id.frag);
if (tabFragment!=null){
((IFragmentInterface) tabFragment).fragmentMethod();
}
}
Hope this is what you are looking for.)