开源项目9GAG源码解析与Material改造(二)

上一篇文章主要讲解了9GAG中的UI部分,这篇文章主要讲解客户端与服务器的数据交换。项目中的数据交换主要使用了Volley这个开源项目,关于Volley的讲解可以查看我之前写的博客,除了Volley以外,还使用了Universal-Image-Loader 进行图片的加载。

数据交换流程

整个数据交换的流程很简单,根据指定的API从服务器获得关于图片的数据,把数据存入数据库,图片做缓存,展示的时候先从数据库和缓存里找,没有的话再去服务器GET。

返回数据类型

字符

向服务器请求的地址
下面是返回的数据:

{
data: [
{
id: "a8jx9z6",
from: {
name: ""
},
caption: "When I changed my wifi password but somehow my neigbours still connect",
images: {
small: "",
normal: "http://img-9gag-fun.9cache.com/photo/a8jx9z6_460s.jpg",
large: "http://img-9gag-fun.9cache.com/photo/a8jx9z6_700b.jpg"
},
link: "http://9gag.com/gag/a8jx9z6",
actions: {
like: "http://9gag.com/vote/like/id/a8jx9z6",
dislike: "http://9gag.com/vote/dislike/id/a8jx9z6",
unlike: "http://9gag.com/vote/unlike/id/a8jx9z6"
},
votes: {
count: 13988
}
},
{
id: "aojvm3x",
from: {
name: ""
},
caption: "Showing computer to your crush",
images: {
small: "",
normal: "http://img-9gag-fun.9cache.com/photo/aRVbAV5_460s.jpg",
large: "http://img-9gag-fun.9cache.com/photo/aRVbAV5_700b.jpg"
},
link: "http://9gag.com/gag/aRVbAV5",
actions: {
like: "http://9gag.com/vote/like/id/aRVbAV5",
dislike: "http://9gag.com/vote/dislike/id/aRVbAV5",
unlike: "http://9gag.com/vote/unlike/id/aRVbAV5"
},
votes: {
count: 14551
}
},
{
id: "aAp8PwL",
from: {
name: ""
},
...
...
...
caption: "All I will probably love the new one as well. Don't understand all the hate.",
images: {
small: "",
normal: "http://img-9gag-fun.9cache.com/photo/avLKjy5_460s.jpg",
large: "http://img-9gag-fun.9cache.com/photo/avLKjy5_700b.jpg"
},
link: "http://9gag.com/gag/avLKjy5",
actions: {
like: "http://9gag.com/vote/like/id/avLKjy5",
dislike: "http://9gag.com/vote/dislike/id/avLKjy5",
unlike: "http://9gag.com/vote/unlike/id/avLKjy5"
},
votes: {
count: 12675
}
}
],
paging: {
next: "avLKjy5"
}
}

JSON封装

通过对服务器返回的数据分析得到每此返回的是一个JSON的字串,这个字串中包含了若干个图片的信息和最后一个paging的数据。再分析每个图片的信息可以发现,每个图片包含caption,images,votes等部分,其中image和votes又包含子信息。根据返回的数据和我们的需求设计出如下的Feed类

public class Feed extends BaseModel {
    private static final HashMap<String, Feed> CACHE = new HashMap<String, Feed>();

    private String id;
    private String caption;
    private String link;
    private Image images;
    private Vote votes;

    public class Image {
        public String small;
        public String normal;
        public String large;
    }

    private class Vote {
        public int count;
    }

    public static class FeedRequestData {
        public ArrayList<Feed> data;
        public Paging paging;

        public String getPage() {
            return paging.next;
        }
    }

    private class Paging {
        public String next;
    }
    ...
    ...
    }

同个这个类,每次请求的数据都可以封装在一个FeedRequestData对象中,这样操作起来比单独解析每一个Feed会方便很多。

请求数据

 private void loadData(String next) {
        //request data from Internet
        RequestManager.INSTANCE.getRequestQueue().add(new GsonRequest<>(String.format(GagApi.LIST, "hot", next),
                Feed.FeedRequestData.class, null, new Response.Listener<Feed.FeedRequestData>() {
            final boolean isRefreshFromTop = ("0".equals(page));

            @Override
            public void onResponse(final Feed.FeedRequestData response) {
                TaskUtil.executeAsyncTask(new AsyncTask<Object, Void, Void>() {
                                              @Override
                                              protected Void doInBackground(Object... params) {
                                                  if (isRefreshFromTop) {
                                                      feedsDataHelper.deleteAll();
                                                  }
                                                  page = response.getPage();
                                                  ArrayList<Feed> feeds = response.data;

                                                  //write to db
                                                  feedsDataHelper.bulkInsert(feeds);
                                                  return null;
                                              }

                                              @Override
                                              protected void onPostExecute(Void aVoid) {
                                                  super.onPostExecute(aVoid);
                                                  swipeLayout.setRefreshing(false);
                                                  PageListView.isLoading = false;
                                              }
                                          }
                );
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Log.e("FeedFragment","VolleyError" + volleyError.toString());
                swipeLayout.setRefreshing(false);
            }
        }));
    }

自定义了一个Gson Request用来解析Gson,注意下面两句

 page = response.getPage();
 ArrayList<Feed> feeds = response.data;

page对应的是JSON字串中的paging,而ArrayList feeds就是所有的图片信息,虽然只是一个对象但却包含了所有的图片信息,是不是很方便~

图片

关于图片的加载是在CursorAdapter的bindView()里完成的,利用的是Volley的图片加载技术,具体请参考这个文章:使用Volley加载图片

 mDefaultImageDrawable = new ColorDrawable(mResource.getColor(COLORS[cursor.getPosition() % COLORS.length]));
        holder.imageRequest = ImageCacheManager.loadImage(feed.images.normal, ImageCacheManager
                .getImageListener(holder.image, mDefaultImageDrawable, mDefaultImageDrawable), 0, DensityUtils.dip2px(context, IMAGE_MAX_HEIGHT));

上面还涉及了ImageCacheManager这个类,这个类主要负责图片加载和缓存的相关设置。
当然了,这里也可以使用Universal-Image-Loader来加载图片(其实我感觉使用这个更简洁一些…)

总结

本文讲解了9GAG中的网络数据交换的部分,主要是字符和图片两种类型的数据传输和Feed的结构设计,总体来说并不是很难,只要熟悉了Volley和了解了项目结构就能看懂源码中的这部分,下一篇文章将会讲解数据的缓存,包括字符串和图片两种格式,缓存是这个项目的难点,项目中很大一部分代码都与缓存有关,看懂了缓存就把整个项目都看懂了,还等什么,赶紧开始下一篇的阅读吧。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值