Reputation: 8626
I have a problem trying to update a ListView in a fragment which is inside a ViewPager fragment. The whole scenario is that a FragmentActivity works like the base to communicate between fragments.
Specifically, a ListFragment single choice fragment sends an object reference in FragmentActivity and then this redirected to the ViewPager fragment which in turn should update another Fragment child of it.
Everything seemd to operate perfect and the ViewPager fragment the first time being created shows the data I need, BUT, then when you select a row in the ListFragment that initiates this procedure while gets into the ViewPager fragment in this block of code,
public void refreshDataWithClassType(ClassType classType) {
Log.d(TAG, "Should refresh data");
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) viewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
ExamsListFragment viewPagerFragment = (ExamsListFragment) fragmentPagerAdapter.getItem(i);
if(viewPagerFragment != null) {
// Do something with your Fragment
// Check viewPagerFragment.isResumed() if you intend on interacting with any views.
viewPagerFragment.refreshExams(classType.getClassTypeId());
}
}
}
I just send the message to every ViewPagerFragment to refresh my data (Exams). But after some time while I got NullPointerException I found out that in the refreshExams method,
public void refreshExams(int classTypeId) {
Bundle args = new Bundle();
args.putInt(KEY_POSITION, getArguments().getInt(KEY_POSITION));
args.putInt(KEY_CLASS_TYPE, classTypeId);
setArguments(args);
getRepositoryExams();
if (examsArrayAdapter == null) Log.d(TAG, "ExamsArrayAdapter is NULL");
if (getActivity() == null) Log.d(TAG, "Activity is NULL");
if (examsList.size() == 0) {
examsArrayAdapter.clear();
examsArrayAdapter.notifyDataSetChanged();
} else {
examsArrayAdapter = new ExamsArrayAdapter(getActivity(), R.layout.exam_row_layout, (ArrayList<Exam>) examsList);
listView.setAdapter(examsArrayAdapter);
}
}
now even I already supposed to have this instance of Fragment and it's OK the first time that it is beign created,
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
rootView = inflater.inflate(R.layout.exams_list_fragment, container, false);
listView = (ListView) rootView.findViewById(R.id.examsListView);
return rootView;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callBackExamListener = (OnExamSelectedListener) activity;
} catch (ClassCastException ex) {
throw new ClassCastException(activity.toString() + " must implement OnExamSelectedListener");
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getRepositoryExams();
examsArrayAdapter = new ExamsArrayAdapter(getActivity(), R.layout.exam_row_layout, (ArrayList<Exam>) examsList);
listView.setAdapter(examsArrayAdapter);
listView.setOnItemClickListener(listRowItemClickListener);
}
getActivity() and examsArrayAdapter is NULL ????
How to fix this?
Thank you in advance!
Upvotes: 2
Views: 2910
Reputation: 2072
As stated here,
Every fragment, even those that are childen of another fragment, receive a call to onAttach() when they are added to the fragment tree. The activity containing the fragment is passed in as a parameter. The simplest solution is may be to save the activity as a member of your fragment. Then it is available when needed later.
The parent activity is passed in as a Context, so you will need to cast it as an Activity. So you can get the containing activity of your nested fragment with this code:
private Activity mHostActivity;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mHostActivity = (Activity) context;
}
Upvotes: 0
Reputation: 13269
I'm actually recognizing some of my code in here. I think what is happening is that you aren't checking to make sure the viewPagerFragment
s you are getting are in onResume
, and they may be destroyed if they are more than 1 page away from the current alive page. If the viewPagerFragment
is not in onResume
, you need to use a method to set a boolean flag on the viewPagerFragment
, so that it will call refreshExams
when it does get into onResume
.
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) viewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
ExamsListFragment viewPagerFragment = (ExamsListFragment) fragmentPagerAdapter.getItem(i);
if(viewPagerFragment != null) {
// Do something with your Fragment
// Check viewPagerFragment.isResumed() if you intend on interacting with any views.
if(viewPagerFragment.isResumed())
viewPagerFragment.refreshExams(classType.getClassTypeId());
}
}
HOWEVER, I actually have found out that this code above only worked well for me due to the way that I created my FragmentPagerAdapter
, as I used an ArrayList
to hold my Fragment
s, and it would return them in getItem
. This FAILED when rotating since Android destroyed the Activity
and Fragment
s. I would suggest that you query the FragmentManager
to get your Fragment
s out of the ViewPager
, and make sure to check if each viewPagerFragment
is in onResume
before refreshing, and set your flag to refresh otherwise. The accepted answer to this question is the RIGHT approach to looking through your ViewPager
's children Fragment
s.
Upvotes: 2