android - 无法在 GridView 上显示图像

标签 android gridview android-adapter picasso

我的应用程序上的第一个 Activity 显示了一些热门电影的缩略图。我正在从 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

如您所见,即使 ImageAdapter 中有 Log.v 消息,也没有打印任何日志。我是 Android 新手,无法弄清楚发生了什么。有人请帮帮我!

谢谢!

编辑:

大家好,

感谢您的所有回答。我从 ImageAdapter 类中删除了 notificationDataSetChanged() 并通过对 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 已正确获取。我的网络并不慢,日志几乎立即显示 URL。这正常吗?

最佳答案

删除 getView() 中的 notificationDataSetChanged() 并将 populator.notifyDataSetChanged() 添加到 onPostExecute 末尾。

如果不起作用。

移动

populater = new ImageAdapter(inflater,R.layout.image_view_poster,R.id.one_poster,posterURLs);
gridview.setAdapter(populater); 

到 onPostExecute 结束。

关于android - 无法在 GridView 上显示图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34793105/

相关文章:

android - 如果上下文不是 Activity 上下文而是应用程序上下文,如何启动 Intent

java - While 循环和黑屏

java - 带 TextChangedListener 的 RetroLambda

java - 如何使 ImageView 的高度成为图像的高度?安卓

java - TextDrawable - 根据键(电子邮件、id)显示颜色

Android:ProgressDialog 未显示在适配器类中

android - 单击搜索图标时如何在工具栏中使用 SearchView

c# - 返回单元格与字符串相似的行号

asp.net - 模式弹出窗口关闭后刷新更新面板内的 gridview

javascript - javascript中计算错误