我的应用上的第一个活动显示了一些热门电影的缩略图。我从The Movie DB API中提取这些数据。我能够下载图像URL和其他细节。但是,我无法在我的应用程序上的GridView上显示图像。我正在尝试编写一个自定义ImageAdapter类来使用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获取数据的类:
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类中删除了notifyDataSetChanged(),并通过对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;
}
}
虽然这会在UI上显示图像,但显示图像需要很长时间。在我看到任何图片之前大约需要20秒,有时它甚至没有显示图片,尽管我可以在日志中看到图片URL正在被正确获取。我的网络速度不慢,日志几乎立即显示网址。这是正常的吗?
答案 0 :(得分:1)
在异步任务的onPostExecute中创建并设置适配器/数据
答案 1 :(得分:1)
在getView()中删除notifyDataSetChanged()并将populater.notifyDataSetChanged()添加到onPostExecute的末尾。
如果不起作用。
移动
populater = new ImageAdapter(inflater,R.layout.image_view_poster,R.id.one_poster,posterURLs);
gridview.setAdapter(populater);
结束onPostExecute。