Currently, I am trying to create a nested view pager using a fragment, how can I access top parent function to refresh the View?
Let's say I have:
public class ParentFragment extends Fragment {
...{
...
viewPagerAdapter = new ViewPagerParentAdapter(getChildFragmentManager(), listOfItem);
viewPager.setAdapter(viewPagerAdapter);
}
public void refreshView(){
loadData();
}
private class ViewPagerParentAdapter extends FragmentStatePagerAdapter{
private List<String> tabTitle;
private List<Item> listOfItem;
public ViewPagerParentAdapter(FragmentManager fm, #NonNull List<Item> listOfItem) {
super(fm);
this.tabTitle = new ArrayList<>();
this.listOfItem = new ArrayList<>();
if (listOfItem.size() > 0) {
this.listOfItem = listOfItem;
for (Item item : this.listOfItem) {
tabTitle.add(Item.getCLASSIFICATION());
}
}
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
return DetailFragment.newInstance(getItemAtPosition(position).getDETAILS());
}
public Item getItemAtPosition(int position) {
return listOfItem != null ? listOfItem.get(position) : null;
}
}
}
and here my object
public class Item{
//POJO
private String CLASSIFICATION;
private Details details;
}
detail fragment
public class DetailFragment extends Fragment{
...{
...
Details details = getArguments().getParcelable("details");
viewPagerAdapter = new DetailViewPagerAdapter(getChildFragmentManager(), details);
viewPagerDetails.setAdapter(viewPagerAdapter);
}
public void refreshParentView(){
((ParentFragment) getParentFragment()).refreshView(); //getting Null
}
public class DetailViewPagerAdapter extends FragmentStatePagerAdapter {
String[] tabTitle = {"Components", "Materials", "Descriptions"};
Details details;
public DetailViewPagerAdapter(FragmentManager fm, #NonNull Details details) {
super(fm);
this.details = details;
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return DetailsChildFragment.newInstance(details.getCOMPONENT());
case 1:
return DetailsChildFragment.newInstance(details.getMATERIAL());
case 2:
return DetailsChildFragment.newInstance(details.getDESC());
}
return null;
}
#Override
public int getCount() {
return tabTitle.length;
}
}
}
last child fragment
public class DetailsChildFragment extends Fragment implements View.OnClickListener{
...{
...
...
Button buttonRefresh = (Button)getView().findViewById(R.id.button_refresh);
buttonRefresh.setOnClickListener(this);
}
#Override
public void onClick(View view){
switch(view.getId()){
case R.id.button_refresh:
((DetailFragment)getParentFragment()).refreshParentView();
break;
}
}
}
Currently I am getting Null on the detail fragment refreshParentView
Any suggestions? Thanks in advance
You could use an interface as a Listener for events happening in the child
public interface Listener{
void onRefreshButtonClicked();
}
The child fragment needs to have a Listener as a field, and then you could set the Listener when getting an instance of the child fragment.
public class ChildFragment extends Fragment{
private Listener listener;
public void setListener(Listener listener)//setter
...
//now on button click you call the listener
refreshButton.setOnClickListener(new View.OnClickListener(){
#Override onClick(){
if(listener!=null){
listener.onRefreshButtonClicked();
}
}
}
public class ParentFragment extends Fragment{
...
ChildFragment child = ChildFragment.getInstance()
child.setListener(new Listener(){
#Override
void onRefreshButtonClicked(){
// implement your logic
}
}
An advantage of doing it like this is that you don't need to cast the parent from Fragment to ParentFragment which makes your code re-usable should you ever need to
When you add your DetailFragment do it with a tag, so that you can retrieve it's instance when you need it. Example:
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, detailFragment,"detailFragmentTag").commit();
Now, any time you need to access this fragment, you only need to call
DetailFragment parentFragment = (DetailFragment) getActivity().getSupportFragmentManager().findFragmentByTag("detailFragmentTag");
if(detailFragment != null && detailFragment.isAdded()){ //check if it is not null and it is added to the view so you dont end up in some NPE
detailFragment.refreshParentView()
Related
Activity
public class GroupesActivity extends BaseActivity {
SelectedBundle selectedBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_groupes);
sectionsPagerAdapter = new GroupPagerAdapter(this, getSupportFragmentManager());
viewPager.setAdapter(sectionsPagerAdapter);
tabs.setupWithViewPager(viewPager);
}
private void getAllGroup() {
// api call retrive data
// send data using interface on response
// set data selectedBundle.onBundleSelect(isVisible,calanderModelList,groupModelList,eventModelList);
}
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
public interface SelectedBundle {
void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelList, List<GroupModel> groupModelList, List<EventModel> eventModelList);
}
}
Frgment
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_all_groups_fragments, container, false);
// get data only once on oncreateview
((GroupesActivity) getActivity()).setOnBundleSelected(new GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelListtt, List<GroupModel> groupModelList, List<EventModel> eventModelList) {
Log.e("retrive data","data")
}
});
return root;
}
}
GroupPagerAdapter
public class GroupPagerAdapter extends FragmentPagerAdapter {
#StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public GroupPagerAdapter(Context context, FragmentManager fm) {
super( fm);
this.mContext=context;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new AllGroupsFragments();
case 1:
return new HostFragments();
case 2:
return new GuestFragments();
}
return null;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
#Override
public int getCount() {
return 3;
}
}
problem
i have three fragments in tabview when i swipe this obove fragment
and then come again in this fragmnet that interface not called and i'm
not getting data from activity
How to get that data again from its parent activity, i need to only
retrive that data from activity on each time of fragments oncreateView
Thanks in adavance ;)
Use setMenuVisibility() method in Fragment to fix the issue.
//In fragments
#Override
public void setMenuVisibility(final boolean isVisible) {
super.setMenuVisibility(isVisible);
if (isVisible) {
//visible to user- do ur stuff
((GroupesActivity) getActivity()).setOnBundleSelected(new
GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel>
calanderModelListtt, List<GroupModel> groupModelList, List<EventModel>
eventModelList) {
Log.e("retrive data","data")
}
});
}
}
the following link may help if you face any issues:
How to determine when Fragment becomes visible in ViewPager
I am using a viewpager to show some editext
In the picture the red rectangle is my fragment and the blue one is my activity
in my activity i implement my fragment like this
myAtivity
#Override
protected void onCreate(Bundle savedInstanceState) {
...
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
CardFragmentPagerAdapter pagerAdapter = new CardFragmentPagerAdapter(getSupportFragmentManager(), dpToPixels(2, this));
ShadowTransformer fragmentCardShadowTransformer = new ShadowTransformer(viewPager, pagerAdapter);
fragmentCardShadowTransformer.enableScaling(true);
viewPager.setAdapter(pagerAdapter);
viewPager.setPageTransformer(false, fragmentCardShadowTransformer);
viewPager.setOffscreenPageLimit(3);
...
CardFragmentPagerAdapter
public class CardFragmentPagerAdapter extends FragmentStatePagerAdapter implements CardAdapter {
private List<CardFragment> fragments;
private float baseElevation;
public CardFragmentPagerAdapter(FragmentManager fm, float baseElevation) {
super(fm);
fragments = new ArrayList<>();
this.baseElevation = baseElevation;
for(int i = 0; i< 3; i++){
addCardFragment(new CardFragment());
}
}
#Override
public float getBaseElevation() {
return baseElevation;
}
#Override
public CardView getCardViewAt(int position) {
return fragments.get(position).getCardView();
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public Fragment getItem(int position) {
return CardFragment.getInstance(position);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object fragment = super.instantiateItem(container, position);
fragments.set(position, (CardFragment) fragment);
return fragment;
}
public void addCardFragment(CardFragment fragment) {
fragments.add(fragment);
}
}
And all the edit text i am using it in CardFragment a standard fragment
my question is how to use the data of the fragment edit text in my activity
I user this tutorai to perform this viewpager https://rubensousa.github.io/2016/08/viewpagercards
You can achieve this using interface callback:
Add this new interface:
interface OnItemClickListener {
void onItemClicked(int position);
}
In your fragment(s):
private OnItemClickListener listener;
Also, add a function to set this listener:
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
Finally in your Activity:
pagerAdapter.setOnItemClickListener(this);
implement the interface on your Activity:
class MyActivity extends --- implements OnItemClickListener
override its method:
void onItemClicked(int position) {
//do what you want in your Activity
}
Final Step:
Set Activity as the listener for Fragment when you are instantiating them for your ViewPager:
//this == getActivity()
MyFragment.newInstance(this)
I'm having difficulty in setting smooth scroll for Fragments inside ViewPager, nested in another Fragment which acts as their parent.
I set up this method :
public void scrollToTop()
{
this.recyclerView.smoothScrollToPosition(0);
}
For Fragments not in a ViewPager, but I don't know how to get the reference of Fragments inside a ViewPager.
I did
BottomLobiFragment activeLobi = (BottomLobiFragment)getSupportFragmentManager().findFragmentByTag(utilities.lobbyTag);
to get the parent Fragment.
Code for a ViewPager (The rest are almost identical, difference is only at number of item, and constructor)
public class LobbyPagerAdapter extends FragmentStatePagerAdapter {
public LobbyPagerAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return Friends.newInstance("Friends, Instance 1");
// case 1: return Photo.newInstance("Photo, Instance 1");
// case 2: return Activities.newInstance("Activities, Instance 1");
default: return Friends.newInstance("Friends, Default");
}
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
#Override
public int getCount() {
//return 3;
return CONTENT.length;
}
private class setAdapterTask extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(Void result) {
}
}
}
Note : Every adapter is located inside the parent Fragment
First modify your Adapter to this
public class LobbyPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Fragment> mFragments = new ArrayList<>();
public LobbyPagerAdapter (FragmentManager fm) {
super(fm);
mFragments.add(Friends.newInstance("Friends, Instance 1"));
mFragments.add(Photo.newInstance("Photo, Instance 1"));
mFragments.add(Activities.newInstance("Activities, Instance 1"));
}
#Override
public Fragment getItem(int pos) {
return mFragments.get(pos);
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
#Override
public int getCount() {
//return 3;
return CONTENT.length;
}
private class setAdapterTask extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(Void result) {
}
}
}
Now in your fragment or activity which is holding the ViewPager & the adapter instance, you can simply do like adapter.getItem(1); example :
//Suppose your LobbyPagerAdapter instance looks like this in your code
LobbyPagerAdapter adapter = new LobbyPagerAdapter(getFragmentManager());
// And now you want to get the fragment at second position in your tab
Photo photoFragmentObject = (Photo)adapter.getItem(1);
// And now you want to get the fragment at first position in your tab
Friends friendsFragmentObject = (Friends)adapter.getItem(0);
This is the scenario:
the adapter already contains data
i need to clear the old data set and add a new one fetched from the server
The 'clear()' works removing all the items but then the adapter gets re-populated with the old fragments instead of the new ones.
Thanks in advance for helping.
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private ArrayList<MyFragment> mFragments;
...
#Override
public Fragment getItem(int pos) {
return mFragments.get(pos);
}
...
public void clear() {
mFragments.clear();
notifyDataSetChanged();
}
public void addItems(List<MyItem> items) {
for(MyItem it : items) {
mFragments.add(MyFragment.newInstance(it));
}
notifyDataSetChanged();
}
#Override
public int getItemPosition(Object object) {
MyFragment fi = (MyFragment) object;
int idx = mFragments.indexOf(fi);
if (idx >= 0) {
return POSITION_UNCHANGED;
} else {
return POSITION_NONE;
}
}
...
}
public class MyActivity extends FragmentActivity {
private ViewPager mPager;
private MyFragmentAdapter mAdapter;
...
private void resetItems(List<MyItem> items) {
mAdapter.clear();
mAdapter.addItems(items);
}
...
}
I'm having some problems when I try to replace one Fragment with another one in a ViewPager.
Current situation
I have a ViewPager with 3 pages, each one is a Fragment. In first page, I have a ListView inside a ListFragment ("FacturasFragment"). When I click on an item of that list, I use onListItemClick method for handle that event.
What I want
When list item is clicked, I want to replace ListFragment (contains a list of invoices) with another Fragment ("DetallesFacturaFragment", contains details of invoice).
When I'm in "DetallesFacturaFragment" and press Back Button, should return to ListFragment.
Scrolling between pages should not change Fragment displayed in first one. It is, if I'm in first page with "DetallesFacturaFragment" and scroll to second page, when return to first one should continue displaying "DetallesFacturaFragment".
Code
FragmentActivity
public class TabsFacturasActivity extends SherlockFragmentActivity {
private MyAdapter mAdapter;
private ViewPager mPager;
private PageIndicator mIndicator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
private static class MyAdapter extends FragmentPagerAdapter {
private String[] titles = { "VER FACTURAS", "VER CONSUMO", "INTRODUCIR LECTURA" };
private final FragmentManager mFragmentManager;
private Fragment mFragmentAtPos0;
private Context context;
public MyAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
mFragmentManager = fragmentManager;
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0
return new FacturasFragment();
case 1: // Fragment # 1
return new ConsumoFragment();
case 2:// Fragment # 2
return new LecturaFragment();
}
return null;
}
#Override
public int getCount() {
return titles.length;
}
#Override
public int getItemPosition(Object object)
{
if (object instanceof FacturasFragment && mFragmentAtPos0 instanceof DetallesFacturaFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
}
}
ListFragment
public class FacturasFragment extends ListFragment {
private ListView lista;
private ArrayList<TuplaFacturaWS> facturas;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.activity_facturas, container, false);
facturas = myApplication.getFacturas();
lista = (ListView) view.findViewById(id.list);
MyAdapter myAdaptador = new MyAdapter(this, facturas);
setListAdapter(myAdaptador);
return view;
}
public void onListItemClick (ListView l, View v, int position, long id) {
myApplication.setFacturaActual(position);
mostrarDatosFactura();
}
private void mostrarDatosFactura() {
final DetallesFacturaFragment fragment = new DetallesFacturaFragment();
FragmentTransaction transaction = null;
transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pager, fragment); //id of ViewPager
transaction.addToBackStack(null);
transaction.commit();
}
private class MyAdapter extends BaseAdapter {
private final FacturasFragment actividad;
private final ArrayList<TuplaFacturaWS> facturas;
public MyAdapter(FacturasFragment facturasActivity, ArrayList<TuplaFacturaWS> facturas) {
super();
this.actividad = facturasActivity;
this.facturas = facturas;
}
#Override
public View getView(int position, View convertView,
ViewGroup parent) {
LayoutInflater inflater = actividad.getLayoutInflater(null);
View view = inflater.inflate(R.layout.list_row, null, true);
//Set data to view
return view;
}
#Override
public int getCount() {
return facturas.size();
}
#Override
public Object getItem(int pos) {
return facturas.get(pos);
}
#Override
public long getItemId(int position) {
return position;
}
private OnClickListener checkListener = new OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
};
}
}
Fragment
public class DetallesFacturaFragment extends SherlockFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.activity_factura, container, false);
//Set data to view
return view;
}
}
At the moment, when I click on list item, white view appears in first page. I've verified and onCreateView method of "DetallesFacturaFragment" is executed, but nothing appears on that page.
And first time I click on list item, it shows that white screen. But after coming back to list, I have to click twice to a list item for showing white screen.
I've been googling and looking at some many questions but couldn't find anyone solved with completed code.
After so many hours spent, I've found correct solution modifying code in that answer.
It replaces Fragment in first page of ViewPager with another one, and if you return back from second Fragment, first Fragment is correctly displayed. Doesn't matter Fragment displayed in first page, if you swipe from one page to another, it doesn't change its Fragment.
Here is my code:
FragmentActivity
public class TabsFacturasActivity extends SherlockFragmentActivity {
public void onBackPressed() {
if(mPager.getCurrentItem() == 0) {
if (mAdapter.getItem(0) instanceof DetallesFacturaFragment) {
((DetallesFacturaFragment) mAdapter.getItem(0)).backPressed();
}
else if (mAdapter.getItem(0) instanceof FacturasFragment) {
finish();
}
}
}
private static class MyAdapter extends FragmentPagerAdapter {
private final class FirstPageListener implements
FirstPageFragmentListener {
public void onSwitchToNextFragment() {
mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
.commit();
if (mFragmentAtPos0 instanceof FacturasFragment){
mFragmentAtPos0 = new DetallesFacturaFragment(listener);
}else{ // Instance of NextFragment
mFragmentAtPos0 = new FacturasFragment(listener);
}
notifyDataSetChanged();
}
}
private String[] titles = { "VER FACTURAS", "VER CONSUMO", "INTRODUCIR LECTURA" };
private final FragmentManager mFragmentManager;
public Fragment mFragmentAtPos0;
private Context context;
FirstPageListener listener = new FirstPageListener();
public MyAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
mFragmentManager = fragmentManager;
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0
if (mFragmentAtPos0 == null)
{
mFragmentAtPos0 = new FacturasFragment(listener);
}
return mFragmentAtPos0;
case 1: // Fragment # 1
return new ConsumoFragment();
case 2:// Fragment # 2
return new LecturaFragment();
}
return null;
}
#Override
public int getCount() {
return titles.length;
}
#Override
public int getItemPosition(Object object)
{
if (object instanceof FacturasFragment &&
mFragmentAtPos0 instanceof DetallesFacturaFragment) {
return POSITION_NONE;
}
if (object instanceof DetallesFacturaFragment &&
mFragmentAtPos0 instanceof FacturasFragment) {
return POSITION_NONE;
}
return POSITION_UNCHANGED;
}
}
}
FirstPageFragmentListener
public interface FirstPageFragmentListener {
void onSwitchToNextFragment();
}
FacturasFragment (FirstFragment)
public class FacturasFragment extends ListFragment implements FirstPageFragmentListener {
static FirstPageFragmentListener firstPageListener;
public FacturasFragment() {
}
public FacturasFragment(FirstPageFragmentListener listener) {
firstPageListener = listener;
}
public void onListItemClick (ListView l, View v, int position, long id) {
firstPageListener.onSwitchToNextFragment();
}
}
DetallesFacturaFragment (SecondFragment)
public class DetallesFacturaFragment extends SherlockFragment {
static FirstPageFragmentListener firstPageListener;
public DetallesFacturaFragment() {
}
public DetallesFacturaFragment(FirstPageFragmentListener listener) {
firstPageListener = listener;
}
public void backPressed() {
firstPageListener.onSwitchToNextFragment();
}
}
To solve minor issue that Android suggest not using non-default constructor for fragment. You should change the constructor to something like this:
in FacturasFragment :
public static FacturasFragment createInstance(FirstPageFragmentListener listener) {
FacturasFragment facturasFragment = new FacturasFragment();
facturasFragment.firstPageListener = listener;
return facturasFragment;
}
Then you can call it from getItem function like this :
mFragmentAtPos0 = FacturasFragment.createInstance(listener);
in DetallesFacturaFragment :
public static DetallesFacturaFragment createInstance(FirstPageFragmentListener listener) {
DetallesFacturaFragment detallesFacturaFragment= new DetallesFacturaFragment();
detallesFacturaFragment.firstPageListener = listener;
return detallesFacturaFragment;
}
Then you can call it from FirstPageListener.onSwitchToNextFragment() function like this :
mFragmentAtPos0 = DetallesFacturaFragment.createInstance(listener);
I found two ways to replace fragment in viewpager.
Way 1: By updating ViewPagerAdapter
Way 2: By using a root fragment
Way1:
In this way, we need to update the fragment from viewpager adapter's fragment list and notify the fragment about the change.
For example:
private void changefragment(int position) {
Fragment newFragment = CategoryPostFragment.newInstance();
adapter.fragments.set(position, newFragment);
adapter.notifyDataSetChanged();
viewPager.setCurrentItem(position);
}
Here is the viewpager adapter code for this
import java.util.List;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.PagerAdapter;
import com.trickbd.trickbdapp.ui.activity.homeactivity.fragments.FavFragment;
import com.trickbd.trickbdapp.ui.activity.homeactivity.fragments.HomePostFragment;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
public List<Fragment> fragments;
public ViewPagerAdapter(FragmentManager manager, List<Fragment> fragments) {
super(manager);
this.fragments = fragments;
}
#NonNull
#Override
public Fragment getItem(int position) {
if (fragments.get(position)!=null){
return fragments.get(position);
}else {
if (position==0){
return new HomePostFragment();
}else {
return new FavFragment();
}
}
}
#Override
public int getCount() {
return fragments.size();
}
//method to add fragment
public void addFragment(Fragment fragment) {
fragments.add(fragment);
}
#Override
public int getItemPosition(#NonNull Object object) {
if (object instanceof FavFragment) {
return POSITION_UNCHANGED; // don't force a reload
} else {
// POSITION_NONE means something like: this fragment is no longer valid
// triggering the ViewPager to re-build the instance of this fragment.
return POSITION_NONE;
}
}
}
I was doing fine with this code. I become concerned when the super(manager) method of FragmentStatePagerAdapter deprecated in api 28.
When I use "super(manager,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);" along with first way of replacing fragment the application crash on runtime.
Also, there is a back draw that when we called adapter.notifydatasetchanged() from the viewpager adapter it's not efficient. It's recreating the whole viewpager while we are trying to change only a specific fragment.
So, way no 2 come with the solution of all problems.
Way 2:
Without adding the actual fragment to the viewpager we should add a root fragment to the viewpager. In root fragment there will be actual fragment added(previously we added in the viewpager. Then we can replace any fragment easily without the help of FragmentStatePagerAdapter.
Code of the root fragment:
Rootfragment.java
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentTransaction;
import com.trickbd.trickbdapp.R;
import dagger.android.support.DaggerFragment;
public class RootFragment extends DaggerFragment {
public RootFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.root_layout, container, false);
if (getFragmentManager() != null) {
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.root_frame, new HomePostFragment());
transaction.commit();
}
return view;
}
}
root_layout.xml
<?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"
android:id="#+id/root_frame">
</FrameLayout>
So previous replacing code will be updated like below
private void changefragment(int position) {
Fragment newFragment = CategoryPostFragment.newInstance();
replacefragment(newFragment);
viewPager.setCurrentItem(position);
}
public void replacefragment(Fragment fragment){
getSupportFragmentManager();
FragmentTransaction trans = getSupportFragmentManager()
.beginTransaction();
trans.replace(R.id.root_frame, fragment);
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
By this way, we can replace the fragment more efficiently.
To get the currently added fragment in rootfragment we may use this code.
if (getSupportFragmentManager().findFragmentById(R.id.root_frame) instanceof HomePostFragment){
HomePostFragment postFragment = (HomePostFragment) getSupportFragmentManager().findFragmentById(R.id.root_frame);
}
You may learn more about this here