3

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;
    }
Community
  • 1
  • 1
coffeeak
  • 2,980
  • 7
  • 44
  • 87
  • try to make a simple activity with an imageView and charge it with an image, just to know weither the problem in the adapter or in api that download the image. Another thing don't forget to add internet permission – Fakher Oct 07 '15 at 10:03
  • display image outside if condition may be help – Mohit Suthar Oct 07 '15 at 10:16

1 Answers1

3

those line:

//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);

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 your GridView . 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

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • what's the size of `movies`? – Blackbelt Oct 07 '15 at 10:04
  • and getView is called ? Did you declare the internet permission on the manifest ?Are you able o load one of the picture returned by `getThumbnail()` – Blackbelt Oct 07 '15 at 10:09
  • yes, getView is being called but no, not one single picture is being loaded.....I added the internet permission too – coffeeak Oct 07 '15 at 10:13
  • Are you able to load one of the picture returned by getThumbnail() on your browser ? – Blackbelt Oct 07 '15 at 10:16
  • What appears in the LogCat for this entry: Log.v("Populating", movies.get(position).getThumbnail()); You can always check in a browser and ensure the url you are constructing actually points to an image. (Please be careful not to post your api_key) – James Oct 07 '15 at 10:17
  • Yes, just tried one of the urls and there is an image (doesn't have the api key so can post it here): http://image.tmdb.org/t/p/w185/t5KONotASgVKq4N19RyhIthWOPG.jpg – coffeeak Oct 07 '15 at 10:19
  • try prepending a valid schema: Something like `http://image.tmdb.org/t/p/w185/t5KONotASgVKq4N19RyhIthWOPG.jpg` – Blackbelt Oct 07 '15 at 10:19
  • Unfortunately No luck :'( – coffeeak Oct 07 '15 at 10:21
  • A little update though, if I input one image url, then the image will load. – coffeeak Oct 07 '15 at 10:54
  • In Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail); Instead of using the *dynamic* url, I put in one url. – coffeeak Oct 07 '15 at 10:57
  • you mean, if you hardcode the one of the image url? – Blackbelt Oct 07 '15 at 10:58
  • move `Log.v("Populating", movies.get(position).getThumbnail());` outside `if (convertView)` and what it is printing on the log – Blackbelt Oct 07 '15 at 10:59
  • It still prints out the thumbnail urls outside the if – coffeeak Oct 07 '15 at 11:05
  • are they correct ? If you try to open them one by one in the browser ? – Blackbelt Oct 07 '15 at 11:06
  • could you update your question with the changes you did. It should work – Blackbelt Oct 07 '15 at 11:11
  • if there is an issue it lies somewhere else. Sorry I couldn't help you more – Blackbelt Oct 07 '15 at 12:27
  • @Blackbelt Finally got it working with this thread's solution: http://stackoverflow.com/questions/24179665/okhttp-and-picasso-dont-run-together/28251889#28251889. I was using picasso 2.5.2 as defined in the course I am following, I just used the same dependencies as those in the thread and tada! Working. I can finally sleep now.... – coffeeak Oct 07 '15 at 14:47