实现从网上下载大量图片在GridView上显示过程中遇到的一些问题

  图片从Flickr上下载(需要fq才能访问)。
  
  我们先理下思路再开始写代码,首先从Flickr上拿到JSON字符串,然后解析,我们可以用一个类来代表每张图片所包含的信息,这些信息的下载都很快,我们可以用AsyncTask来解决,等要通过url去下载图片的时候,AsyncTask就不合适了,具体原因看我这篇文章:关于Android AsyncTask的一些总结。所以我们现在来单独考虑下图片的下载,首先我们没必要也不应该一次下载所有图片,因为我们只需要及时加载用户当前滑到界面的图片即可,而且一次下载所有图片从时间和内存角度考虑都是不可取的,因此只需要下载当前用户所看到界面的图片即可。具体实现时,我们可以弄个后台线程去下载图片。下面我们来具体看下实现过程。
  
  关于Flickr API的使用这里就不说了,可以去Flickr网站看相关文档。
  
  其中JSON字符串下载及解析的相关主要代码如下:

AsyncTask<Void,Void,List<PhotoItem>> mAsyncTask = new AsyncTask<Void,Void,List<PhotoItem>>() {

    @Override
    protected List<PhotoItem> doInBackground(Void... params) {
        try {
            mData = parseJson(getJsonString());
            return mData;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(List<PhotoItem> data) {
        if (data != null) {
            mGridViewAdapter.setData(data);
            mGridView.setAdapter(mGridViewAdapter);
        }
    }

};

//解析JSON字符串
List<PhotoItem> parseJson(String jsonString) throws JSONException {
    List<PhotoItem> data = new ArrayList<>();


    JSONObject jsonObject = new JSONObject(jsonString);
    JSONObject jsonObject1 = jsonObject.getJSONObject("photos");
    JSONArray jsonArray = jsonObject1.getJSONArray("photo");

    for (int i = 0; i < jsonArray.length(); i++) {
        PhotoItem photoItem = new PhotoItem();
        photoItem.setImageUrl((String) jsonArray.getJSONObject(i).get("url_s"));
        data.add(photoItem);
    }

    return data;
}

//获取JSON字符串
public String getJsonString() throws IOException {

    URL url = new URL("https://api.flickr.com/services/rest/?method=flickr.photos.getRecent" +
            "&api_key=XXX&format=json&nojsoncallback=1" +
            "&extras=url_s");
    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

    try {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        InputStream inputStream = httpURLConnection.getInputStream();

        if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            return null;
        }

        int bytesRead = 0;
        byte[] buffer = new byte[1024];
        while ((bytesRead = inputStream.read(buffer)) > 0) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }
        byteArrayOutputStream.close();
        return new String(byteArrayOutputStream.toByteArray());

    } finally {
        httpURLConnection.disconnect();
    }

}  

  注意URL中的api_key=XXX换成你从Flickr网站上获取的API KRY。
  上面的getJsonString方法主要是将获得的InputStream变成String,parseJson方法就是解析获得的String,并返回解析的结果。
  
  下面我们来看下怎么实现只下载当前用户所看到界面的图片,其实主要代码就下面两段:

//给GridView设置滑动监听
mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
            mGridViewIsIdle = true;
            mGridViewAdapter.notifyDataSetChanged();
        } else {
            mGridViewIsIdle = false;
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
});  
//滑动过程中不产生新的异步下载任务(在getView中做的判断)
if (((MainActivity) mContext).isGridViewIsIdle()) {
    final ViewHolder finalViewHolder = viewHolder;
    mHandlerThreadHandler.post(new Runnable() {
        @Override
        public void run() {
            mMyHandlerThread.downloadImage(
                    mData.get(position).getImageUrl(), finalViewHolder.mImageView);
        }
    });
}  

  上面代码一个就是给GridView设置滑动的监听,一个就是在下载图片前做判断,只有GridView处于静止状态才下载图片。至于为什么要句mGridViewAdapter.notifyDataSetChanged(),是因为我们是在GridView处于idle状态时才设置mGridViewIsIdle = true,而这时并不会调用getView,所以需要mGridViewAdapter.notifyDataSetChanged()去调用下getView。
  
  下面我们再来看下图片错位的问题怎么解决。先看下为什么会发生图片错位,其实问题就出在convertView的复用,在从服务器下载图片的时候,可能某个图片下载的比较慢,这样当用户已经滑过它所处的位置时,它才下载好,因为View的复用,它便被放到了那个原先属于它,现在不属于它的位置,于是出现了图片错位。下面看下怎么解决这个问题。
  首先在getView中:

viewHolder.mImageView.setTag(mData.get(position).getImageUrl());//防止图片错位  

  然后在更新UI时:

//更新UI操作,放回主线程
mMainThreadHandler.post(new Runnable() {
    @Override
    public void run() {
        //防止图片错位
        if (imageView.getTag() == string) {
            imageView.setImageBitmap(bitmap);
        }
    }
});  

  这样就可以有效防止图片错位。
     
  其他的细节问题可以具体看源代码:
  https://github.com/qian135/BlogArticleDemo/tree/master/ImageDownloadOne
  再次友情提示下:注意URL中的api_key=XXX换成你从Flickr网站上获取的API KEY
  
  参考资料:
  《Android编程权威指南》
  《Big.Nerd.Ranch.Guides.Android.Programming.The.Big.Nerd.Ranch.Guide.2nd.Edition》(Android编程权威指南第二版)
  
  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值