Reputation: 53
This app displays movies and each movie poster can be clicked to see details about the movie. However, when I try to add a button to the detail view layout the app crashes with these errors. When I remove the button from the layout the app works as it should. This crash seems odd to me.
04-19 20:05:53.479 28975-28975/com.jcaseydev.popularmovies E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.jcaseydev.popularmovies, PID: 28975
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jcaseydev.popularmovies/com.jcaseydev.popularmovies.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.GridView.setAdapter(android.widget.ListAdapter)' 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 'void android.widget.GridView.setAdapter(android.widget.ListAdapter)' on a null object reference
at com.jcaseydev.popularmovies.MovieListFragment.onCreateView(MovieListFragment.java:72)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:339)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:602)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1237)
at android.app.Activity.performStart(Activity.java:6268)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
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)
Here is my detail activity code.
package com.jcaseydev.popularmovies;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
public class DetailFragment extends Fragment{
public DetailFragment(){}
Movie movie;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.detail_fragment, container, false);
//get intent
Intent intent = getActivity().getIntent();
//key for the intent extra
String MOVIE_INFO = "movie_info";
//test if intent is null and if it has the correct extra
if(intent != null && intent.hasExtra(MOVIE_INFO)){
//fill movie with the details of the clicked item
movie = intent.getParcelableExtra(MOVIE_INFO);
//update view with all of the details
updateView(rootView);
}
return rootView;
}
private void updateView(View view){
//set up the views
TextView title = (TextView) view.findViewById(R.id.movieTitle);
TextView overview = (TextView)view.findViewById(R.id.movieOverview);
TextView releaseDate = (TextView)view.findViewById(R.id.movieReleaseDate);
ImageView moviePoster = (ImageView)view.findViewById(R.id.moviePoster);
TextView movieVoteAvg = (TextView)view.findViewById(R.id.movieVote);
//set the text on the views
title.setText(movie.getMovieTitle());
overview.setText(movie.getMovieOverview());
releaseDate.setText(movie.getMovieReleaseDate());
Picasso.with(getActivity()).load(movie.getMoviePoster()).into(moviePoster);
movieVoteAvg.setText(Double.toString(movie.getMovieVoteAverage()));
}
}
Here is the layout file associated with the detailview class
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/moviePoster"
android:contentDescription="@string/movie_poster" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/movieReleaseDate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/movieVote"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/movieTitle" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/movieOverview" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"/>
Here is the movie list class
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MovieListFragment extends Fragment {
private ArrayList<Movie> movieArrayList = new ArrayList<>();
private ArrayList<String> listOfMoviePosters = new ArrayList<>();
private String MOVIE_KEY = "movie_info";
private ImageAdapter imageAdapter;
private String BASE_URL = "http://api.themoviedb.org/3/movie/now_playing";
int toggle = 0;
public MovieListFragment(){
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
private void updateMovies() {
//clear out both lists
movieArrayList.clear();
listOfMoviePosters.clear();
//create a new async task and execute
FetchMovieData fmd = new FetchMovieData();
fmd.execute();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.movie_list_fragment, container, false);
imageAdapter = new ImageAdapter(getActivity(), listOfMoviePosters);
GridView mGridView = (GridView) rootview.findViewById(R.id.movie_list_grid_view);
mGridView.setAdapter(imageAdapter);
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Movie details = movieArrayList.get(position);
Intent intent = new Intent(getActivity(), DetailActivity.class)
.putExtra(MOVIE_KEY, details);
startActivity(intent);
}
});
return rootview;
}
@Override
public void onStart() {
super.onStart();
updateMovies();
}
public class FetchMovieData extends AsyncTask<Void, Void, List<Movie>> {
private List<Movie> getDataFromJSon(String json)throws JSONException{
//items that need to be got
final String ARRAY_OF_MOVIES = "results";
final String TITLE = "title";
final String POSTER_PATH = "poster_path";
final String OVERVIEW = "overview";
final String RELEASE_DATE = "release_date";
final String VOTE_AVERAGE = "vote_average";
final String MOVIE_ID = "id";
//store the json in a json object
JSONObject jsonObject = new JSONObject(json);
//get the actual movie results
JSONArray jsonArray = jsonObject.getJSONArray(ARRAY_OF_MOVIES);
//get the length of the array for looping
int limit = jsonArray.length();
//creat a list of movies
List<Movie> movies = new ArrayList<>();
//loop through all of the movies in the array
for(int i = 0; i < limit; i++){
//get the current movie object
JSONObject movieObject = jsonArray.getJSONObject(i);
//get the various details about the movie
String title = movieObject.getString(TITLE);
String poster = "http://image.tmdb.org/t/p/w342/" + movieObject.getString(POSTER_PATH);
String overview = movieObject.getString(OVERVIEW);
String releasedate = movieObject.getString(RELEASE_DATE);
Double voteAvg = movieObject.getDouble(VOTE_AVERAGE);
int movieId = movieObject.getInt(MOVIE_ID);
//add the movie object to the movie list
movies.add(new Movie(title, poster, overview, releasedate, voteAvg, movieId));
}
return movies;
}
@Override
protected List<Movie> doInBackground(Void... params) {
try {
final String QUERY_API = "api_key";
//Build URL to get data from
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(QUERY_API, BuildConfig.TMDB_API_KEY)
.build();
Log.d("URL", builtUri.toString());
//Using OkHttp to make network request
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(builtUri.toString())
.build();
//creating a response object
Response response = null;
try {
//attempt to execute request
response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
//Storing results of request in a string
String jsonData = response.body().string();
try {
//attempt to call method that will extract data
return getDataFromJSon(jsonData); //call to extract data
} catch (JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(List<Movie> result) {
if (result != null){
//add all of the movie objects that have be gathered
//into the movieArrayList
movieArrayList.addAll(result);
//Call updatePoster to get movie posters
updatePoster();
//notify the image adapter that there is data now
imageAdapter.notifyDataSetChanged();
}
}
public void updatePoster(){
//for every movie in movieArraylist add to
//listOfMoviePosters
for (Movie movie : movieArrayList){
listOfMoviePosters.add(movie.getMoviePoster());
}
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.movie_list_fragment_menu, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//simple way to toggle the sort order
if(id == R.id.sort_action) {
if (toggle == 0) {
BASE_URL = "http://api.themoviedb.org/3/movie/top_rated";
movieArrayList.clear();
listOfMoviePosters.clear();
updateMovies();
toggle = 1;
} else if(toggle == 1){
BASE_URL = "http://api.themoviedb.org/3/movie/now_playing";
movieArrayList.clear();
listOfMoviePosters.clear();
updateMovies();
toggle = 0;
}
}
return super.onOptionsItemSelected(item);
}
}
Im not sure what could be causing this. Thanks in advance for the help!
Upvotes: 1
Views: 102
Reputation: 51
Can you show the content of this file movie_list_fragment.xml? I think the problem is from there. Maybe you the GridView has a different ID as compare to movie_list_grid_view.
Upvotes: 0
Reputation: 13357
The stack trace tells you:
Attempt to invoke virtual method 'void android.widget.GridView.setAdapter(android.widget.ListAdapter)' on a null object reference
Where did you call setAdapter
in the code?
mGridView.setAdapter(imageAdapter);
What did you try to call it on?
mGridView
How did you get the reference to that?
GridView mGridView =(GridView)rootview.findViewById(R.id.movie_list_grid_view);
...Which is clearly returning null. So now just figure out why it can't find the view.
I don't see the id movie_list_grid_view
anywhere in your code.
Upvotes: 1