I have been making a Movie App (project work for learning android on udacity btw). I encountered a few problems but resolved them by following threads such as these Unable to modify ArrayAdapter in ListView: UnsupportedOperationException
However, although my app does not crash, the images are not loading and I cannot figure out why. Here is my code:
Layout XMl files movies_item.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id = "@+id/movies_item_thumbnail"
>
</ImageView>
fragment_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.cindy.popularmovies.MoviesFragment">
<GridView
android:id="@+id/movies_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:gravity="center"
/>
</FrameLayout>
MovieArrayAdapter.java
public class MovieArrayAdapter extends ArrayAdapter<Movie> {
private final Context context;
private final List<Movie> movies;
public MovieArrayAdapter(Context context,List<Movie> movies) {
super(context,0,movies);
this.context = context;
this.movies = movies;
}
/*
* Within the getView() method you would inflate an XML based layout and
* then set the content of the individual views based on the Java object for this row.
* */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if(rowView == null) {
//Inflate the XML based Layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.movies_item, parent, false);
//Get the ImageView
ImageView movieThumbnail = (ImageView) rowView.findViewById(R.id.movies_item_thumbnail);
//Load Image into the ImageView
Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail);
Log.v("Populating", movies.get(position).getThumbnail());
}
return rowView;
}
@Override
public int getCount() {
return super.getCount();
}
@Override
public int getPosition(Movie item) {
return super.getPosition(item);
}
}
MovieFragment.java
public class MoviesFragment extends Fragment {
private MovieArrayAdapter mMoviesAdapter;
public MoviesFragment() {
}
@Override
public void onStart() {
super.onStart();
new FetchMoviesTask().execute();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mMoviesAdapter = new MovieArrayAdapter(getActivity(),new ArrayList<Movie>());
GridView moviesGridView = (GridView) rootView.findViewById(R.id.movies_gridview);
moviesGridView.setAdapter(mMoviesAdapter);
return rootView;
}
public class FetchMoviesTask extends AsyncTask<String,Void,Movie[]> {
final String LOG_TAG = this.getClass().getSimpleName();
@Override
protected Movie[] doInBackground(String...params) {
//Retrieve the Popular Movies Json String
String moviesJsonString = getMoviesJsonString();
//Parse the Json String to get important data
try {
return getPopularMoviesInfo(moviesJsonString);
} catch(JSONException e) {
Log.e(LOG_TAG,e.getMessage(),e);
}
return null;
}
@Override
protected void onPostExecute(Movie[] movies) {
if(movies != null) {
mMoviesAdapter.clear();
mMoviesAdapter.addAll(movies);
}
}
/*
* This Function is to retrieve the Popular movies Json String from a WEB API
* */
private String getMoviesJsonString() {
HttpURLConnection urlConnection = null;
BufferedReader bufferedReader = null;
String moviesJsonString = null;
try {
//Set up the URI
final String MOVIES_BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
final String SORT_PARAM = "sort_by";
final String API_PARAM ="api_key";
Uri moviesUri = Uri.parse(MOVIES_BASE_URL).buildUpon()
.appendQueryParameter(SORT_PARAM, "popularity.desc")
.appendQueryParameter(API_PARAM,getString(R.string.movies_api))
.build();
//Open the connection
URL url = new URL(moviesUri.toString());
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
//Read the input stream into a string
InputStream inputStream = urlConnection.getInputStream();
if(inputStream == null) {
return null;
}
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuffer buffer = new StringBuffer();
while((line = bufferedReader.readLine()) != null) {
buffer.append(line + "\n");
}
if(buffer.length() == 0){
//Stream was empty
return null;
}
moviesJsonString = buffer.toString();
}catch(IOException e) {
Log.e(LOG_TAG,"Error",e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if(bufferedReader != null) {
try {
bufferedReader.close();
} catch(IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
return moviesJsonString;
}
/*
* This function is to parse the JSON String to retrieve info
* */
private Movie[] getPopularMoviesInfo(String jsonString) throws JSONException{
//Base URL of thumbnail
final String THUMBNAIL_BASE_URL = " http://image.tmdb.org/t/p/w185";
//The attribute names we are interested in the JSON String
final String M_RESULTS = "results";
final String M_THUMBNAIL = "backdrop_path";
final String M_TITLE = "original_title";
final String M_ID = "id";
final String M_SYPNOSIS = "overview";
final String M_USER_RATING = "vote_average";
final String M_RELEASE_DATE = "release_date";
//Convert Json String to Json Object
JSONObject moviesJsonObject = new JSONObject(jsonString);
//Get the Json Array
JSONArray moviesJsonArray = moviesJsonObject.getJSONArray(M_RESULTS);
Movie[] movies = new Movie[moviesJsonArray.length()];
for(int i=0;i<moviesJsonArray.length();i++) {
JSONObject movie = moviesJsonArray.getJSONObject(i);
movies[i] = new Movie(THUMBNAIL_BASE_URL + movie.getString(M_THUMBNAIL),
movie.getString(M_TITLE),
movie.getString(M_ID),
movie.getString(M_SYPNOSIS),
movie.getString(M_USER_RATING),
movie.getString(M_RELEASE_DATE));
Log.v("Movie",movie.getString(M_TITLE));
}
return movies;
}
}
}
There is no error, but the images are not loading. I have been looking in other threads, but cannot find the answer to my problem. Thank you very much.
[UPDATED] Changed the code according to discussion below:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
//Inflate the XML based Layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.movies_item, parent, false);
}
//Get the ImageView
ImageView movieThumbnail = (ImageView) convertView.findViewById(R.id.movies_item_thumbnail);
//Load Image into the ImageView
Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail);
Log.v("Populating", movies.get(position).getThumbnail());
return convertView;
}
those line:
go outside the
if(rowView == null) {
You will always get only one
null
convertView
, and you have to call that two lines while you are updating/populating yourGridView
. At the moment you should see alway the first image over and over. Please don't forget to add the Internet permission to the manifest