Первое действие в моем приложении показывает миниатюры некоторых популярных фильмов. Я извлекаю эти данные из API DB DB. Я могу загружать URL-адреса изображений и другие подробности в порядке. Однако я не могу отображать изображения в GridView в своем приложении. Я пытаюсь написать собственный класс ImageAdapter для отображения изображений с использованием библиотеки Picasso. Вот код для этого. Разделы, которые были закомментированы являются те, которые я пытался и не:Невозможно отобразить изображения на GridView
public class ImageAdapter extends BaseAdapter {
private LayoutInflater inflater;
private int mLayout;
private int mId;
private List<?> mImageList = new ArrayList<>();
public ImageAdapter(LayoutInflater i, int layout, int id, List<?> images) {
inflater = i;
mLayout = layout;
mId = id;
mImageList = images;
}
public int getCount() {
return mImageList.size();
}
public Object getItem(int position) {
return mImageList.get(position);
}
public long getItemId(int position) {
return position;
}
//TODO check errors in the section below.
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
/*View view;
ImageView imageView;
if (convertView == null) {
view = inflater.inflate(mLayout, parent, false);
} else {
view = convertView;
}
try {
if (mId == 0) {
// If no custom field is assigned, assume the whole resource is an ImageView.
imageView = (ImageView) view;
} else {
// Otherwise, find the ImageView field within the layout
imageView = (ImageView) view.findViewById(mId);
}
} catch (ClassCastException e) {
Log.e("ImageAdapter", "You must supply a resource ID for an ImageView");
throw new IllegalStateException(
"ImageAdapter requires the resource ID to be an ImageView", e);
}
Log.v("ImageAdapter", "Inside ImageAdapter.");
Log.v("ImageAdapter",mImageList.get(position).toString());
Picasso.with(inflater.getContext()).load(mImageList.get(position).toString()).into(imageView);
/* Uri uri = Uri.parse(mImageList.get(position).toString());
imageView.setImageURI(uri);*/
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(inflater.getContext());
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
Log.v("ImageAdapter",mImageList.get(position).toString());
notifyDataSetChanged();
Picasso.with(inflater.getContext()).load(mImageList.get(position).toString()).into(imageView);
return imageView;
/*if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = (ImageView) convertView.findViewById(mId);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}*/
//return imageView;
}
}
А вот класс, где я получаю данные из API:
public class MainActivityFragment extends Fragment {
List<Uri> posterURLs = new ArrayList<Uri>();
ImageAdapter populater;
String[] title, overview, popularity, rating, releaseDate;
public MainActivityFragment() {
}
@Override
public void onStart() {
super.onStart();
FetchMovieData data = new FetchMovieData();
data.execute();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
GridView gridview = (GridView) rootView.findViewById(R.id.gridview);
populater = new ImageAdapter(inflater,R.layout.image_view_poster,R.id.one_poster,posterURLs);//TODO handle this in ImageAdapter
gridview.setAdapter(populater);
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(getActivity(), "" + position,
Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
public class FetchMovieData extends AsyncTask<Void, Void, String[]> {
//This is used so that if the name of this class is ever changed, the LOG_TAG will
//change accordingly to reflect that. This way, we don't hardcode the name of the
//class in the Log messages.
private final String LOG_TAG = FetchMovieData.class.getSimpleName();
/**
* Prepare image URL for presentation.
*/
private String formatURL(String relativeURL) {
String imageBaseURL = "http://image.tmdb.org/t/p/";
String size = "w185";
relativeURL = relativeURL.substring(1);
Uri uri = Uri.parse(imageBaseURL).buildUpon()
.appendPath(size)
.appendPath(relativeURL).build();
return uri.toString();
}
/**
* Take the String representing the complete JSON data and
* pull out the data we need to construct the Strings needed for the wireframes.
*/
private String[] getMovieDataFromJson(String movieJsonStr)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String RESULT_LIST = "results";
final String TITLE = "original_title";
final String POSTER_URL = "poster_path";
final String OVERVIEW = "overview";
final String POPULARITY = "popularity";
final String RATING = "vote_average";
final String RELEASE_DATE = "release_date";
JSONObject allMovieData = new JSONObject(movieJsonStr);
JSONArray resultsArray = allMovieData.getJSONArray(RESULT_LIST);
String[] posterPaths = new String[resultsArray.length()];
title = new String[resultsArray.length()];
overview = new String[resultsArray.length()];
popularity = new String[resultsArray.length()];
rating = new String[resultsArray.length()];
releaseDate = new String[resultsArray.length()];
for(int i = 0; i < resultsArray.length(); i++) {
// Get the JSON object representing one movie's details
JSONObject eachMovie = resultsArray.getJSONObject(i);
title[i] = eachMovie.getString(TITLE);
String relativeURL = eachMovie.getString(POSTER_URL);
posterPaths[i] = formatURL(relativeURL);
overview[i] = eachMovie.getString(OVERVIEW);
popularity[i] = eachMovie.getString(POPULARITY);
rating[i] = eachMovie.getString(RATING);
releaseDate[i] = eachMovie.getString(RELEASE_DATE);
Log.v("poster path", posterPaths[i]);
}
return posterPaths;
}
@Override
protected String[] doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//For building the URL for the weather query from OpenWeatherMap
final String BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
final String SORT_PARAM = "sort_by";
final String API_PARAM = "api_key";
String sort_by = "popularity.desc",
apiKey = "";
// Will contain the raw JSON response as a string.
String movieJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are available at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
Uri queryUri = Uri.parse(BASE_URL).buildUpon()
//.appendQueryParameter(SORT_PARAM,params[0])
.appendQueryParameter(SORT_PARAM, sort_by)
.appendQueryParameter(API_PARAM,apiKey).build();
URL queryUrl = new URL(queryUri.toString());
// Create the request to TheMovieDB, and open the connection
urlConnection = (HttpURLConnection) queryUrl.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
Log.v(LOG_TAG, "Couldn't open input stream.");
// Nothing to do.
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) {
Log.v(LOG_TAG, "Input stream was empty.");
// Stream was empty. No point in parsing.
return null;
}
//if all's well, parse the required data and return it to the system
//(which then calls the onPostExecute() method with this data).
movieJsonStr = buffer.toString();
Log.v(LOG_TAG,movieJsonStr);
return getMovieDataFromJson(movieJsonStr);
//return getWeatherDataFromJson(forecastJsonStr, numDays);
} catch (IOException e) {
Log.e(LOG_TAG, "Error: Couldn't get movie data. ", e);
// If the code didn't successfully get the weather data, there's no point in attempting
// to parse it.
return null;
} catch (JSONException e) {
Log.e(LOG_TAG, "Error in parsing: ", e);
//If there is an error in parsing the JSON data, there's nothing to display.
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);
}
}
}
}
@Override
protected void onPostExecute(String[] strings) {
super.onPostExecute(strings);
for (int i=0; i<strings.length;i++){
Uri uri = Uri.parse(strings[i]);
posterURLs.add(uri);
}
}
}
}
И вот войти в LogCat с момента, когда приложение запускает:
01-14 20:23:46.338 1176-1176/com.example.ishita.popularmovies I/Timeline: Timeline: Activity_idle id: [email protected] time:321945330
01-14 20:23:46.876 1176-2146/com.example.ishita.popularmovies V/FetchMovieData: {"page":1,"results":[{"poster_path":"\/fYzpM9GmpBlIC893fNjoWCwE24H.jpg","adult":false,"overview":"Thirty years after defeating the Galactic Empire, Han Solo and his allies face a new threat from the evil Kylo Ren and his army of Stormtroopers.","release_date":"2015-12-18","genre_ids":[28,12,878,14],"id":140607,"original_title":"Star Wars: The Force Awakens","original_language":"en","title":"Star Wars: The Force Awakens","backdrop_path":"\/njv65RTipNSTozFLuF85jL0bcQe.jpg","popularity":87.856903,"vote_count":2172,"video":false,"vote_average":7.92},{"poster_path":"\/oXUWEc5i3wYyFnL1Ycu8ppxxPvs.jpg","adult":false,"overview":"In the 1820s, a frontiersman, Hugh Glass, sets out on a path of vengeance against those who left him for dead after a bear mauling.","release_date":"2015-12-25","genre_ids":[37,18,12,53],"id":281957,"original_title":"The Revenant","original_language":"en","title":"The Revenant","backdrop_path":"\/6vb1S6H3FD6UQCjza78TptPB8GL.jpg","popularity":34.612251,"vote_count":360,"video":false,"vote_average":7.01},{"poster_path":"\/5aGhaIHYuQbqlHWvWYqMCnj40y2.jpg","adult":false,"overview":"During a manned mission to Mars, Astronaut Mark Watney is presumed dead after a fierce storm and left behind by his crew. But Watney has survived and finds himself stranded and alone on the hostile planet. With only meager supplies, he must draw upon his ingenuity, wit and spirit to subsist and find a way to signal to Earth that he is alive.","release_date":"2015-10-02","genre_ids":[18,12,878],"id":286217,"original_title":"The Martian","original_language":"en","title":"The Martian","backdrop_path":"\/sy3e2e4JwdAtd2oZGA2uUilZe8j.jpg","popularity":30.878855,"vote_count":1908,"video":false,"vote_average":7.66},{"poster_path":"\/jjBgi2r5cRt36xF6iNUEhzscEcb.jpg","adult":false,"overview":"Twenty-two years after the events of Jurassic Park, Isla Nublar now features a fully functioning dinosaur theme park, Jurassic World, as originally envisioned by John Hammond.","release_date":"2015-06-12","genre_ids":[28,12,878,53],"id":135397,"original_title":"Jurassic World","original_language":"en","title":"Jurassic World","backdrop_path":"\/dkMD5qlogeRMiEixC4YNPUvax2T.jpg","popularity":25.952499,"vote_count":3532,"video":false,"vote_average":6.76},{"poster_path":"\/kqjL17yufvn9OVLyXYpvtyrFfak.jpg","adult":false,"overview":"An apocalyptic story set in the furthest reaches of our planet, in a stark desert landscape where humanity is broken, and most everyone is crazed fighting for the necessities of life. Within this world exist two rebels on the run who just might be able to restore order. There's Max, a man of action and a man of few words, who seeks peace of mind following the loss of his wife and child in the aftermath of the chaos. And Furiosa, a woman of action and a woman who believes her path to survival may be achieved if she can make it across the desert back to her childhood homeland.","release_date":"2015-05-14","genre_ids":[53,28,12],"id":76341,"original_title":"Mad Max: Fury Road","original_language":"en","title":"Mad Max: Fury Road","backdrop_path":"\/tbhdm8UJAb4ViCTsulYFL3lxMCd.jpg","popularity":22.542466,"vote_count":3268,"video":false,"vote_average":7.52},{"poster_path":"\/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg","adult":false,"overview":"Interstellar chronicles the adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitations on human space travel and conquer the vast distances involved in an interstellar voyage.","release_date":"2014-11-05","genre_ids":[12,18,878],"id":157336,"original_title":"Interstellar","original_language":"en","title":"Interstellar","backdrop_path":"\/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg","popularity":19.138919,"vote_count":4090,"video":false,"vote_average":8.26},{"poster_path":"\/fqe8JxDNO8B8QfOGTdjh6sPCdSC.jpg","adult":false,"overview":"Bounty hunters seek shelter from a raging blizzard and get caught up in a plot of betrayal and deception.","release_date":"2015-12-25","genre_ids":[53,37,18,9648],"id":273248,"original_title":"The Hateful Ei
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/fYzpM9GmpBlIC893fNjoWCwE24H.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/oXUWEc5i3wYyFnL1Ycu8ppxxPvs.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/5aGhaIHYuQbqlHWvWYqMCnj40y2.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/jjBgi2r5cRt36xF6iNUEhzscEcb.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/kqjL17yufvn9OVLyXYpvtyrFfak.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/fqe8JxDNO8B8QfOGTdjh6sPCdSC.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/pEbyD5ZtnhYXbpwJQ8pkaMOzlcB.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/q0R4crx2SehcEEQEkYObktdeFy.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/z2sJd1OvAGZLxgjBdSnQoLCfn3M.jpg
01-14 20:23:46.886 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/5JU9ytZJyR3zmClGmVm9q4Geqbd.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/cWERd8rgbw7bCMZlwP207HUXxym.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/D6e8RJf2qUstnfkTslTXNTUAlT.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/vQ7oVX2j7BnMDYyzuFeG1epqvGb.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/noUp0XOqIcmgefRnRZa1nhtRvWO.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/mSvpKOWbyFtLro9BjfEGqUw5dXE.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/p2SdfGmQRaw8xhFbexlHL7srMM8.jpg
01-14 20:23:46.887 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/y31QB9kn3XSudA15tV7UWQ9XLuW.jpg
01-14 20:23:46.888 1176-2146/com.example.ishita.popularmovies V/poster path: http://image.tmdb.org/t/p/w185/aAmfIX3TT40zUHGcCKrlOZRKC7u.jpg
Как вы можете видеть, нет журнала не печатается из ImageAdapter, даже если у меня есть сообщения Log.v там. Я новичок в Android и не могу понять, что происходит. Кто-нибудь, пожалуйста, помогите мне!
Спасибо!
EDIT:
Привет, Все,
Спасибо за все ваши ответы. Я удалил notifyDataSetChanged() из класса ImageAdapter и решить эту проблему путем внесения следующих изменений в класс ImageAdapter:
public class ImageAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<?> mImageList = new ArrayList<>();
public ImageAdapter(LayoutInflater i, List<?> images) {
inflater = i;
mImageList = images;
}
public int getCount() {
return mImageList.size();
}
public Object getItem(int position) {
return mImageList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, create a new ImageView
imageView = new ImageView(inflater.getContext());
} else {
imageView = (ImageView) convertView;
}
Picasso.with(inflater.getContext()).load(mImageList.get(position).toString()).into(imageView);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageView.setAdjustViewBounds(true);
return imageView;
}
}
Хотя это показывает изображения на пользовательском интерфейсе, это занимает очень много времени, чтобы показать вверх по изображений. Мне нужно около 20 секунд, прежде чем я смогу увидеть какие-либо фотографии вообще, и иногда даже не покажут изображения, хотя я вижу в журналах, что URL-адреса изображений правильно выбраны. Моя сеть не медленная, и журналы показывают URL-адреса почти сразу. Это нормально?
Удалить notifyDataSetChanged(); в getView. –