I use the example of a pager enter link description here
I have everything worked out but there is one problem. I have 4 different fragments. One of them contains ListView. When I click on an item in the ListView, change the global variable guestId. If then return to other fragments, these they should be changed. Because they use this variable as a parameter. But they do not change.
public class Guest extends Fragment {
...
private ViewPager pager;
private MyPagerAdapter adapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.guest, null);
...
if (InternetResiver.isOnline(getActivity())) {
setData();
} else {
AlertDialog alert = InternetResiver.getAlertDialog(getActivity());
alert.show();
}
return v;
}
public void startNewTread(String newId) {
guestId = newId;
Log.d("usernewid",newId);
setData();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return Folio.newInstance(guestId,hotel,room);
case 1: return BalanceDetail.newInstance(guestId,hotel);
case 2: return History.newInstance(guestId,hotel);
case 3: return Record.newInstance(guestId,hotel,room);
default: return Folio.newInstance(guestId,hotel,room);
}
}
#Override
public int getCount() {
return 4;
}
}
public void setData() {
String link = String.format(......., guestId, hotel);
new MyAsincTask(getActivity()){........}.execute(link);
}
}
my fragment
public class Folio extends Fragment {
private ArrayList<FolioBean> folioBeans;
private TableLayout tableFolio;
private String guestId;
private String hotel;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.folio, null);
guestId = getArguments().getString("guestid");
hotel = getArguments().getString("hotel");
folioBeans = new ArrayList<>();
tableFolio = (TableLayout) v.findViewById(R.id.tableFolio);
if (InternetResiver.isOnline(getActivity())) {
setData();
} else {
AlertDialog alert = InternetResiver.getAlertDialog(getActivity());
alert.show();
}
return v;
}
public static Folio newInstance(String guestid,String hotel,String room) {
Folio f = new Folio();
Bundle b = new Bundle();
b.putString("guestid", guestid);
b.putString("hotel", hotel);
b.putString("room", room);
f.setArguments(b);
return f;
}
public void setData() {
String link = String.format(........., guestId, hotel);
new MyAsincTask(getActivity()){........}.execute(link);
}
}
other fragments are loaded using the same guestId
It is because ViewPager cached fragments. You need use FragmentStatePagerAdapter instead FragmentPagerAdapter, and call notifydatasetchanged() after changing guestId, and override
Override getItemPosition in your PagerAdapter like this:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
see similar questions
Refresh images on FragmentStatePagerAdapter on resuming activity
Related
I am trying to refresh the current fragment in the tabbed layout of my viewpager. I have one fragment (UserProgressFragment) that creates the ViewPager and sets the adapter (UserProgressAdapter) along with creating tabbed layout.
In my UserProgressAdapter, in the getItem() method I am returning two other fragments, (UserWeightTrackerFragment and UserCalorieCounterFragment) based on which tab i am on.
My issue is how do i refresh the fragment and update its content/view from the UserCalorieCounterFragment on a button click, because access to the viewpager and adapter are set in the UserProgressFragment? I have considered notifyDataChange for the adapter but i dont know how to call this from this class as it is set up on the UserProgressFragment class. The purpose of wanting to refresh this page is to update a specific view which is a chart, if context is needed.
I have attached the code below:
UserProgressFragment
public class UserProgressFragment extends Fragment{
public static UserProgressFragment newInstance() {
return new UserProgressFragment();
}
public UserProgressFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_user_progress, container, false);
ViewPager viewPager = view.findViewById(R.id.progress_viewpager);
viewPager.setAdapter(new UserProgressTabsAdapter(getChildFragmentManager()));
TabLayout tabLayout = view.findViewById(R.id.progress_sliding_tabs);
tabLayout.setupWithViewPager(viewPager, true);
return view;
}
}
UserProgressTabsAdapter
public class UserProgressTabsAdapter extends FragmentStatePagerAdapter {
private static final int PAGE_COUNT = 2;
private String tabTitles[] = new String[]{"Weight Tracker", "Calorie Counter"};
public UserProgressTabsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return UserWeightTrackerFragment.newInstance(position);
case 1:
return UserCalorieCounterFragment.newInstance(position + 1);
}
return null;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
UserCalorieCounterFragment (need to refresh this one)
public class UserCalorieCounterFragment extends Fragment implements View.OnClickListener, AdapterView.OnItemSelectedListener {
public static final String ARG_PAGE = "ARG_PAGE";
public static UserCalorieCounterFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
UserCalorieCounterFragment fragment = new UserCalorieCounterFragment();
fragment.setArguments(args);
return fragment;
}
public UserCalorieCounterFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int mPage = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_user_calorie_counter, container, false);
Button mAddCalories = view.findViewById(R.id.btn_add_calorie);
mAddCalories.setOnClickListener(this);
return view;
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_add_calorie:
//REFRESH/UPDATE HERE
break;
}
}
You can create a public method in your fragment which contains the view pager which will contain the notifyDataSetChanged() function. And in the view pager fragment/item, you can call getParentFragment() and type cast it to your parent/first fragment and access that public method to notifyDataSetChanged().
There is an activity in which there is a fragment, let's call it FirstFragment. There is a framelayout in this fragment containing another fragment, SecondFragment. By clicking on SecondFragment, ThirdFragment is fired. Here, I need to be able to go back to the SecondFragment when pressing back button. However, by clicking on back button, the activity is closed. Here's my code :
MainActivity.java
public class MainActivity extends AppCompatActivity{
ViewPager viewPager;
String[] titles;
SecondFragment secondFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentPagerAdapter fragment = new FragmentPagerAdapter(getSupportFragmentManager());
viewPager = findViewById(R.id.viewPager);
viewPager.setAdapter(fragment);
firstFragment = new FirstFragment();
}
public class FragmentPagerAdapter extends android.support.v4.app.FragmentPagerAdapter {
public FragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0 : return FirstFragment.newInstance("hi");
default: return new OtherFragment();
}
}
#Override
public int getCount() {
return 3;
}
}
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
FirstFragment.java
public class FirstFragment extends Fragment implements RecyclerViewListener {
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Fragment secondFragment =SecondFragment.newInstance("hi");
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.frameLayout, secondFragment).commit();
return inflater.inflate(R.layout.fragment_first, container, false);
}
public static FirstFragment newInstance(String text) {
FirstFragment f = new FirstFragment();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
#Override
public void clicked(int position) {
Fragment productDetailFragment = ThirdFragment.newInstance(position);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.frameLayout, productDetailFragment).addToBackStack(null).commit();
Toast.makeText(getContext(), "pos : " + position, Toast.LENGTH_SHORT).show();
}
#Override
public boolean longClicked(int position) {
return false;
}
}
SecondFragment.java
public class SecondFragment extends Fragment {
RecyclerView recyclerView;
static ArrayList<Item> items;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_second, container, false);
recyclerView = v.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
items = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Item item = new Item(R.drawable.accept_state, "esm" + i, Integer.toString(i * 100));
items.add(item);
}
recyclerView.setAdapter(new RecylcerViewAdapter(getContext(), (RecyclerViewListener) getParentFragment(), items));
return v;
}
public static SecondFragment newInstance(String text) {
SecondFragment f = new SecondFragment();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
}
ThirdFragment.java
public class ThirdFragment extends android.support.v4.app.Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_third, container, false);
return v;
}
public static ThirdFragment newInstance(int position) {
ThirdFragment f = new ThirdFragment();
Bundle b = new Bundle();
f.setArguments(b);
return f;
}
}
RecyclerViewListener.java
public interface RecyclerViewListener {
void clicked(int position);
boolean longClicked(int position);
}
RecyclerViewAdapter.java
public class RecylcerViewAdapter extends RecyclerView.Adapter<RecylcerViewAdapter.RecyclerViewHolder>{
private Context context;
private RecyclerViewListener recyclerViewListener;
private ArrayList<Item> items;
public RecylcerViewAdapter(Context context, RecyclerViewListener recyclerViewListener, ArrayList<Item> items) {
this.context = context;
this.recyclerViewListener = recyclerViewListener;
this.items = items;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
RecyclerViewHolder recyclerViewHolder = new RecyclerViewHolder(view);
return recyclerViewHolder;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.bind(position);
}
#Override
public int getItemCount() {
return items.size();
}
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView name;
TextView cost;
public RecyclerViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
recyclerViewListener.clicked(getAdapterPosition());
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
return recyclerViewListener.longClicked(getAdapterPosition());
}
});
imageView = itemView.findViewById(R.id.image);
name = itemView.findViewById(R.id.name);
cost = itemView.findViewById(R.id.cost);
}
public void bind(int position) {
Item item = items.get(position);
imageView.setImageResource(item.getImageID());
name.setText(item.getName());
cost.setText(item.getCost());
}
}
}
First of all, override onBackPressed() and then use use getChildFragmentManager() as shown below:
public void onBackPressed() {
// If the fragment exists and has some back-stack entry
if (myFragment != null && mytFragment.getChildFragmentManager().getBackStackEntryCount() > 0){
// Get the fragment fragment manager - and pop the backstack
myFragment.getChildFragmentManager().popBackStack();
}
// Else, nothing in the direct fragment back stack
else{
// Let super handle the back press
super.onBackPressed();
}
}
I have a Viewpager contains Recylerview which has 2 different holders. One of them is also view pager. Hence I have nested viewpager nad nested fragments. When I tap the second tab and tap back the first tab it is fine .But when I tap the third tab and tap back the first tab. It gives following error:
java.lang.IllegalArgumentException: No view found for id 0x7f0f00ce (:id/viewPagerComments) for fragment CommentFragment
MainAcitivty
viewPager.setAdapter(new MainViewPagerAdapter(getSupportFragmentManager(),models.size()));
navigationTabBar.setModels(models);
navigationTabBar.setViewPager(viewPager, 0);
MainViewPagerAdapter
private int size;
public MainViewPagerAdapter(FragmentManager fm, int size) {
super(fm);
this.size = size;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return DashboardtFragment.newInstance(size, position);
default:
return TempFragment.newInstance(size, position);
}
}
DashboardtFragment
public static DashboardtFragment newInstance(int size, int index) {
Bundle args = new Bundle();
args.putInt(ARG_I,index);
args.putInt(ARG_S,size);
DashboardtFragment fragment = new DashboardtFragment();
fragment.setArguments(args);
return fragment;
}
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
final View v = inflater.inflate(R.layout.dashboard_fragment, null);
return v;
}
#Override
public void showRecyleview(DashboardResponseModel model) {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
DashboardRecyleViewAdapter adapter = new DashboardRecyleViewAdapter(getActivity(),getChildFragmentManager(),model);
recyclerView.setAdapter(adapter);
}
DashboardRecyleViewAdapter
public static class ViewHolder1 extends RecyclerView.ViewHolder {
public ViewHolder1(View itemView) {
super(itemView);
viewPager = itemView.findViewById(R.id.viewPagerComments);
}
}
case 1 :
return new ViewHolder1( layoutInflater.inflate(R.layout.dashboard_comments, parent,
false));
case 1:
ViewHolder1 viewHolder1 = (ViewHolder1) holder;
viewPager.setAdapter(new CommentViewPagerAdapter(
childFragmentManager,
model.getCommentList().size(),
model.getCommentList()
));
break;
CommentViewPagerAdapter
public CommentViewPagerAdapter(FragmentManager fm, int size,
List<CommentList> list) {
super(fm);
this.size = size;
this.list=list;
}
#Override
public Fragment getItem(int position) {
return CommentFragment.newInstance(size,position,list.get(position));
}
CommentFragment
public static CommentFragment newInstance(int size, int index, CommentList
comment) {
Bundle args = new Bundle();
args.putString(ARG_C,new Gson().toJson(comment));
args.putInt(ARG_I,index);
args.putInt(ARG_S,size);
CommentFragment fragment = new CommentFragment();
fragment.setArguments(args);
return fragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState)
{
final View v = inflater.inflate(R.layout.comment_content, null);
}
PagerAdapter mPagerAdapter;
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
super.setAdapter(null);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mPagerAdapter != null) {
super.setAdapter(mPagerAdapter);
}
}
#Override
public void setAdapter(PagerAdapter adapter) {
}
public void storeAdapter(PagerAdapter pagerAdapter) {
mPagerAdapter = pagerAdapter;
}
first create a customviewpager than add the above code. Use storeAdapter instead of setAdapter.
I have a project that needs to have two viewpager, each in a different fragment of the activity.
The architecture something like this
The problem is that when a pager view is inflated, the other isn't.
For example, the fragments 1, 2 and 3 can be accessed by clicking. When I click on the first fragment, it inflates the view pager with its two fragments perfectly, but if I click on the fragment 3, the view pager does not inflate the fragments and also the tabs get slower.
Opening the application process again, by clicking on the fragment 3 first, it works perfectly, but clicking on the first after, this problem happens again.
Already debugged the processes and there is nothing different.
My Activity
public class HomeActivity extends AppCompatActivity implements NavigationFragment.OnNavigationListener{
public NavigationFragment mNavigation;
private String mTagFragmentShowing = "";
private int currentNavigation = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ButterKnife.bind(this);
mNavigation = (NavigationFragment) getFragmentManager().findFragmentById(R.id.manager_navigation);
onNavigationSelected(currentNavigation);
}
#Override
public void onNavigationSelected(int position) {
if (mTagFragmentShowing.equals(String.valueOf(position)))
return;
currentNavigation = position;
mNavigation.setNavigationSelected(position);
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(mTagFragmentShowing);
// Hide last fragment
if (fragment != null && fragment.isVisible()) {
fragmentManager.beginTransaction().hide(fragment).commit();
}
// Show new fragment
mTagFragmentShowing = String.valueOf(position);
fragment = fragmentManager.findFragmentByTag(mTagFragmentShowing);
if (fragment != null && fragment.isHidden()) {
fragmentManager.beginTransaction().show(fragment).commit();
} else if (fragment == null) {
fragmentManager.beginTransaction().add(R.id.manager_content, getFragmentByPosition(position), mTagFragmentShowing)
.setTransition(FragmentTransaction.TRANSIT_NONE).commit();
}
}
private Fragment getFragmentByPosition(int position) {
switch (position) {
case 0:
return new DiscoverFragment();
case 1:
return new UpcomingFragment();
case 2:
return new FeaturesFragment();
case 3:
return new VideosFragment();
case 4:
return new MySongsFragment();
}
return null;
}
My Navigation Fragment. It control the other fragments
public class NavigationFragment extends Fragment implements View.OnClickListener {
public ViewHolder mHolder;
public View mButtonSelected;
public OnNavigationListener mCallback;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.component_navigation, container, false);
ButterKnife.bind(this, view);
initView(view);
return view;
}
public void initView(View view) {
mHolder = new ViewHolder();
mHolder.discover = view.findViewById(R.id.component_navigation_discover);
mHolder.upcoming = view.findViewById(R.id.component_navigation_upcoming);
mHolder.features = view.findViewById(R.id.component_navigation_features);
mHolder.videos = view.findViewById(R.id.component_navigation_videos);
mHolder.mymusic = view.findViewById(R.id.component_navigation_mymusic);
mHolder.discover.setTag(0);
mHolder.upcoming.setTag(1);
mHolder.features.setTag(2);
mHolder.videos.setTag(3);
mHolder.mymusic.setTag(4);
mHolder.discover.setOnClickListener(this);
mHolder.upcoming.setOnClickListener(this);
mHolder.features.setOnClickListener(this);
mHolder.videos.setOnClickListener(this);
mHolder.mymusic.setOnClickListener(this);
mButtonSelected = mHolder.features;
}
public void setNavigationSelected(int position) {
setNavigationButtonSelected(false);
switch (position) {
case 0:
mButtonSelected = mHolder.discover;
break;
case 1:
mButtonSelected = mHolder.upcoming;
break;
case 2:
mButtonSelected = mHolder.features;
break;
case 3:
mButtonSelected = mHolder.videos;
break;
case 4:
mButtonSelected = mHolder.mymusic;
break;
}
setNavigationButtonSelected(true);
}
public void setNavigationButtonSelected(boolean enabled) {
mButtonSelected.setBackgroundColor(enabled ? getResources().getColor(R.color.color_red) : Color.TRANSPARENT);
}
#Override
public void onClick(View view) {
if (view != mButtonSelected) {
mCallback.onNavigationSelected((Integer) view.getTag());
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnNavigationListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnNavigationSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
static class ViewHolder {
View discover;
View upcoming;
View features;
View videos;
View mymusic;
}
public interface OnNavigationListener {
public void onNavigationSelected(int position);
}
My Fragments with View Pager
public class MySongsFragment extends Fragment {
private OnFragmentInteractionListener mListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.mysongs_fragment_container, MySongsViewPagerFragment.newInstance(0)).commit();
return inflater.inflate(R.layout.fragment_my_songs, container, false);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
My View Pager
public class MySongsViewPagerFragment extends Fragment {
private static final int NUM_PAGES = 4;
private String[] tab_names;
private List<String> mTabNames;
private PagerAdapter mPagerAdapter;
public #Bind(R.id.pager)
ViewPager mPager;
public static MySongsViewPagerFragment newInstance(int index) {
MySongsViewPagerFragment fragment = new MySongsViewPagerFragment();
Bundle args = new Bundle();
args.putInt("index", index);
fragment.setArguments(args);
return fragment;
}
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = initView(inflater, container);
return view;
}
#NonNull private View initView(LayoutInflater inflater, ViewGroup container) {
View view = inflater.inflate(R.layout.fragment_view_pager_my_songs, container, false);
ButterKnife.bind(this, view);
tab_names = getResources().getStringArray(R.array.tabs_mysongs);
mTabNames = Arrays.asList(tab_names);
mPagerAdapter = new ScreenSlidePagerAdapter(getActivity().getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mPager.onTouchEvent(event);
return false;
}
});
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mPager);
return view;
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override public Fragment getItem(int position) {
switch (position) {
case 0:
return new PlaylistsFragment();
case 1:
return new SongsFragment();
case 2:
return new AlbumsFragment();
case 3:
return new ArtistsFragment();
default:
return new PlaylistsFragment();
}
}
#Override public int getCount() {
return NUM_PAGES;
}
#Override public CharSequence getPageTitle(int position) {
return mTabNames.get(position);
}
}
The problem was activity context in viewpager
In My View Pagers. I change
mPagerAdapter = new ScreenSlidePagerAdapter(getActivity().getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
to
mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
The two viewpager used the same context. So when I inflated the first, the other was not inflated because interpreted that already existed an inflated viewpager.
Thanks for the help mcwise for show me the method getChildFragmentManager().
I created a ViewPager that uses individual Fragments. There are 3, here is an example of one of them:
public class PainFragment extends Fragment {
private TextView mTxtScale;
private Button mBtnMinus;
private Button mBtnPlus;
private int mScale;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pain, container, false);
mTxtScale = (TextView)v.findViewById(R.id.scale);
mBtnMinus = (Button)v.findViewById(R.id.minus);
mBtnPlus = (Button)v.findViewById(R.id.plus);
mScale = Integer.valueOf(mTxtScale.getText().toString());
mBtnMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mScale--;
if(mScale == -1) {
mScale = 9;
}
mTxtScale.setText(String.valueOf(mScale));
}
});
mBtnPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mScale++;
if(mScale == 10) {
mScale = 0;
}
mTxtScale.setText(String.valueOf(mScale));
}
});
return v;
}
public static PainFragment newInstance(String text) {
PainFragment f = new PainFragment();
Bundle b = new Bundle();
//b.putString("msg", text);
f.setArguments(b);
return f;
}
public int getScale() {
int scale = Integer.valueOf(mTxtScale.getText().toString());
return scale;
}
And I instantiated the ViewPager in my MainFragment:
public class MainFragment extends Fragment {
Entry mEntry = new Entry();
ViewPager mPager;
JournalPagerAdapter mAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_screen, container, false);
mPager = (ViewPager)rootView.findViewById(R.id.pager);
mPager.setOffscreenPageLimit(2); // So all 3 pages are loaded at once.
mAdapter = new JournalPagerAdapter(getActivity().getSupportFragmentManager());
mPager.setAdapter(mAdapter);
...
I have button click listeners in the ViewPager Fragments. I would like to know the best way to set up a listener so that my main fragment can detect when a button is pressed on one of the ViewPager fragments.
/** Update - Here is my adapter class **/
public class JournalPagerAdapter extends FragmentPagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public JournalPagerAdapter(FragmentManager mgr) {
super(mgr);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return PainFragment.newInstance("PainFragment");
case 1: return StressFragment.newInstance("StressFragment");
case 2: return SleepFragment.newInstance("SleepFragment");
default: return PainFragment.newInstance("PainFragment");
}
}
#Override
public int getCount() {
return 3;
}
/* Thanks to Streets of Boston (http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager)
* for the next 3 methods, should include in all PagerAdapters. Let's you get the fragment instances by position */
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
Second answer with pseudo example of using a ClickListener instead of the Callback. This should let you keep all logic out of the Activity.
Implement OnClickListener interface in MainFragment. Add a OnClickListener to your JournalPagerAdapter constructor. Presumably the Adapter is creating the PainFragments. Add OnClickListener to PainFragment newInstance and have the Adapter provide it when it creates each PainFragment.
public class PainFragment extends Fragment {
private TextView mTxtScale;
private Button mBtnMinus;
private Button mBtnPlus;
private int mScale;
protected OnClickListener mainClickListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pain, container, false);
mTxtScale = (TextView)v.findViewById(R.id.scale);
mBtnMinus = (Button)v.findViewById(R.id.minus);
mBtnPlus = (Button)v.findViewById(R.id.plus);
mScale = Integer.valueOf(mTxtScale.getText().toString());
mBtnMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mScale--;
if(mScale == -1) {
mScale = 9;
}
mTxtScale.setText(String.valueOf(mScale));
mainClickListener.onClick(view);
}
});
mBtnPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mScale++;
if(mScale == 10) {
mScale = 0;
}
mTxtScale.setText(String.valueOf(mScale));
mainClickListener.onClick(view);
}
});
return v;
}
public static PainFragment newInstance(String text, OnClickListener onClickListener) {
PainFragment f = new PainFragment();
f.mainClickListener = onClickListener;
Bundle b = new Bundle();
//b.putString("msg", text);
f.setArguments(b);
return f;
}
public int getScale() {
public class MainFragment extends Fragment implements OnClickListener {
Entry mEntry = new Entry();
ViewPager mPager;
JournalPagerAdapter mAdapter;
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_screen, container, false);
mPager = (ViewPager)rootView.findViewById(R.id.pager);
mPager.setOffscreenPageLimit(2); // So all 3 pages are loaded at once.
mAdapter = new JournalPagerAdapter(getActivity().getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
...
public class JournalPagerAdapter extends FragmentPagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
private OnClickListener mOnClickListener;
public JournalPagerAdapter(FragmentManager mgr, OnClickListener onClickListener) {
super(mgr);
mOnClickListener = onClickListener;
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return PainFragment.newInstance("PainFragment", mOnClickListener);
case 1: return StressFragment.newInstance("StressFragment", mOnClickListener);
case 2: return SleepFragment.newInstance("SleepFragment", mOnClickListener);
default: return PainFragment.newInstance("PainFragment", mOnClickListener);
}
}
...
The proper way to achieve this is probably through the use of a callback. Your fragment would utilize a normal click listener which would then use a callback to communicate back to the hosting Activity.
See the Android docs regarding communicating from a Fragment back to the Activity; then the Activity can communicate it to other Fragments.
http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.