Reputation: 12385
I'm building an App that use Fragment and a single MainActivity
that showing different fragments in the same ViewPager to replicate the behaviour of a typical MVC application.
The problem is that haven't understood how could I update the fragment programmatically to update the ViewPager
with the new Fragment changes
For example I have this Fragment
that show a chart, (in my intention) when I invoke setFragment(int interval, Point[] snodePoint)
from the main, the chart should be updated in ViewPager
public class LineFragment extends Fragment {
static int interval;
static Point snodePoints[];
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_linegraph, container,
false);
Bundle bundle = this.getArguments();
ChartConfig cg = bundle.getParcelable("FragmentData");
snodePoints = cg.getPoints();
interval= cg.getInterval();
Line l = new Line();
for(int i=0; i<snodePoints.length; i++){
LinePoint p = new LinePoint();
Point sp=snodePoints[i];
p.setX(sp.getX());
p.setY(sp.getY());
l.addPoint(p)
}
l.setColor(getResources().getColor(R.color.green));
LineGraph li = (LineGraph) v.findViewById(R.id.linegraph);
li.addLine(l);
li.setRangeY(0, interval);
li.setLineToFill(0);
li.setOnPointClickedListener(new OnPointClickedListener() {
@Override
public void onClick(int lineIndex, int pointIndex) {
// TODO Auto-generated method stub
}
});
return v;
}
}
In few words I need to
How could I do this?
The Main Activity with the FragmentAdapter
public class MainActivity extends FragmentActivity {
ViewPager mViewPager;
MyFragmentAdapter mMyFragmentAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
final ActionBar bar = this.getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
LineFragment lineFrag = new LineFragment();
BarFragment barFrag = new BarFragment();
PieFragment pieFrag = new PieFragment();
mMyFragmentAdapter = new MyFragmentAdapter(this, mViewPager);
mMyFragmentAdapter.addTab(bar.newTab().setText("Line"), LineFragment.class,
null, lineFrag);
mMyFragmentAdapter.addTab(bar.newTab().setText("Bar"), BarFragment.class,
null, barFrag);
mMyFragmentAdapter.addTab(bar.newTab().setText("Pie"), PieFragment.class,
null, pieFrag);
mViewPager.setOffscreenPageLimit(mMyFragmentAdapter.getCount() - 1);
}
public static class MyFragmentAdapter extends FragmentStatePagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final MainActivity mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private final ArrayList<Fragment> mFrag = new ArrayList<Fragment>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public MyFragmentAdapter(MainActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args,
Fragment frag) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mFrag.add(frag);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
Bundle args = new Bundle();
ChartConfig cg = new ChartConfig(interval, snodePoint);
args.putParcelable("FragmentData", cg);
Fragment f = mFrag.get(position);
f.setArguments(args);
return f;
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
}
}
}
The first time that I create the fragment, the main activity pass successful the parameters to the Fragment through the overrided getItem(int position)
, but if I try to change the data, also if I try to invoke notifyDataSetChanged()
on the adapter mMyFragmentAdapter
, nothing happens and the fragments in ViewPager
continue to use the same data passed in creation.
EDIT
Following some partial code seen in other question about fragment update I have also tried this
public void update() {
try{
LineFragment fragment =
(LineFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.view_pager+":0");
if(fragment != null)
{
if(fragment.getView() != null)
{
fragment.updateDisplay();
}
}
}
catch(RuntimeException e){
e.printStackTrace();
}
}
Assuming that 0 is the id of the first Fragment-Tab fragment(I'm not sure about this kind of operation), but fragment.updateDisplay();
is not invoked.
Upvotes: 24
Views: 77258
Reputation: 29
This code is work for Kotlin
Inside the Viewpager Adapter use this:-
val viewPagerAdapter = ViewpagerAdapter(childFragmentManager)
view_pager.offscreenPageLimit = 3
In-side the fragment use this :-
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
// hit API
}
override fun onResume() {
super.onResume()
// hit API
}
Upvotes: 0
Reputation: 675
How to update-refresh Fragment in View Pager by Main Activity programmatically after long struggle I have found proper solution
tablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
refreshTab(tab.getPosition());// create a method
viewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
private void refreshTab(int position) {
switch (position) {
case 0:
break;
case 1:
CompaniesInterest comP1 = (CompaniesInterest) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
comP1.refreshpage();
break;
case 2:
TotalSelectedCompanies toTal = (TotalSelectedCompanies) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
toTal.refreshpage();
}
}
// Create a interface for refresh data for fragmen
public interface Refreshpage {
void refreshpage();
}
// implements Refreshpage interface in both fragment TotalSelectedCompanies and CompaniesInterest
//
@Override`enter code here`
public void refreshpage() {
// do what you want to refresh
}
Upvotes: 3
Reputation: 1441
very simple to override the method in the fragment
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();
}
else{
//no
}
}
Upvotes: 3
Reputation: 11329
In your Adapter override getItemPosition
@Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}
After that
viewPager.getAdapter().notifyDataSetChanged()
should work.
Upvotes: 61
Reputation: 87064
I need to understand how the Fragment can get the data passed by main, maybe I'm missing something but really I haven't understood how could I do this.
From this it seems that you want to pass the data at the moment of the creation of the Fragment
. If this is what you want you shouldn't make a custom constructor(and generally for a Fragment
you should have only the default no-args constructor(because the platform needs it to recreate the Fragment
at certain times)).
Instead you should either pass the data in a Bundle
:
@Override
public Fragment getItem(int position) {
switch (position) {
//...
Bundle args = new Bundle();
args.put("a_string_representing_theKey", data)
LineFragment f = new LineFragment();
f.setArguments(args);
return f;
//...
}
}
This will only work if the data can be put in a Bundle
(see the put...
method of the Bundle
class, all primitives + objects that are Parcelable
). In the fragment you could then retrieve the arguments using getArguments()
.
You can also make the Fragment
retrieve the data directly from the Activity
:
// in the lifecycle method where you want the data
((MainActivity)getActivity()).getDataForFragment(); // use the data
For example I have this Fragment that show a chart, (in my intention) when I invoke setFragment(int interval, Point[] snodePoint) from the main, the chart should be updated in ViewPager
You seem to contradict yourself. For this use the code from the question I linked to, of course just calling your current setFragment()
method will not do anything as you just update the value of two variables, you'll need to let the UI know about the change(like calling another method to recreate the view hierarchy, setting the new values on the chart view and calling invalidate()
etc).
Edit:
The code used in the question I linked to should work, but you aren't using the proper code. You have a FragmentStatePagerAdapter
but you're using the code for a FragmentPagerAdapter
which will not work:
FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mViewPager.getAdapter();
LineFragment f = (LineFragment) a.instantiateItem(pager, thePositionYouWant);
Keep in mind that the code above will work only for the visible fragment plus 1 fragment on each side, the other fragments will not be available(and as the user doesn't see them or can't move to them right away they shouldn't be updated).
Upvotes: 3