无法在 GridView 上显示图像
Unable to display images on a GridView
我的应用程序中的第一个 activity 显示了一些热门电影的缩略图。我正在从 The Movie DB API 中提取这些数据。我可以很好地下载图像 URL 和其他详细信息。但是,我无法在我的应用程序的 GridView 上显示图像。我正在尝试编写自定义 ImageAdapter class 以使用 Picasso 库显示图像。这是它的代码。被注释掉的部分是我尝试过但失败的部分:
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 获取数据的 class:
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: android.os.BinderProxy@3d81b4d8 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
如您所见,尽管我在那里有 Log.v 消息,但 ImageAdapter 没有打印任何日志。我是 android 的新手,无法弄清楚发生了什么。有人,请帮助我!
谢谢!
编辑:
大家好,
感谢您的所有回答。我从 ImageAdapter class 中删除了 notifyDataSetChanged() 并通过对 ImageAdapter class 进行以下更改解决了问题:
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;
}
}
虽然这显示了 UI 上的图像,但需要很长时间才能显示图像。我大约需要 20 秒才能看到任何图片,有时它甚至不显示图片,尽管我可以在日志中看到图片 URL 被正确获取。我的网络并不慢,日志几乎立即显示了 URL。这正常吗?
在异步任务的 onPostExecute 中创建并设置 adapter/data
删除 getView() 中的 notifyDataSetChanged() 并将 populater.notifyDataSetChanged() 添加到 onPostExecute 的末尾。
如果不行。
移动
populater = new ImageAdapter(inflater,R.layout.image_view_poster,R.id.one_poster,posterURLs);
gridview.setAdapter(populater);
onPostExecute 结束。
我的应用程序中的第一个 activity 显示了一些热门电影的缩略图。我正在从 The Movie DB API 中提取这些数据。我可以很好地下载图像 URL 和其他详细信息。但是,我无法在我的应用程序的 GridView 上显示图像。我正在尝试编写自定义 ImageAdapter class 以使用 Picasso 库显示图像。这是它的代码。被注释掉的部分是我尝试过但失败的部分:
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 获取数据的 class:
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: android.os.BinderProxy@3d81b4d8 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
如您所见,尽管我在那里有 Log.v 消息,但 ImageAdapter 没有打印任何日志。我是 android 的新手,无法弄清楚发生了什么。有人,请帮助我!
谢谢!
编辑:
大家好,
感谢您的所有回答。我从 ImageAdapter class 中删除了 notifyDataSetChanged() 并通过对 ImageAdapter class 进行以下更改解决了问题:
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;
}
}
虽然这显示了 UI 上的图像,但需要很长时间才能显示图像。我大约需要 20 秒才能看到任何图片,有时它甚至不显示图片,尽管我可以在日志中看到图片 URL 被正确获取。我的网络并不慢,日志几乎立即显示了 URL。这正常吗?
在异步任务的 onPostExecute 中创建并设置 adapter/data
删除 getView() 中的 notifyDataSetChanged() 并将 populater.notifyDataSetChanged() 添加到 onPostExecute 的末尾。
如果不行。
移动
populater = new ImageAdapter(inflater,R.layout.image_view_poster,R.id.one_poster,posterURLs);
gridview.setAdapter(populater);
onPostExecute 结束。