I have a Fragment for a ViewPager. The ViewPager is updated based on an action fired by the user. Well when the Fragment is recreated so to speak, the page of a ViewPager is not updated as should be, or even shown for that matter! When I swipe over to other pages and then back to that one, it loads?
Here is the Fragment:
public static class CardFrontFragment extends Fragment {
public CardFrontFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = null;
rootView = inflater.inflate(R.layout.activity_dashboard, container, false);
TextView textviewLocation = (TextView)rootView.findViewById(R.id.textview_location);
TextView textviewConditions = (TextView)rootView.findViewById(R.id.textview_points);
ViewPager viewPagerDashboard = (ViewPager)rootView.findViewById(R.id.viewPager_Dashboard);
if(overviewData != null) {
textviewLocation.setText(overviewData.getLocation());
textviewPoints.setText(overviewData.getPoints());
viewPagerDashboard.setAdapter(adapterSectionsPager);
adapterSectionsPager.notifyDataSetChanged();
viewPagerDashboard.destroyDrawingCache();
textviewLocation.setText(overviewData.getWeathersLocation());
textviewPoints.setText(overviewData.getWeathersConditions());
}
return rootView;
}
}
Here is the adapter:
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return DashboardSectionFragment.create
(uiContext, position, overviewData, forecastData, hourlyData, radarData);
}
#Override
public int getCount() {
// Show 4 total pages:
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section_1).toUpperCase(l);
case 1:
return getString(R.string.title_section_2).toUpperCase(l);
case 2:
return getString(R.string.title_section_3).toUpperCase(l);
case 3:
// Radar Page:
return getString(R.string.title_section_4).toUpperCase(l);
}
return null;
}
}
I heard I am extending the correct one FragmentStatePagerAdapter over FragmentPagerAdapter. Yet nothing is working. I have called many methods of the ViewPager and adapter in the Fragment when the ViewPager is recreated but it still does not load initially till it appears off screen then back on...
Thanks!
try overriding the following like this and update the viewpager and pageradapater instance
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
viewPager.invalidate();
pagerAdapter.notifyDataSetChanged();
}
or else depending upon the specific location of the Fragment you can do the following
#Override
public void onPageSelected(int arg0) {
if(int == 2)// In which specifi fragment you want to update the view
{
viewPager.invalidate();
pagerAdapter.notifyDataSetChanged();
}
}
I hope this would help you
Try to update view when fragment get visible to user as follows:
public class MyFragment extends Fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
**//Update views here**
}
}
Related
I have FragmentActivity (MainFragmentActivity) that is calling some fragments. I will say the below one is the 3rd Fragment.
BaseFragment fragSensors = SensorsPagerFragment.newInstance(
m_objAppCredentials);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (bFirst)
ft.add(R.id.flControlContainer, fragSensors, strTag);
else
ft.replace(R.id.flControlContainer, fragSensors, strTag);
And below class holds a viewpaper which calls more fragment upon swipe.
And in that one of the fragment an activity is called.
When the back button is pressed from the activity. The 1st Fragment UI appears and its mixes with UI of one of the fragment in the viewpager.
How to destroy the UI of the fragment inside the viewpaper or to avoid UI mixing?
public class SensorsPagerFragment extends BaseFragment {
ViewPager m_oVP;
public SensorsPagerFragment() {
LogUtils.LOGD("DEBUG", "SensorsPagerFragment::CTOR");
}
public static SensorsPagerFragment newInstance(AppCredentials objAppCredentials) {
SensorsPagerFragment frag = new SensorsPagerFragment();
m_objAppCredentials = objAppCredentials;
return frag;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sensors_pager, container, false);
m_oVP = (ViewPager) v.findViewById(R.id.vpSensors);
//pager.setOffscreenPageLimit(0);
// Attach the adaptor to the PAGER
m_oVP.setAdapter(buildAdapter());
return v;
}
private PagerAdapter buildAdapter() {
return (new SensorFragmentPA(getChildFragmentManager()));
}
#Override
public void onStop() {
super.onStop();
CustomToast.Warning(getActivity().getApplicationContext(),
"SensorsPagerFragment::onStop()", 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// class SensorFragmentPA
class SensorFragmentPA extends FragmentPagerAdapter {
public SensorFragmentPA(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return Constants.cTOTAL_PAGES;
}
#Override
public Fragment getItem(int nPageNum) {
SensorsFragment f = SensorsFragment.newInstance(m_objAppCredentials, nPageNum);
return f;
}
#Override
public String getPageTitle(int nPageNum) {
return Integer.toString(nPageNum + 1);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
}
I have resolved the issue.
I have implemented the callbacks in each fragment. And in the MainFragmentActivity replace the fragments.
I am using ViewPager with my fragments. All fragments has animation and it does not work when switching back maybe because ViewPager saves somehow state of near Fragments, do you have some idea how to avoid it?
getItemPosition() doesn't make anything in this case
private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return GetStartedOneFragment.newInstance();
case 1:
return GetStartedTwoFragment.newInstance();
case 2:
return GetStartedThreeFragment.newInstance();
case 3:
return GetStartedFourFragment.newInstance();
case 4:
return GetStartedFiveFragment.newInstance();
case 5:
return GetStartedSixFragment.newInstance();
default:
return GetStartedOneFragment.newInstance();
}
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
I used a Fragment as a slider content, see the sample code below. Feel free to ask more details if required.
I have 4 flight modes in the example. The ViewPager is used with the associated adapter (ScreenSlidePagerAdapter).
You can see the app in the Play Store to see the slider (search "Flight Recorder 24").
// In the main fragment java code
private View headerView;
private ViewPager mPager;
public ScreenSlidePagerAdapter mPagerAdapter;
// ...
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View mainView = inflater.inflate(R.layout.monitoring_fragment,container, false);
// The header of the list
View view = inflater.inflate(R.layout.header_monitoring_fragment, mListView, false);
headerView = view;
//...
mPager = (ViewPager) view.findViewById(R.id.pager);
FragmentManager fm = getChildFragmentManager();
mPagerAdapter = new ScreenSlidePagerAdapter(fm);
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem(UserConfiguration.getUserConf().getPositionFromFlightMode());
// Attach the page change listener inside the activity
mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
// This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position)
{
int flight_mode = UserConfiguration.getFlightModeFromPosition(position);
UserConfiguration.getUserConf().setFlightMode(flight_mode);
}
// This method will be invoked when the current page is scrolled
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
// Code goes here
}
// Called when the scroll state changes:
// SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING
#Override
public void onPageScrollStateChanged(int state)
{
// Code goes here
}
});
// ...
}
// ...
// Slider adapter
private class ScreenSlidePagerAdapter extends FragmentPagerAdapter
{
public ScreenSlidePagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
// position to flight mode
int flight_mode = UserConfiguration.getFlightModeFromPosition(position);
FlightModeFragment flightModeFragment = FlightModeFragment.newInstance(flight_mode);
return flightModeFragment;
}
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
#Override
public int getCount()
{
return 4;
}
}
Then you have to create a Fragment with your slider content (here the class FlightModeFragment), it will be instanciated with an integer to identify the page embedded into a Bundle savedInstanceState (I have 4 pages).
public class FlightModeFragment extends Fragment
{
LinearLayout mainLayout;
ImageView live15minImageView;
ImageView modeImageView;
ImageView imageViewLeft;
ImageView imageViewRight;
private TextView textViewRecord;
private TextView textViewGps;
int flight_mode = UserConfiguration.AC_LISTENER_TRAVEL_RECORDER_MODE;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// handle fragment arguments
Bundle arguments = getArguments();
if(arguments != null)
{
flight_mode = arguments.getInt("flight_mode");
}
}
// ...
}
I'm working with viewpager inside fragments. I'm using pagerAdapter to switch between two pages via XML. Here is the code:
public class DemoPagerAdapter extends FragmentPagerAdapter {
public DemoPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
Fragment f;
switch (index) {
case 0:
f = new FirstFragment();
break;
case 1:
f = new SecondFragment();
break;
}
return f;
}
#Override
public int getCount() {
return 2;
}
}
And I'm calling it like this:
public class DemoFragment1 extends Fragment {
private ViewPager viewPager;
private DemoPagerAdapter mAdapter;
public DemoFragment1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.security, container, false);
mAdapter = new DemoPagerAdapter(getActivity().getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
showPages(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
return rootView;
}
Everything works fine. But if I move to DemoFragment2 and then come back to DemoFragment1, PagerAdapter is not called.
Your ViewPager is nested in a Fragment, you should use the ChildFragmentManager, modify:
mAdapter = new DemoPagerAdapter(getChildFragmentManager());
I also assume the ViewPager will keep the off screen fragment in memory, thus it might not call getItem(int index) again. Add
viewPager.setOffscreenPageLimit(0);
return rootView;
Well, I encontered this issue last week.
When I put the ViewPager in the fragment with a FragmentPagerAdapter, after I move forward to anoter Fragment and back, the pager' s view not exists.
I supposed is the FragmentPagerAdapter won' t retain its view in the ViewPager ' s host Fragment, Their life cycle is not the same. Though you put the VewPager' s host Fragment in the back stack, but the FragmentPagerAdapter' s fragment not. And Then, I gave up FragmentPagerAdapter and tried android.support.v4.view.PagerAdapter, (note, it wont' t use fragment to inject view!), everything is fine!
below is the sample:
private final PagerAdapter coverPager = new PagerAdapter() {
private LayoutInflater mLayoutInflater;
#Override
public int getCount() {
return 2;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (mLayoutInflater == null) {
mLayoutInflater = LayoutInflater.from(getActivity());
}
switch (position) {
case 0:
View frontPage = mLayoutInflater.inflate(R.layout.profile_cover, container, false);
ImageView avatar = (ImageView) frontPage.findViewById(R.id.avatar);
Picasso.with(getActivity())
.load(mAvatarUrl)
.placeholder(R.drawable.error)
.error(R.drawable.error)
.into(avatar);
TextView screenName = (TextView) frontPage.findViewById(R.id.screen_name);
screenName.setText("#" + mScreenName);
TextView remark = (TextView) frontPage.findViewById(R.id.remark);
remark.setText(TextUtils.isEmpty(mRemark) ? mScreenName : mRemark);
if (mVerified) {
frontPage.findViewById(R.id.verified).setVisibility(View.VISIBLE);
}
container.addView(frontPage);
return frontPage;
case 1:
View introPage = mLayoutInflater.inflate(R.layout.profile_intro, container, false);
CatnutUtils.setText(introPage, R.id.description, TextUtils.isEmpty(mDescription)
? getString(R.string.no_description) : mDescription);
CatnutUtils.setText(introPage, R.id.location, mLocation);
CatnutUtils.setText(introPage, R.id.profile_url, Constants.WEIBO_DOMAIN + mProfileUrl);
container.addView(introPage);
return introPage;
default:
return null;
}
}
};
and then in your onViewCreate or OnCreateView, put mViewPager.setAdapter(coverPager);
the instantiateItem is the place to put the page' s view, similar like the FragmentPagerAdapter!
It' s just like put the FragmentAdapter' s view int the ViewPager' s host Fragment, not the other fragment!
Hope it' s helpful!
I am using ViewPager and Fragment to display data from sqlite. Content for all page is same so I used same Fragment class for all pages. In fragment there is a TextView. And there are two Buttons in Activity.
I am trying to update text of TextView when any Button is clicked from Activity. For this I used interface and override methods in fragment.All works fine.
Note: Buttons are in Activity(common for all pages)
Problem
When I press button it will update textview of next page. E.g. when I click button in page1 the textview of page2 will be updated and so on.
I used following code. Any help would be appreciate. Thanks.
Fragment code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create a new TextView and set its text to the fragment's section
// number argument value.
View view = inflater.inflate(R.layout.fragmentview, container, false);
txtAmount = (TextView) view.findViewById(R.id.txtAmount);
return view;
}
#Override
public void onPlusClick(String amount) {
// update textview here
}
#Override
public void onMinusClick(String amount) {
// update textview here
}
Adapter code
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummyFragment();
onClick = (onButtonClick) fragment;
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return arrModel.size();
}
#Override
public CharSequence getPageTitle(int position) {
return arrModel.get(position).fname;
}
Activity code
#Override
public void onClick(View v) {
if (v == btnMinus) {
onClick.onMinusClick(edtAmount.getText().toString());
} else if (v == btnPlus) {
onClick.onPlusClick(edtAmount.getText().toString());
}
}
Every time getItem is called you are creating a new fragment a assigning it to onClick so onClick is having reference to the latest fragment which in 2nd in your case.
Try creating a list of fragments in constructor of the adapter:
List<Fragment> fragments=new List<Fragment>();
Fragment currentFragment;
public Myadapter(){
fragments.add(new DummyFragment());
fragments.add(new DummyFragment());
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
public Fragment getCurrentFragment(){
return currentFragment;
}
#Override
public void setPrimaryItem(ViewGroup container, int position,
Object object) {
super.setPrimaryItem(container, position, object);
currentFragment=fragments.get(position);
}
Then in Activity-
public void onClick(View v) {
if (v == btnMinus) {
adapter.getCurrentFragment().onMinusClick(edtAmount.getText().toString());
} else if (v == btnPlus) {
adapter.getCurrentFragment().onPlusClick(edtAmount.getText().toString());
}
}
I have a fragment activity that uses a ViewPager to display a set of fragments. On the fragment activity I have a button that when clicked, it sends a message to the current fragment to refresh its contents. Everything works ok (activity / current fragment communication) except the fact that I cannot refresh the fragment's view. Accessing the current view by getView() does not work as this function returns null; it seems that after the fragment is created (on ViewCreated is called) getView gets destroyed. Am I missing something here? How to I cause a fragment to redraw its contents programmatically? It seems that the only way this works is when the fragment is created from the parent activity. Do I have to remove and re-add the fragment again to do this?
Here is the code:
The main activity:
public class MainActivity extends FragmentActivity {
private MyAdapter mAdapter;
private static ViewPager mPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViewPager();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_test:
updateFragment();
return true;
default: return true;
}
}
private void updateFragment() {
for (int i=0; i< mAdapter.getCount(); i++) {
SampleFragment fragment = (SampleFragment) mAdapter.getItem(i);
fragment.update();
}
}
private void setupViewPager() {
try {
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(this.mAdapter);
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
SampleFragment fragment = new SampleFragment(position);
return fragment;
}
#Override
public int getCount() {
return 5;
}
}
}
and the fragment class:
public class SampleFragment extends Fragment{
private int myPosition = -1;
public SampleFragment(int position) {
this.myPosition = position;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
update(view, "Updated from onCreateView");
return view;
}
#Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.textTitle).setOnClickListener(myClickListener);
}
private OnClickListener myClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.textTitle:
break;
}
}
};
public void update() {
update(getView(), "Updated from main");
}
private void update(View view, String subtitleText) {
TextView title = (TextView) view.findViewById(R.id.textTitle);
TextView subtitle = (TextView) view.findViewById(R.id.textSubtitle);
title.setText("Fragment " + myPosition);
subtitle.setText(subtitleText);
}
}
The error happens on view.FindViewById (view is null) when called from the menu item in the main activity.
You can take a look at this article which explains how to keep references to the fragments in your ViewPager.
There are two methods described on the page. The first one involves setting a tag when you add the fragment using the FragmentManager. Then you can retrieve the fragment using findFragmentByTag(). However, I did not see how to make this work using FragmentPagerAdapter or FragmentStatePagerAdapter, since these implementations add the fragments for you. If you are using your own custom PagerAdapter, this may work for you.
The other method, which does work for FragmentPagerAdapter or FragmentStatePagerAdapter, involves keeping a map of all your fragments, updating inside your getItem() and destroyItem() implementations. This method has worked for me.
Once you have a reference to the current fragment, you can just call a method in your fragment to refresh its view.