Reputation: 2219
I have assigned Fragment based ViewPager as RecyclerView item. The onBindViewHolder()
inside RecyclerView.Adapter
produces
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
while setting text using setText()
. Means the view is not created at the time of binding the value.
I am not able to figure it out that -> why the view is not created, even though ViewPager
and Fragment
inflation is handled in onCreateViewHolder()
? I tried inflation also in onBindViewHolder()
but still the same.
How can i force Page Fragment
inflation before onBindViewHolder()
.
RecyclerView.Adapter
public class MainListRVA extends RecyclerView.Adapter<ViewHolder> implements ConstantValues {
FragmentManager oFm;
private int viewPagerId = 1;
private static ArrayList<MainListItem> oListItems = new ArrayList<MainListItem>();
MainListRVA(ArrayList<MainListItem> theArray, FragmentManager fm){
oListItems = theArray;
oFm = fm;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_pager_main_list_item_folder, parent, false);
return new FolderVH(v);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
FolderVH folderVH = (FolderVH) holder;
MainListItem listItem = oListItems.get(position);
folderVH.fragmentOne.title.setText(listItem.oTitle);
folderVH.fragmentTwo.title.setText(listItem.oDetail);
/////////////////////////////////////////////////////
////////////////////THIS GIVE NULL POINTER EXCEPTION
}
public class FolderVH extends ViewHolder {
FolderMainPageFragment fragmentOne, fragmentTwo;
ViewPager viewPager;
FolderVH(View v) {
super(v);
ArrayList<Fragment> fragments = new ArrayList<Fragment>();
fragmentOne = FolderMainPageFragment.newInstance("one");
fragmentTwo = FolderMainPageFragment.newInstance("two");
fragments.add(fragmentOne);
fragments.add(fragmentTwo);
FolderVPAdapter folderVPAdapter = new FolderVPAdapter(oFm, fragments);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setId(viewPagerId++);
viewPager.setAdapter(folderVPAdapter);
}
}
@Override
public int getItemCount() {
return oListItems.size();
}
void move(int fromPos, int toPos){ }
void remove(int position){ }
}
FragmentPagerAdapter
public class FolderVPAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public FolderVPAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
@Override
public int getCount() {
return this.fragments.size();
}
}
Pager Fragment
public class FolderMainPageFragment extends Fragment {
TextView title;
public static FolderMainPageFragment newInstance(String text) {
return new FolderMainPageFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main_list_item_view, container, false);
this.title = (TextView) v.findViewById(R.id.list_title);
return v;
}
}
Upvotes: 2
Views: 763
Reputation: 3331
Of course title
is null.
FolderMainPageFragment
hasn't even started its life cycle by the time you are accessing title
. Which means onCreateView
is not called yet and layout has not been inflated so has title
.
As far as inflation in onCreateViewHolder()
is concerned, you are merely inflating the layout view_pager_main_list_item_folder
and not main_list_item_view
(from FolderMainPageFragment
which contains title
) because the FolderVPAdapter
hasn't even started yet.
Also why would you want to put a ViewPager
inside a RecyclerView
is beyond me? Perhaps you could do something else.
To pass data to Fragment
write a method handleArgs() in FolderMainPageFragment
.
public class FolderMainPageFragment extends Fragment {
TextView title;
Bundle mBundle;
public void handleArgs(Bundle bundle) {
mBundle = bundle;
if (title != null)
title.setText(bundle.getString("title"));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main_list_item_view, container, false);
this.title = (TextView) v.findViewById(R.id.list_title);
if (mBundle != null) // When handleArgs() is called before onCreateView().
handleArgs(mBundle);
return v;
}
}
The advantage of writing your own Bundle
method is that you can now use it in onBindViewHolder(). However you need to come up with a way where Bundle's new instance is not created in onBindViewHolder().
Upvotes: 0
Reputation: 2219
Here is the final solution that i have.
1) I added a condition to check if view is null while binding in onBindViewHolder
2) If null i just flagged boolean bindExceptionally
as true inside the fragment class.
3) When fragment will create view at onCreateView()
it will check if the flag is true to set the text. Else it will simply move ahead without setting text.
Note: fragments are inflated in onCreateViewHolder()
and not in onBindViewHolder()
hence fragments inflated only once and then they are recycled.
Updated - RecyclerView.Adapter
public class MainListRVA extends RecyclerView.Adapter<ViewHolder> implements ConstantValues {
FragmentManager oFm;
private int viewPagerId = 1;
static ArrayList<MainListItem> oListItems = new ArrayList<MainListItem>();
MainListRVA(ArrayList<MainListItem> theArray, FragmentManager fm){
oListItems = theArray;
oFm = fm;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_pager_main_list_item_folder, parent, false);
return new FolderVH(v);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Log.e("onBindViewHolder", "onBindViewHolder");
FolderVH folderVH = (FolderVH) holder;
MainListItem listItem = oListItems.get(position);
folderVH.viewPager.setCurrentItem(0);
if(folderVH.fragmentOne.title != null) {
folderVH.fragmentOne.title.setText(listItem.oTitle);
} else {
folderVH.fragmentOne.bindExceptionally = true;
folderVH.fragmentOne.currListItem = listItem;
}
}
public class FolderVH extends RecyclerView.ViewHolder {
FolderMainPageFragment fragmentOne, fragmentTwo;
ViewPager viewPager;
FolderVH(View v) {
super(v);
Log.e("FolderVH", "FolderVH");
ArrayList<Fragment> fragments = new ArrayList<Fragment>();
fragmentOne = FolderMainPageFragment.newInstance("one");
fragmentTwo = FolderMainPageFragment.newInstance("two");
fragments.add(fragmentOne);
fragments.add(fragmentTwo);
FolderVPAdapter folderVPAdapter = new FolderVPAdapter(oFm, fragments);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setId(viewPagerId++);
viewPager.setAdapter(folderVPAdapter);
}
}
@Override
public int getItemCount() {
return oListItems.size();
}
void move(int fromPos, int toPos){ }
void remove(int position){ }
}
Updated - Pager Fragment
public static class FolderMainPageFragment extends Fragment {
TextView title;
boolean bindExceptionally = false;
MainListItem currListItem;
public static FolderMainPageFragment newInstance(String text) {
return new FolderMainPageFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main_list_item_view_folder, container, false);
this.title = (TextView) v.findViewById(R.id.list_title);
if(bindExceptionally) {
title.setText(currListItem.oTitle);
bindExceptionally = false;
currListItem = null;
}
return v;
}
}
Upvotes: 1
Reputation: 533
As Abbas mentioned, the views inside the fragments is not initiated at the time when onBindViewHolder
are called.
You should read a bit about fragments, if fragment is the way you want to go, then you should separate the view logic for the particular fragment inside the fragment.
The only information you are supposed to pass to the fragments is the ones you put in the bundle you pass with setArguments
at initiation of the fragment. There is a lot of lifecycle issues which will give you a pain otherwise.
In this case, if you want to set title to the fragments, you should instead do something like this at initiation:
Bundle args = new Bundle();
bundle.putString("title", "My title");
fragmentOne = FolderMainPageFragment.newInstance("one");
fragmentOne.setArguments(args);
And then in your fragments onViewCreated()
Bundle args = getArguments();
title.setText(args.getString("title"));
Upvotes: 0