I try to build viewPager with several fragments.
But when I launch app I get crash with text
Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
my code is following:
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 4;
MainFragment main;
CartFragment cart;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
main = new MainFragment();
cart = new CartFragment();
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return main;
case 1:
return null;
case 2:
return null;
case 3:
return cart;
default:
return null;
}
}
}
Use below code for calling Fragments...
#Override
public android.support.v4.app.Fragment getItem(int position) {
Fragment f = new Fragment();
switch (position) {
case 0:
f = new LogoFragment();
break;
case 1:
f = new AboutUsFragment();
break;
case 2:
f = new ServicesFragment();
break;
}
return f;
}
this is my way to use it :
public class ViewPagerAdapter extends FragmentPagerAdapter {
ArrayList<PagerFragments> mFragments;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
this.mFragments = new ArrayList<>();
}
public void addFragment(Fragment fragment,String title) {
PagerFragments t = new PagerFragments();
t.setTitle(title);
t.setFragment(fragment);
mFragments.add(t);
notifyDataSetChanged();
}
public void addFragment(Fragment fragment) {
PagerFragments t = new PagerFragments();
t.setFragment(fragment);
mFragments.add(t);
notifyDataSetChanged();
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
return mFragments.get(position).getFragment();
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return mFragments.get(position).getTitle();
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return mFragments.size();
}
}
PagerFragment.java :
import android.support.v4.app.Fragment;
public class PagerFragments {
Fragment fragment;
String title;
public Fragment getFragment() {
return fragment;
}
public void setFragment(Fragment fragment) {
this.fragment = fragment;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Then in fragment or activity :
private ViewPagerAdapter viewPagerAdapter;
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
viewPagerAdapter.addFragment(new RTopGainLossFragment(oneDay), "1D");
viewPagerAdapter.addFragment(new RTopGainLossFragment(oneWeek), "1W");
viewPagerAdapter.addFragment(new RTopGainLossFragment(oneMonth), "1M");
viewPagerAdapter.addFragment(new RTopGainLossFragment(oneYear), "YTD");
viewPagerAdapter.addFragment(new RTopGainLossFragment(ytd), "1Y");
viewPagerAdapter.addFragment(new RTopGainLossFragment(max), "MAX");
viewpager.setAdapter(viewPagerAdapter);
tab.setupWithViewPager(viewpager);
Related
In my viewpager i set listener from which i call methods from my interface in tab fragments.
But variable in this tab fragments in my interfaces methods always return null.
Tell me why ?
p.s. sorry for my english)
Parent fragment:
public class MyFragment
extends Fragment {
protected Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public void onDetach() {
super.onDetach();
mContext = null;
} }
Container fragment with PagerAdapter:
public class FragmentContainer
extends MyFragment {
private ViewPager viewPager;
private ViewPager.OnPageChangeListener onPageChangeListener;
public interface IPageSelected {
void onPageSelected();
void onPageUnselected();
}
public static FragmentContainer newInstance() {
return new FragmentContainer();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_container, container, false);
viewPager = view.findViewById(R.id.pager);
PagerAdapter pagerAdapter = new PagerAdapter(getFragmentManager());
viewPager.setAdapter(pagerAdapter);
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
onPageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
for(int x = 0; x < pagerAdapter.getCount(); x++) {
((IPageSelected) pagerAdapter.getItem(x)).onPageUnselected();
}
((IPageSelected) pagerAdapter.getItem(position)).onPageSelected();
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
viewPager.addOnPageChangeListener(onPageChangeListener);
return view;
}
#Override
public void onResume() {
super.onResume();
setCurrentItem();
}
private void setCurrentItem() {
viewPager.post(() -> {
viewPager.setCurrentItem(0);
onPageChangeListener.onPageSelected(0);
});
}
class PagerAdapter
extends FragmentStatePagerAdapter {
PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return TestFragment1.newInstance();
case 1:
return TestFragment2.newInstance();
}
return null;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Tab1";
case 1:
return "Tab2";
default:
return null;
}
}
} }
Tab fragments.
Question: why variable mContext in interface methods always return null ?
public class TestFragment1
extends MyFragment
implements FragmentContainer.IPageSelected {
public static TestFragment1 newInstance() {
return new TestFragment1();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
#Override
public void onPageSelected() {
Log.d("myLog", "TestFragment1 onPageSelected: " + mContext); // WHY NULL ???
}
#Override
public void onPageUnselected() {
Log.d("myLog", "TestFragment1 onPageUnselected: " + mContext); // WHY NULL ???
} }
public class TestFragment2
extends MyFragment
implements FragmentContainer.IPageSelected {
public static TestFragment2 newInstance() {
return new TestFragment2();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment2, container, false);
}
#Override
public void onPageSelected() {
Log.d("myLog", "TestFragment2 onPageSelected: " + mContext); // WHY NULL ???
}
#Override
public void onPageUnselected() {
Log.d("myLog", "TestFragment2 onPageUnselected: " + mContext); // WHY NULL ???
} }
In your fragment container :
PagerAdapter pagerAdapter = new PagerAdapter(getFragmentManager()); here is the fault.
In order to attach your child fragments to your container fragment, consider passing child fragment manager getChildFragmentManager() to your viewpager adapter. (Right now your fragments are attached to same level as your container fragment).
I found solution.
Adapter class.
Old:
class PagerAdapter
extends FragmentStatePagerAdapter {
PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return TestFragment1.newInstance();
case 1:
return TestFragment2.newInstance();
}
return null;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Tab1";
case 1:
return "Tab2";
default:
return null;
}
}
}
New:
class PagerAdapter
extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Adapter initialization.
Old:
PagerAdapter pagerAdapter = new PagerAdapter(getFragmentManager());
viewPager.setAdapter(pagerAdapter);
New:
PagerAdapter pagerAdapter = new PagerAdapter(getFragmentManager());
pagerAdapter.addFragment(TestFragment1.newInstance(), "tab1");
pagerAdapter.addFragment(TestFragment2.newInstance(), "tab2");
viewPager.setAdapter(pagerAdapter);
And now new question: what's the differense with the first option ?
Now i initializing adapter in container fragment, it's a cause ?
Why didn't work when initializing was in the adapter ?
How can i send data from Activity to tab fragment when FloatingActionButton is clicked OR where do get it wrong and how can i fix it,I know it has been asked number of times and i tries all solution include this this and this which gave clear explanation but still work for more that 20hr of working i got no error and nothing works.
//float button in main activity
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String MyValue=" Hi fragment";
Bundle bundle = new Bundle();
bundle.putString("value", MyValue);
// set Fragmentclass Arguments
TabFragment1 fragobj = new TabFragment1();
fragobj.setArguments(bundle);
}
});
//In fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view =inflater.inflate(R.layout.tab_fragment_1, container, false);
TextView textView= (TextView)view.findViewById(R.id.textView) ;
if (getArguments() != null) {
String MyValue = getArguments().getString("value");
textView.setText(MyValue);
}
return view;
}
//// here is the adapter
public class PagerAdapter extends FragmentStatePagerAdapter {
private final SparseArray<WeakReference<Fragment>>
instantiatedFragments = new SparseArray<>();
private ArrayList<String> mTabHeader;
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
TabFragment1 tab1 = new TabFragment1();
return tab1;
case 1:
TabFragment2 tab2 = new TabFragment2();
return tab2;
case 2:
TabFragment3 tab3 = new TabFragment3();
return tab3;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
final Fragment fragment = (Fragment) super.instantiateItem(container, position);
instantiatedFragments.put(position, new WeakReference<>(fragment));
return fragment;
}
#Override
public void destroyItem(final ViewGroup container, final int position, final Object object) {
instantiatedFragments.remove(position);
super.destroyItem(container, position, object);
}
#Nullable
public Fragment getFragment(final int position) {
final WeakReference<Fragment> wr = instantiatedFragments.get(position);
if (wr != null) {
return wr.get();
} else {
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return mTabHeader.get(position);
}
}
First, i assume that you want to update the fragment whenever you press the fab, even if your fragment is already on screen. your adapter is returning a new fragment each time, you should instead hold the fragments instance and return the fragment for the given position stored in your array.
Check this generic FragmentStatePagerAdapter:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragmentList = new ArrayList<>();
private List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
}
#Override
public CharSequence getPageTitle(int position) {
if (!mFragmentTitleList.isEmpty()) {
return mFragmentTitleList.get(position);
}
return "";
}
}
Then on your fragment create a method to update your info:
public void updateData(String string){
miTextView.setText(string);
}
And finally on your activity do something like this:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
YourFragment fragment = (YourFragment) adapter.getItem(desiredPosition);
fragment.updateData("your string");
}
});
I have a basic PagerAdapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public PagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Main tab1 = new Main();
return tab1;
case 1:
Secondary tab2 = new Secondary();
return tab2;
case 2:
Third tab3 = new Third();
return tab3;
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
}
It works perfectly for one tablayout and 3 fragments which are displayed in the viewpager. I have multiple of the same fragment design (same tabs) across a few fragments. Is it possible to use this one PagerAdapter with multiple options (fragments), so all it has to change is the classes that are instantiated.
Main tab1 = new Main(); to SomeOtherClass tab1 = new SomeOtherClass();. I tried doing this with parameters and variables but no success.
In the public Fragment getItem(int position); method, you should return the fragment in the mFragmentListfor the given position. Something like this:
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
By this way you can use this adapter for any Fragment.
Also, the method getCount() should be as follow:
#Override
public int getCount() {
return mFragmentList!=null ? mFragmentList.size() : 0;
}
In order to avoid hardcoded values.
I am using ViewPager,
I have to display more data in two fragments, but it does not show anything.
Is There an alternative layout to do it?
this is layout code:
<android.support.v4.view.ViewPager
android:id="#+id/mainContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.8">
</android.support.v4.view.ViewPager>
this is adapter:
public class HitoeAdapter extends FragmentPagerAdapter {
private static HitoeAdapter adapter;
private final HeartRateFragment mHeartRateFragment;
private final ECGFragment mECGFragment;
public HitoeAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
mHeartRateFragment = new HeartRateFragment();
mECGFragment = new ECGFragment();
}
#Override
public Fragment getItem(int pos) {
switch (pos) {
case 0:
return mHeartRateFragment;
case 1:
return mECGFragment;
default:
return null;
}
}
#Override
public int getCount() {
return 2;
}
}
Please help me.
Thanks.
Create the adapter class like below--
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Now add this method to set your fragments with viewpager -
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new HeartRateFragment(), "HeartRateFrag");
adapter.addFragment(new ECGFragment(), "ECGFragment");
viewPager.setAdapter(adapter);
}
My host activity has a viewpager with two fragments A and B.My activity code looks like this:
public class MainActivity extends AppCompatActivity implements
OnDataLoadedListener {
private ViewPager pager;
private MyPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
final int pageMargin = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 4, getResources()
.getDisplayMetrics());
pager.setPageMargin(pageMargin);
tabLayout.setupWithViewPager(pager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String[] TITLES = { "A",
"B" };
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return A.getInstance();
case 1:
return B.getInstance();
}
return null;
}
}
public Fragment findFragmentByPosition(int position) {
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + pager.getId() + ":"
+ adapter.getItemId(position));
}
Now when activity start viewpager get populated with fragment properly and I try to access fragmentby using following code:
if (AFragment == null)
AFragment = (A) findFragmentByPosition(0);
if (BFragment == null)
BFragment = (B) findFragmentByPosition(1);
But AFragment and BFragment always contains null.I have read other simmilar question but it didn't help either.I need access to fragments as I want to call some methods defined in fragment from host activity.
Code to get an instance of fragment:
public static AFragment getInstance() {
AFragment fragment = new AFragment();
return fragment;
}
I'm think that the problem is that you need to move the method to the Adapter, because you need the original instance of the FragmentManager :
public class MyPagerAdapter extends FragmentPagerAdapter {
FragmentManager fm;
private final String[] TITLES = { "A",
"B" };
public MyPagerAdapter (FragmentManager fm) {
super(fm);
this.fm = fm;
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return A.getInstance();
case 1:
return B.getInstance();
}
return null;
}
public Fragment findFragmentByPosition(int position, int pagerId) {
return fm.findFragmentByTag(
"android:switcher:" + pagerId + ":"
+ getItemId(position));
}
}
So now you can call:
adapter.findFragmentByPosition(position, pager.getId());