2015-11-11 2 views
0

Я пишу приложение, чтобы вытащить данные фильма из api MovieDB и отобразить информацию в GridView.Пользовательский адаптер не обновляет gridview

Когда приложение сначала загружается, я бы ожидал, что представление будет заполнено изначально, но это не так. У меня есть опция сортировки в строке меню, и когда параметр сортировки установлен в первый раз, когда GridView заполняется фильмами в порядке его популярности, как и следовало изначально, но независимо от того, какие критерии отбора действительно выбраны.

Я использовал журналы, чтобы определить, что правильные данные извлекаются из API и обрабатываются должным образом, поэтому я должен предположить, что адаптер не обновляет представление должным образом.

Почему не отображается первоначально или обновляется, как следует?

FilmFragment.java:

public class FilmFragment extends Fragment { 

private ArrayList<FilmParcelable> filmParcels = new ArrayList<FilmParcelable>(); 

private ImageAdaptor mFilmAdaptor; 

protected String[] sortOptions = { 
     "popularity.desc", 
     "vote_average.desc" 
}; 

protected String sortBy = sortOptions[0]; 

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

public FilmFragment() { 
} 

@Override 
public void onCreate(Bundle savedInstanceState){ 

    super.onCreate(savedInstanceState); 

    if (savedInstanceState == null || !savedInstanceState.containsKey("films")){ 
     updateFilms(); 
     mFilmAdaptor = new ImageAdaptor(getActivity(),filmParcels); 
    } else { 
     filmParcels = savedInstanceState.getParcelableArrayList("films"); 
     mFilmAdaptor = new ImageAdaptor(getActivity(),filmParcels); 
    } 
    // allow fragment to handle menu events 
    setHasOptionsMenu(true); 
} 

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

public boolean onOptionsItemSelected(MenuItem item){ 
    //Handle action bar item clicks. 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(); 
    if (id == R.id.action_sort){ 
     showSortDialog(); 
     return true; 
    } 

    return super.onOptionsItemSelected(item); 
} 

@Override 
public void onSaveInstanceState(Bundle outState){ 
    outState.putParcelableArrayList("films", filmParcels); 
    super.onSaveInstanceState(outState); 
} 

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

    View rootView = inflater.inflate(R.layout.fragment_main, container, false); 

    // Find GridView to populate with poster images 
    GridView gridView = (GridView) rootView.findViewById(R.id.gridView); 

    // Set the adaptor of the GridView to my ImageAdaptor 
    gridView.setAdapter(mFilmAdaptor); 
    updateAdaptor(); 

    return rootView; 
} 

// Update movie data in case there is a change in the "sort by" option 
// Or the fragment is started with no saved data 

public void updateFilms(){ 
    new FetchFilmTask().execute(); 
} 

public void updateAdaptor(){ 
    mFilmAdaptor.clear(); 
    mFilmAdaptor.addAll(filmParcels); 
    mFilmAdaptor.notifyDataSetChanged(); 
} 

// Show dialog sort pop up 
public void showSortDialog(){ 
    DialogFragment dialog = new SortDialog(); 
    dialog.setTargetFragment(this, 0); 
    dialog.show(getActivity().getSupportFragmentManager(), "SortDialog"); 
} 

// If a fragment or activity called by this fragment returns to this fragment, 
// Get the information returned via the intent 
public void onActivityResult(int requestCode, int resultCode, Intent data){ 

    if (requestCode == 0){ 
     int mSelected = data.getIntExtra("Selected Option", -1); 
     if (mSelected != -1){ 
      sortBy = sortOptions[mSelected]; 
      updateFilms(); 
      updateAdaptor(); 
     } 
    } 
} 


// Class to get JSON data from The Movie Database API 
public class FetchFilmTask extends AsyncTask<Void, Void, FilmParcelable[]> { 

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

    private final String MOVIE_DB_API_KEY = "e1968ef8ba074d7d5bf07a59de8b2310"; 

    protected FilmParcelable[] doInBackground(Void... params){ 
     // These two need to be declared outside the try/catch 
     // so that they can be closed in the finally block. 
     HttpURLConnection urlConnection = null; 
     BufferedReader reader = null; 

     // Will contain raw JSON response as a string 
     String movieDBStr = null; 

     try { 
      // Construct URL for Movie DB query 
      Uri.Builder builder = new Uri.Builder(); 
      builder.scheme("http") 
        .authority("api.themoviedb.org") 
        .appendPath("3") 
        .appendPath("discover") 
        .appendPath("movie") 
        .appendQueryParameter("api_key", MOVIE_DB_API_KEY) 
        .appendQueryParameter("sort_by", sortBy); 


      String myUrl = builder.build().toString(); 
      Log.d(LOG_TAG, myUrl); 

      URL url = new URL(myUrl); 

      // Create the request to The Movie DB, and open the connection 
      urlConnection = (HttpURLConnection) url.openConnection(); 
      urlConnection.setRequestMethod("GET"); 
      urlConnection.connect(); 

      // Read the input stream into a String 
      InputStream inputStream = urlConnection.getInputStream(); 
      StringBuffer buffer = new StringBuffer(); 

      if (inputStream == null){ 
       return null; 
      } 

      reader = new BufferedReader(new InputStreamReader(inputStream)); 

      String line; 
      while ((line = reader.readLine()) != null) { 
       // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) 
       // But it does make debugging a *lot* easier if you print out the completed 
       // buffer for debugging. 
       buffer.append(line + "\n"); 
      } 

      if (buffer.length() == 0) { 
       return null; 
      } 
      movieDBStr = buffer.toString(); 
     } catch (IOException e){ 
      Log.e(LOG_TAG, "Error: ", e); 
      return null; 
     } finally { 
      if (urlConnection != null){ 
       urlConnection.disconnect(); 
      } 
      if (reader != null){ 
       try{ 
        reader.close(); 
       } catch (final IOException e){ 
        Log.e(LOG_TAG, "Error closing stream", e); 
       } 
      } 
     } 
     try { 
      return getFilmDataFromJson(movieDBStr); 
     } catch (JSONException e){ 
      Log.e(LOG_TAG, e.getMessage(), e); 
      e.printStackTrace(); 
     } 

     return null; 
    } 

    /** 
    * Take the String representing the complete forecast in JSON Format and 
    * pull out the data we need to construct the Strings needed for the wireframes. 
    * 
    * Fortunately parsing is easy: constructor takes the JSON string and converts it 
    * into an Object hierarchy for us. 
    */ 
    private FilmParcelable[] getFilmDataFromJson(String movieDBStr) 
     throws JSONException { 

     // JSON objects that need to be extracted 
     final String MDB_RESULTS = "results"; 
     final String MDB_ID = "id"; 
     final String MDB_SYNOPSIS = "overview"; 
     final String MDB_RELEASE = "release_date"; 
     final String MDB_POSTER = "poster_path"; 
     final String MDB_TITLE = "title"; 
     final String MDB_RATING = "vote_average"; 

     JSONObject filmJson = new JSONObject(movieDBStr); 
     JSONArray filmArray = filmJson.getJSONArray(MDB_RESULTS); 

     FilmParcelable[] resultFilms = new FilmParcelable[filmArray.length()]; 
     for (int i = 0; i < filmArray.length(); i++){ 
      // Data needed by the FilmParcelable 
      int id; 
      String title; 
      String releaseDate; 
      String posterUrl; 
      Double voteAverage; 
      String plotSynopsis; 

      JSONObject film = filmArray.getJSONObject(i); 

      id = film.getInt(MDB_ID); 
      plotSynopsis = film.getString(MDB_SYNOPSIS); 
      releaseDate = film.getString(MDB_RELEASE); 
      posterUrl = "http://image.tmdb.org/t/p/w300" + film.getString(MDB_POSTER); 
      title = film.getString(MDB_TITLE); 
      voteAverage = film.getDouble(MDB_RATING); 
      Log.d(LOG_TAG, title); 
      Log.d(LOG_TAG, posterUrl); 

      resultFilms[i] = new FilmParcelable(id, title, releaseDate, posterUrl, voteAverage, plotSynopsis); 
     } 

     return resultFilms; 
    } 

    @Override 
    protected void onPostExecute(FilmParcelable[] result){ 
     if (result != null){ 
      filmParcels = new ArrayList<>(Arrays.asList(result)); 
     } 
    } 

} 

}

ImageAdaptor.java:

public class ImageAdaptor extends ArrayAdapter<FilmParcelable> { 

public ImageAdaptor(Activity context, ArrayList<FilmParcelable> filmParcels){ 
    super(context, 0, filmParcels); 
} 

public View getView(int position, View convertView, ViewGroup parent){ 

    Context context= getContext(); 
    View gridView; 

    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

    String mUrl = getItem(position).getUrl(); 

    if (convertView == null) { 

     gridView = inflater.inflate(R.layout.gridview_film_layout, parent, false); 

     // Find the image view from the gridview_film_layout 
     ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image); 

     // Set the image view to contain image located at mUrl 
     Picasso.with(getContext()).load(mUrl).into(posterView); 
    } else { 
     gridView = convertView; 
    } 

    return gridView; 
} 

}

ответ

1

соответственно код, который вы публикуемую вы возвращаетесь снова и снова то же самое ячейки вашего GridView. Вы должны иметь эти две линии

ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image); 
Picasso.with(getContext()).load(mUrl).into(posterView); 

из если/еще настороже:

if (convertView == null) { 
    // inflate 
} else { 
    // gridView = convertView; 
} 

    ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image); 
    Picasso.with(getContext()).load(mUrl).into(posterView); 
    return gridView; 
+0

Приложение загружает сетку 2x10, где каждый вид является соответствующим плакатом, если изображение, если фильмы отсортированы по популярности, у меня есть не только одна ячейка, как вы описали. – David

+0

Помещение этого кода за пределы оператора if просто заставляет gridview непрерывно перезагружать изображения в ячейки, которые он уже создал. Попытка этого сильно замедлила мое приложение, но кроме того ничего не изменило. – David

+0

Вы были частично правы. Как я обработал обновление адаптера, вызвал обновление адаптера до того, как данные были полностью загружены в фоновом режиме. – David

0

Я пытающиеся обновить адаптер после заполнения ArrayList используется для адаптера. Однако ArrayList была заселена и обновляться в фоновом режиме, поэтому код:

updateFilms(); 
updateAdaptor(); 

причинял адаптер для обновления до того, как данные были завершения загрузки в фоновом режиме.

После того, как было установлено, что решение Blackbelt было правильным.