上一篇文章主要讲解了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和了解了项目结构就能看懂源码中的这部分,下一篇文章将会讲解数据的缓存,包括字符串和图片两种格式,缓存是这个项目的难点,项目中很大一部分代码都与缓存有关,看懂了缓存就把整个项目都看懂了,还等什么,赶紧开始下一篇的阅读吧。