0

I'm trying to create an activity with a fragment. The fragment holds a gridview that contain "Movie Objects". Each object has to be represented using an image in the gridview. The image is a url that I save inside the object as a string and that I load with Picasso.

For some reason, when I instantiate my adapter, it triggers a nullPointerException and I can't for my life, figure out why.

This is my Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        if (savedInstanceState== null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new MovieListFragment())
                    .commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

This is my fragment:

public class MovieListFragment extends Fragment {

    private final String LOG_TAG = MovieListFragment.class.getSimpleName();

    MovieAdapter mMovieAdapter = new MovieAdapter(
            getContext(),
            R.id.image_thumbnail,
            new ArrayList<Movie>()
    );

    public MovieListFragment() {
    }

    @Override
    public void onCreate(Bundle SavedInstanceState) {
        super.onCreate(SavedInstanceState);
        // We want to add options to the Menu bar.
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.movielist_fragment, menu);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // We inflate and store the rootView
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        // We sotre the gridview and set a custom adapter to it. It is defined below
        GridView gridView = (GridView) rootView.findViewById(R.id.gridview);
        gridView.setAdapter(mMovieAdapter);

        // The gridView will react to a user clicking on it.
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getActivity(),position,Toast.LENGTH_SHORT);
            }
        });
        return rootView;
    }

    private void retrieveMovies() {
        FetchMoviesTask moviesTask = new FetchMoviesTask();
        moviesTask.execute();
    }

    @Override
    public void onStart() {
        super.onStart();
        retrieveMovies();
    }

    // Custom adapter to display Movies on a gridView
    public class MovieAdapter extends ArrayAdapter<Movie> {
        //Context member variable
        private Context mContext;
        //Constructor
        public MovieAdapter(Context context, int imgViewResourceId,
                            ArrayList<Movie> items) {
            super(context, imgViewResourceId, items);
            mContext = context;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView;
            // If the view passed is null, we initialize it
            if (convertView == null) {
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(80,80));
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setPadding(2,2,2,2);
            } else {
                imageView = (ImageView) convertView;
            }

            String url = getItem(position).getUrlPath();

            Picasso.with(mContext)
                    .load(url)
                    .resize(80,80)
                    .centerCrop()
                    .into(imageView);


            return imageView;
        }

    }

And this is the exception itself:

Process: com.example.madelenko.movierating, PID: 5326
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.madelenko.movierating/com.example.madelenko.movierating.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
     at android.app.ActivityThread.-wrap11(ActivityThread.java)
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
     at android.os.Handler.dispatchMessage(Handler.java:102)
     at android.os.Looper.loop(Looper.java:148)
     at android.app.ActivityThread.main(ActivityThread.java:5417)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
  Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
     at android.view.LayoutInflater.from(LayoutInflater.java:229)
     at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:178)
     at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:163)
     at com.example.madelenko.movierating.MovieListFragment$MovieAdapter.<init>(MovieListFragment.java:101)
     at com.example.madelenko.movierating.MovieListFragment.<init>(MovieListFragment.java:44)
     at com.example.madelenko.movierating.MainActivity.onCreate(MainActivity.java:21)
     at android.app.Activity.performCreate(Activity.java:6251)
     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
     at android.app.ActivityThread.-wrap11(ActivityThread.java) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
     at android.os.Handler.dispatchMessage(Handler.java:102) 
     at android.os.Looper.loop(Looper.java:148) 
     at android.app.ActivityThread.main(ActivityThread.java:5417) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
George Mulligan
  • 11,813
  • 6
  • 37
  • 50

1 Answers1

2

The problem is the MovieListFragment is not yet associated with a Context when you are initializing your MovieAdapter so getContext() is returning null.

To fix this first only declare the adapter:

MovieAdapter mMovieAdapter;

and set its value later after the context is attached to the Fragment. This is anytime after onAttach is called in the Fragment life cycle such as in the onCreateView method you have:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    mMovieAdapter = new MovieAdapter(
        getContext(),
        R.id.image_thumbnail,
        new ArrayList<Movie>()
    );
    ....
}
George Mulligan
  • 11,813
  • 6
  • 37
  • 50
  • Worked perfectly. When exactly is my fragment associated with a context? – Javier Ventajas Hernández Feb 09 '16 at 23:18
  • I included that in the answer. You can use the `Context` anytime from `onAttach` and after as shown in the [lifecycle diagram](http://developer.android.com/images/fragment_lifecycle.png). After `onDetach` is called you should once again be careful making any calls to `getContext()` as it will be `null`. – George Mulligan Feb 09 '16 at 23:24