1

For fun I'm going through the Udacity Popular Movies App tutorial. I have set it so that there is a spinner in the toolbar that calls a sortMovies(String sortBy) method in my MainActivityFragment. The sortMovies() then calls GetMoviesTask.execute(sortBy).

When I run the program, everything works out fine. It displays the gridView of Movie posters sorted by Popularity which I have called in the onCreateView() of the MainActivityFragment.

However, when I click the spinner and choose to sort by "Highest Rated" it executes GetMoviesTask.execute properly (I checked the json being returned), but when it gets time to set the GridView adapter, it is saying the gridView is null.

Here is MainActivity:

public class MainActivity extends AppCompatActivity {

final String SORT_POPULARITY = "popularity.desc";
final String SORT_HIGHEST_RATED = "vote_average.desc";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Spinner spinner = (Spinner) findViewById(R.id.spinner_sort_by);

    ArrayAdapter spinnerAdapter = ArrayAdapter.createFromResource(this,
            R.array.spinner_sort_options,
            R.layout.simple_spinner_layout_item);

    spinner.setAdapter(spinnerAdapter);
    spinnerAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
    spinner.setSelection(0, false);
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            MainActivityFragment mainActivityFragment;
            mainActivityFragment = new MainActivityFragment();

            switch (position) {
                case 0:
                    mainActivityFragment.sortMovies(SORT_POPULARITY);
                    break;
                case 1:
                    mainActivityFragment.sortMovies(SORT_HIGHEST_RATED);
                    break;
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

            // sometimes you need nothing here
        }
    });

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

}

@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);
}
}

Here is MainActivityFragment:

public class MainActivityFragment extends Fragment {

View rootView;
GridView gridView;
List<Movie> movies = new ArrayList<>();

public MainActivityFragment(){

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.fragment_main, container, false);
    gridView = (GridView) rootView.findViewById(R.id.gridView);

    GetMoviesTask getMoviesTask = new GetMoviesTask();
    getMoviesTask.execute("popularity.desc");

    return rootView;
}

@Override
public void onStart() {
    super.onStart();
   // GetMoviesTask getMoviesTask = new GetMoviesTask();
   // getMoviesTask.execute();

}

public void sortMovies(String sortBy) {

    GetMoviesTask getMoviesTask =  new GetMoviesTask();
    getMoviesTask.execute(sortBy);
}

public class GetMoviesTask extends AsyncTask<String, Void, String[]> {


    @Override
    protected String[] doInBackground(String... params) {

        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;
        String sortBy = params[0];
        //Contains the Json Result
        String moviesJson = null;

        try {

            final String API_BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
            final String API_KEY = "b96087f4a03b686eaf542c5df8037005";
            final String API_KEY_PARAM = "api_key";
            final String API_PAGE = "page";
            final String API_SORT_BY = "sort_by";

            Uri apiUri = Uri.parse(API_BASE_URL).buildUpon()
                    .appendQueryParameter(API_SORT_BY, sortBy)
                    .appendQueryParameter(API_PAGE, "1")
                    .appendQueryParameter(API_KEY_PARAM, API_KEY)
                    .build();

            URL url = new URL(apiUri.toString());

            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();
            InputStream inputStream = urlConnection.getInputStream();
            StringBuffer buffer = new StringBuffer();


            if (inputStream == null) {
                moviesJson = null;
            }else {
                reader = new BufferedReader(new InputStreamReader(inputStream));
            }

            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }

            if (buffer.length() == 0) {
                moviesJson = null;
            }

            ////////////////////////////////////////////////////
            //////////Return the json string containing the movies////////////
            moviesJson = buffer.toString();

        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (NetworkOnMainThreadException e) {
            Log.d("Error: ", e.toString());
        }

        try {
            return getMoviesFromJson(moviesJson);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(String[] jsonMovieData) {

        if (jsonMovieData != null) {
            try {
                gridView.setAdapter(new ImageAdapter(getContext(), jsonMovieData));
                gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    public void onItemClick(AdapterView<?> parent, View v,
                                            int position, long id) {

                        //pass the movie to the Detail Activity
                        Intent i = new Intent(getActivity(), MovieDetail.class);
                        i.putExtra("movie", movies.get(position));
                        startActivity(i);

                    }
                });
            } catch (NullPointerException e) {
                e.printStackTrace();
            }

        } else

        {
            Toast.makeText(getContext(), "Nothing to show :(",
                    Toast.LENGTH_LONG).show();
        }

    }

        }


    private String[] getMoviesFromJson(String jsonMovieData) throws JSONException {

        //Json Object(s) to be extracted
        final String TMDB_POSTER = "poster_path";
        final String TMDB_ORIGINAL_TITLE = "original_title";
        final String TMDB_OVERVIEW = "overview";
        final String TMDB_VOTE_COUNT = "vote_count";
        final String TMDB_VOTE_AVERAGE = "vote_average";
        final String TMDB_BACKDROP = "backdrop_path";
        final String TMDB_BASE_POSTER_PATH = "http://image.tmdb.org/t/p/w500/";
        final String TMDB_RESULTS = "results";
        final String TMDB_ID = "id";

        JSONObject moviesJson = new JSONObject(jsonMovieData);
        JSONArray moviesArray = moviesJson.getJSONArray(TMDB_RESULTS);

        String[] posterPaths = new String[moviesArray.length()];


        // Extract movie data and build movie objects
        for(int i = 0; i < moviesArray.length(); i++) {
            Movie movie = new Movie();
            JSONObject movieJson = moviesArray.getJSONObject(i);
            movie.posterPath = TMDB_BASE_POSTER_PATH + movieJson.optString(TMDB_POSTER).toString();
            posterPaths[i] = movie.posterPath;
            movie.title = movieJson.optString(TMDB_ORIGINAL_TITLE).toString();
            movie.description = movieJson.optString(TMDB_OVERVIEW).toString();
            movie.title = movieJson.optString(TMDB_ORIGINAL_TITLE).toString();
            movie.backDrop = movieJson.optString(TMDB_BACKDROP).toString();
            movie.voteAverage = movieJson.optString(TMDB_VOTE_AVERAGE).toString();
            movie.numOfVotes = movieJson.optString(TMDB_VOTE_COUNT).toString();
            movies.add(movie);

        }

        return posterPaths;
    }
}

As stated, when the app loads, the images load in the gridview perfectly fine, but when I select one of the spinners, in onPostExecute it says:

02-02 16:03:13.323 19412-19412/com.ferr3t.don.gurumovies W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.GridView.setAdapter(android.widget.ListAdapter)' on a null object reference
02-02 16:03:13.333 19412-19412/com.ferr3t.don.gurumovies W/System.err:     at com.ferr3t.don.gurumovies.MainActivityFragment$GetMoviesTask.onPostExecute(MainActivityFragment.java:161)

I'm sure there is a simple solution that I am overlooking, however after 2 straight days, I've finally turned to stackOverflow...any help would be greatly appreciated.

  • can you make sure that `gridView = (GridView) rootView.findViewById(R.id.gridView);` is NOT null. – T D Nguyen Feb 02 '16 at 22:47
  • That's the problem...on the second pass through GetMoviesTask.execute() it is null. I'm not sure why, but for some reason it is getting set to null after the first pass through GetMoviesTask.execute(); – Don Harmison Feb 02 '16 at 22:50
  • You mean it works normally for the first pass? – T D Nguyen Feb 02 '16 at 22:58
  • Yes, it works perfectly fine. It loads all the image posters, and you can click on them to see the detailed view. But when I select an item from the spinner (to sort by highest rated or popularity), it gets to "gridView.setAdapter(new ImageAdapter(getContext(), jsonMovieData));" and then throws the nullpointer exception. – Don Harmison Feb 02 '16 at 23:00
  • I think the problem is here: `switch (position) { case 0: mainActivityFragment.sortMovies(SORT_POPULARITY); break; case 1: mainActivityFragment.sortMovies(SORT_HIGHEST_RATED); break; }` – T D Nguyen Feb 02 '16 at 23:00
  • what's the problem there? the switch calls the sortMovies method and passes the correct sortBy variable. It gets all the way to the point where it tries to set the gridView adapter with the new images, then it says gridView is null. – Don Harmison Feb 02 '16 at 23:02

1 Answers1

0

Instead of creating new fragment MainActivityFragment mainActivityFragment; mainActivityFragment = new MainActivityFragment();

You should find the existing fragment in your current activity. When you create a new one but the fragment has not attached to the activity then the createView() method is not called yet causing null pointer exception.

To find the existing fragment:

get currently displayed fragment

Community
  • 1
  • 1
T D Nguyen
  • 7,054
  • 4
  • 51
  • 71
  • Thanks for this answer. It took me a while to figure out that my Fragment was in content_main.xml rather than fragment_main.xml which only contains the Layout. It is working properly now. – Don Harmison Feb 03 '16 at 17:18