Android backpress not restoring fragments in pager - android

I navigate from fragment A which has a pager adapter with 2 fragments to fragment B committing the transaction to backstack. On returning to fragment A the pager adapter although initialised fails to load its fragments.
This part runs after returning to fragment A.
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
POSPagerAdapter posPagerAdapter = new POSPagerAdapter(getSupportFragmentManager());
ViewPager viewPager = (ViewPager)getActivity().findViewById(R.id.pager);
viewPager.setAdapter(posPagerAdapter);
setQuantity(cart.quantity);
setCharge(cart.totalAmount);
cart.onCartChanged.subscribe(cartChangedSuscriber);
}
This is how i'm navigating to fragment B
PaymentMethodFragment f = PaymentMethodFragment.newInstance();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container,f)
.addToBackStack(null).commit();

Related

FragmentManager in RecyclerView adapter

I have an activity with a viewpager that contains 2 tabs. Each tab is a host fragment that has 2 child fragments. First fragments are recyclerviews that open up other fragments with FragmentTransactions. I am having trouble creating different backstacks for them.
So in my recyclerview adapter in onBindViewHolder i have the onclicklistener like this:
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirstFragment fragment1 = new FirstFragment();
SecondFragment fragment2 = new SecondFragment();
FragmentManager fm = ((FragmentActivity) view.getContext()).getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction
.replace(R.id.frame_container, fragment2,"Tag")
.addToBackStack(null)
.commit();
}
});
If i make the transaction like this from the recyclerview, the backstack is the same for both tabs, so if i open second fragments on tab1, then on tab2, if i go back to tab1 and press back, the second fragment on tab2 gets popped insead.
If i make a button in the FirstFragment outside of the recyclerview and make the fragment transaction from FirstFragment like this:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frame_container, SecondFragment.newInstance(), "Tag");
ft.addToBackStack(null);
ft.commit();
}
});
then it works as intended, but i want to do it from the recyclerview.
Is there any way this can be done?
You should carry your item click listener logic into the host fragment of the tab. Then in both of your host fragments you should make required transaction by using child fragment manager. Thus, the transactions are kept in the back stack of the host fragments. Then you have to manage these different stacks which are activity's fragment stack, host1's fragment stack and host2's fragment stack. For that purpose, you have to override onBackPressed in your activity then you ask the current visible host fragment for if there is a transaction. If there is you should pop that transaction and return in onBackPressed callback.If there is no let the activity to handle event by calling super.

Why is onCreateView in Fragment called twice after device rotation in Android?

I have simple activity and fragment transaction. What i noticed that on configuration changes oncreateView of Fragment is called twice. Why is this happening?
Activity Code Here :
#Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println("Activity created");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager manager = getSupportFragmentManager();
BlankFragment fragment = new BlankFragment();
addFragmentToActivity(manager,
fragment,
R.id.root_activity_create
);
}
public static void addFragmentToActivity (FragmentManager fragmentManager,
Fragment fragment,
int frameId)
{
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(frameId, fragment);
transaction.commit();
}
Fragment Code Here :
public class BlankFragment extends Fragment {
public BlankFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
}
On first load onCreateView() is called once
But onRotation onCreateView() is called twice
why ?
Because of this transaction.replace(frameId, fragment); Really? Yes,I mean because of fragment .You already have one fragment onFirst load, When you rotate onCreate() will be called once again, so now fragment manager has old fragment ,so it methods will execute(once),and next you are doing transaction replace() which will remove old fragment and replace it with new once and again(onCreateView() will be called for second time). This is repeating for every rotation.
If you use transaction.add(frameId, fragment,UNIQUE_TAG_FOR_EVERY_TRANSACTION) you would know the reason. for every rotatation, no.of onCreateView() calls will increase by 1. that means you are adding fragments while not removing old ones.
But solution is to use old fragments.
in onCreate()of activity
val fragment = fragmentmanager.findFrgmentByTag("tag")
val newFragment : BlankFragment
if(fragment==null){
newFragment = BlankFragment()
}else{
newFragment = fragment as BlankFragment()
}
//use newFragment
Hope this solves confusion
Android automatically restores the state of its views after rotation. You don't have to call addFragmentToActivity again after rotation. The fragment will automatically be restored for you!
In your case, it happens twice because:
1. Android restores the fragment, its onCreateView is called
2. You replace the restored fragment with your own fragment, the oncreateview from that fragment is called too
do this:
if (savedInstanceState == null)
{
addFragmentToActivity(manager, fragment, R.id.test);
}

Android ViewPager fragment replace

I have an activity with bottom tabs, which I use to switch fragments. One of the tabs have fragment with ViewPager setup (with 3 tabs). ViewPager has a RecyclerView and when I click on any item, the new fragment should replace fragment in which ViewPager exists.
But I receive an error No view found for id R.id.frame_layout_content for fragment IndexFragment when trying to replace fragment. How to properly replace fragment in this case?
Code flow:
Activity -> replace fragment in R.id.frame_layout_content with ViewPagerFragment -> Setup the ViewPager with fragment adapter (3 tabs) -> Click on RecyclerView item in IndexFragment to replace fragment in R.id.frame_layout_content with IndexDetailsFragment.
ViewPagerFragment:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
mViewPager = (ViewPager) view.findViewById(R.id.pager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
adapter.addFragment(new IndexFragment(), view.getResources().getString(R.string.title_index));
adapter.addFragment(new FaqFragment(), view.getResources().getString(R.string.title_faq));
adapter.addFragment(new QuotesFragment(), view.getResources().getString(R.string.title_cquotes));
mViewPager.setAdapter(adapter);
tabLayout = (TabLayout) view.findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
super.onViewCreated(view, savedInstanceState);
}
Code to change fragment from IndexFragment:
IndexDetailsFragment newFragment = new IndexDetailsFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
transaction.replace(R.id.frame_layout_content, newFragment);
transaction.addToBackStack(null);
transaction.commit();
Try to change
IndexFragment newFragment = new IndexFragment();
to
Fragment newFragment = new IndexFragment();
Hope it helps.
R.id.frame_layout_content is inside MainActivity, so IndexFragment won't be able to access it.
You should make an interface, so IndexFragment can notify MainActivity and then MainActivity should change R.id.frame_layout_content content.
When I call FragmentTransaction transaction = getFragmentManager().beginTransaction() in IndexFragment (which replaced with FragmentManager attached to ViewPager) I receive an instance attached to ViewPager not to activity, which has R.id.frame_layout_content
So the solution is to get FragmentManager instance from parent Activity:
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();

Fragment Switching in the same Activity restarts the same Fragment

I am working on an application.
Somewhere I want to load a Fragment in an Activity and when a Gridview/Listview item will be clicked on the FirstFragment, I load the SecondFragment
I have added the Fragments the way below:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.form_creation_view);
Fragment fragment = new FirstFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.form_view, fragment).commit();
}
Second Fragment:
Fragment fragment = new SecondFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.form_view, fragment).commit();
OnBackPress of MainActivity.java :
#Override
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
So, when I press the BackButton on the Mainactivity when SecondFragment is loaded, it switches to the FirstFragment, but it calls the onCreateView() method of the FirstFragment again.
The FirstFragment has a Recyclerview inside and I send an API request in the OnCreateView() method to the server in order to load the data into this Recyclerview.
Now when I come back again to this Fragment from the SecondFragment, I want the it so that the request should not be executed and the data should be populated into the RecyclerView.
How can I achieve this?
Can anyone please help me here?
in your onCreateView, you should do a check like this:
if(mList.size() == 0){
//make api call
}else{
//set recyclerView adapter
}
This way, when you come back from the SecondFragment you can repopulate the RecyclerView.
You should also consider saving this list on onSaveInstanceState

Maintaining Backstack for Fragment with ChildFragments android

I Have an Activity A which calls a Fragment F1. Now this Fragment calls another Fragment F2 using below code:
Fragment fragment = new F2Fragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack("fragment");
ft.commit();
Then Fragement F2 calls another Fragment F3 using similar code :
Fragment fragment = new F3Fragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack("fragment");
ft.commit();
Fragment F3 has 3 child Fragments (for 3 Tabs) and they are added using tabhost as below:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.main_tab, container,
false);
mTabHost = (FragmentTabHost) rootView
.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(),
R.layout.main_tab);
Bundle arg1 = new Bundle();
arg1.putInt("CF1", 1);
mTabHost.addTab(
mTabHost.newTabSpec("Tab1").setIndicator("CF1",
getResources().getDrawable(R.drawable.tab_left)),
CF1Fragment, arg1);
Bundle arg2 = new Bundle();
arg2.putInt("CF2", 2);
mTabHost.addTab(
mTabHost.newTabSpec("Tab2").setIndicator("CF2",
getResources().getDrawable(R.drawable.tab_middle)),
CF2Fragment.class, arg2);
Bundle arg3 = new Bundle();
arg3.putInt("CF3", 3);
mTabHost.addTab(
mTabHost.newTabSpec("Tab3").setIndicator("CF3",
getResources().getDrawable(R.drawable.tab_rigth)),
CF3Fragment.class, arg2);
return rootView;
}
Till this point everything is working fine with proper back navigation.
Child Fragment calls a dialogfragment as below
ConfirmDialogFragment cd = new ConfirmDialogFragment();
cd.show(fm, "Confirm Fragment");
In Dialog I have a button, pressing on which has to refresh the CF1 Fragmnet(from where its called). Its successfully refreshes the CF1 fragment with new list but issue is when I press back button. On pressing back it should go to F3 (from where CF1 was called) but it remains in CF1 with state prior to calling Dialog. Pressing Back again takes it to Fragment F3.
I tried many things but nothing seems to be working for me. I assume that when Confirm Dialog is called from CF1 it places itself on top of Backstack, so when back is pressed from CF1 it resumes to state from where Dialog Fragment got called. I understand if somehow this isn't placed on backstack while calling dialogfragment , this would be resolved but
nothing seem to be working as of now. Please advise.
use below code to remove fragments from backstack
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager .getBackStackEntryCount() > 0){
fragmentManager .popBackStack();
}

Categories

Resources