Friday, January 25, 2013

ViewPager, Fragment and one oversight

Scenario
There is a  fragment which inflates a view consisting of some UI widgets (few TextViews, Spinners and etc). A ViewPager will load multiple instances of this fragment with different data using FragmentPagerAdapter. As you can see in the first snippet below the data is received through an intent from another activity (first part in red). Then iterating over the data we are creating new fragments, passing as an argument the data we want to populate each fragment with (second part in red). For example, consider the data as a list of all tasks assigned to you by your manager. It consists of subject shown in a TextView, status of the task shown in a Spinner and whether its finalized or not shown with a CheckBox.

Problem
ViewPager loads first fragment with the help of  the assigned adapter. The data is loaded into the UI views, so far so good. Now, if we try to swipe to the next fragment we notice that the data either is not populated into the second fragment's UI or it is partially populated. 
public class MyActivity extends FragmentActivity {  
           @Override  
           public void onCreate(Bundle savedInstanceState) {  
                super.onCreate(savedInstanceState);  
                setContentView(R.layout.activity_my_layout);  
                ViewPager pager = (ViewPager) findViewById(R.id.dataPager);  
                List<MyData> dataList = (List<MyData>) getIntent()  
                          .getSerializableExtra("DATA");  
                List<Fragment> fragments = new ArrayList<Fragment>();  
                int i = 0;  
                if (dataList != null) {  
                     for (MyData data: dataList) {  
                          MyFragment myFragment = new MyFragment();  
                          Bundle args = new Bundle();  
                          args.putSerializable("MYDATA", data);  
                          myFragment.setArguments(args);  
                          fragments.add(myFragment);  
                     }  
                MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);  
                pager.setAdapter(adapter);  
           }  
           private class MyPagerAdapter extends FragmentPagerAdapter {  
                private List<Fragment> myFrags;  
                public MyPagerAdapter(FragmentManager manager,  
                          List<Fragment> frags) {  
                     super(manager);  
                     this.myFrags = frags;  
                }  
                @Override  
                public Fragment getItem(int paramInt) {  
                     return myFrags.get(paramInt);  
                }  
                @Override  
                public int getCount() {  
                     return myFrags.size();  
                }  
           }  
      }  
 }  

Solution
In the onCreateView of the fragment we are inflating a view for our fragment's UI. The problem arises when we try to find our UI widgets from findViewById of the activity instead of the inflated view of the current fragment. You can clearly see this in the snippet below. In our example the code in green is the correct way of finding a view.

Public class MyFragment extends Fragment{
      . . .  
      private View rootView;  
      . . .  
      @Override  
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
           rootView = inflater.inflate(R.layout.myLayout, container, false);   
           return rootView;  
      }  
      @Override  
      public void onActivityCreated(Bundle savedInstanceState) {  
           super.onActivityCreated(savedInstanceState);  
           . . .  
           ((TextView) getActivity().findViewById(R.id.my_Text_view))  
                               .setText("MY_TEXT");  
           ((TextView) rootView.findViewById(R.id.my_Text_view))  
                               .setText("MY_TEXT");  
           . . .  
      }   
           . . .  




1 comment :