I have written code that fetches a JSON object from a remote endpoint. For this question, I am passing in a mock object which is an array of objects. My goal is to deconstruct the object and for each element of the array, create a fragment within a ViewPager. Each fragment should display the id of the object it is representing. The object looks like this:
{'data':[{'id':1},{'id':2}]}
If I uncomment the code in FragmentClass, each fragment will display "test." However, if I try to set the text based on the value I pass via arguments, I run into this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object reference
The code for FragmentClass is:
public class FragmentClass extends Fragment {
private TextView txtId;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_screen_slide, container, false);
txtId = (TextView) rootView.findViewById(R.id.txtId);
txtId.setText(getArguments().get("id").toString());
// txtId.setText("test");
return rootView;
}
}
The code for the ViewPager class, ScreenSliderPagerActivity is:
public class ScreenSliderPagerActivity extends FragmentActivity {
private ViewPager mPager;
private PagerAdapter pagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
String data = intent.getStringExtra("data");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
// Instantiate a ViewPager and a PagerAdapter.
mPager = (ViewPager) findViewById(R.id.pager);
pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), data);
mPager.setAdapter(pagerAdapter);
}
@Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public int NUM_PAGES; //making this a public variable within the inner class allows me to dynamically change the number of fragments created. In this instance, 2 will be created, one for each element of the array.
public ScreenSlidePagerAdapter(FragmentManager fm, String data) {
super(fm);
try {
JSONObject json = new JSONObject(data);
JSONArray jsonArray = json.getJSONArray("data");
NUM_PAGES = jsonArray.length();
Log.d("NUM_PAGES", String.valueOf(NUM_PAGES)); //2
FragmentTransaction ft = fm.beginTransaction();
Bundle args = new Bundle();
// I think the problem is something in the loop, but I cannot seem to figure another way to do this.
for (int i = 0; i < NUM_PAGES; i++){
JSONObject obj = (JSONObject) jsonArray.get(i);
FragmentClass fragment = new FragmentClass();
ft.add(R.id.pager, fragment);
args.putString("id", obj.get("id").toString());
fragment.setArguments(args);
}
ft.commit();
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public Fragment getItem(int position) {
return new FragmentClass();
}
@Override
public int getCount() {
return NUM_PAGES;
}
}
}
Finally, my MainActivity containing the mock object is:
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.btn);
}
public void handleClick(View view){
String mockData = "{'data':[{'id':1},{'id':2}]}";
Intent intent = new Intent(MainActivity.this, ScreenSliderPagerActivity.class);
intent.putExtra("data",mockData);
MainActivity.this.startActivity(intent);
}
}
FragmentStatePagerAdapter
s don't work that way. You can't add your fragments in constructor of your adapter to the fragment manager and expect it to be added in the right place. You have to return the constructed fragment with the arguments in getItem(int)
method:
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public int NUM_PAGES; //making this a public variable within the inner class allows me to dynamically change the number of fragments created. In this instance, 2 will be created, one for each element of the array.
private ArrayList<FragmentClass> mFragments = new ArrayList<>();
public ScreenSlidePagerAdapter(FragmentManager fm, String data) {
super(fm);
try {
JSONObject json = new JSONObject(data);
JSONArray jsonArray = json.getJSONArray("data");
NUM_PAGES = jsonArray.length();
Log.d("NUM_PAGES", String.valueOf(NUM_PAGES)); //2
for (int i = 0; i < NUM_PAGES; i++){
JSONObject obj = (JSONObject) jsonArray.get(i);
Bundle args = new Bundle();
FragmentClass fragment = new FragmentClass();
args.putString("id", obj.get("id").toString());
fragment.setArguments(args);
mFragments.add(fragment);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return NUM_PAGES;
}
}