在上一篇文章《安卓开发笔记——打造属于自己的博客园APP(一)》中,我们基本上实现了博客园的主体UI框架(后面可能会有些小变化,等遇到了再说)。今天来讲讲博客园首页模块的大体实现,国际惯例,先来看下效果图:
整体UI效果:
下拉刷新和上拉加载的动画效果:
在上篇文章中,我们定义的Tabs主题文字分别是(首页,精华,候选,推荐),这边的命名我是根据博客园网站首页的栏目来命名的,那时候我还没仔细看过博客园的开放接口,后来才发现原来博客园没有对应开放这些栏目的接口,博客园只开放了(文章列表,48小时阅读排行,10天内推荐排行,推荐博客列表)等接口,所以我对应的在Tabs标签主题上改动了下文字。由于是随性开发,没有做过多的前期准备,嘿嘿O(∩_∩)O~
PS:其实不按照接口来也是可以的,我们可以采用数据采集的方式来获取数据,有兴趣的朋友可以看看我之前写的一些列关于JAVA采集数据的文章:
《基于Java数据采集入库(一)》:http://www.cnblogs.com/lichenwei/p/3904715.html
《基于Java数据采集入库(二)》:http://www.cnblogs.com/lichenwei/p/3905370.html
《基于Java数据采集入库(三)》:http://www.cnblogs.com/lichenwei/p/3907007.html
《基于Java的数据采集(终结篇)》:http://www.cnblogs.com/lichenwei/p/3910492.html
现在已经实现的效果:主UI效果的基本搭建,网络框架的搭建,各博客列表页面的展示包括更新效果,对图片做了三级缓存处理(后面会把文章,新闻做成离线闪存,实现无网络也能照常浏览)等,功能还有很多,慢慢去实现,然后对各细节的优化也会慢慢迭代去完成。
好了,进入主题,由于文章篇幅问题,我这里只会对第一个页面进行讲解,其他大同小异了。
1、解析XML数据
这里是博客园对博客内容的开放接口:http://wcf.open.cnblogs.com/blog/help
很无奈的发现,博客园的接口是用XML编写的,需要我们去解析XML,挺麻烦的,如果是Json不管在效率上或是我们代码编写上都会来得方便许多。
下面是对首页博文列表:http://wcf.open.cnblogs.com/blog/help/operations/GetSitHomeRecentPagedPosts的XML解析代码
其中第一个参数PAGEINDEX代表页数(默认1),第二个参数PAGESIZE代表每页显示的文章条数(默认20)
1 package com.lcw.rabbit.myblog.parser; 2 3 import com.lcw.rabbit.myblog.entity.Blog; 4 5 import org.xmlpull.v1.XmlPullParser; 6 import org.xmlpull.v1.XmlPullParserException; 7 import org.xmlpull.v1.XmlPullParserFactory; 8 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.util.ArrayList; 12 import java.util.List; 13 14 /** 15 * 对博客列表xml数据的解析 16 * Created by Lichenwei 17 * Date: 2015-08-17 18 * Time: 13:32 19 */ 20 public class BlogsListXmlParser { 21 22 23 /** 24 * 用于解析博客列表的xml,返回Blog的List集合对象 25 * 26 * @param inputStream 27 * @param encode 28 * @return 29 * @throws XmlPullParserException 30 * @throws IOException 31 */ 32 public static List<Blog> getListBlogs(InputStream inputStream, String encode) throws XmlPullParserException, IOException { 33 34 List<Blog> mBlogs = null; 35 Blog mBlog = null; 36 37 //获取XmlPullParser实例 38 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 39 XmlPullParser parser = factory.newPullParser(); 40 parser.setInput(inputStream, encode); 41 //获取解析事件 42 int eventType = parser.getEventType(); 43 //当xml文档未到尾端时 44 while (eventType != XmlPullParser.END_DOCUMENT) { 45 switch (eventType) { 46 //解析根标签的时候,实例化集合 47 case XmlPullParser.START_DOCUMENT: 48 mBlogs = new ArrayList<Blog>(); 49 mBlog = new Blog(); 50 51 break; 52 case XmlPullParser.START_TAG: 53 //当解析到entry标签的时候,实例化Blog对象 54 if ("entry".equals(parser.getName())) { 55 mBlog = new Blog(); 56 } 57 if ("id".equals(parser.getName())) { 58 parser.next(); 59 mBlog.setBlogId(parser.getText()); 60 } else if ("title".equals(parser.getName())) { 61 parser.next(); 62 //特殊处理 63 if (!"博客园".equals(parser.getText())) { 64 mBlog.setBlogTitle(parser.getText()); 65 } 66 } else if ("summary".equals(parser.getName())) { 67 parser.next(); 68 mBlog.setBlogSummary(parser.getText()); 69 } else if ("published".equals(parser.getName())) { 70 parser.next(); 71 mBlog.setBlogPublished(parser.getText()); 72 } else if ("name".equals(parser.getName())) { 73 parser.next(); 74 mBlog.setAuthorName(parser.getText()); 75 } else if ("uri".equals(parser.getName())) { 76 parser.next(); 77 mBlog.setAuthorUri(parser.getText()); 78 } else if ("avatar".equals(parser.getName())) { 79 parser.next(); 80 mBlog.setAuthorAvatar(parser.getText()); 81 } else if ("link".equals(parser.getName())) { 82 //特殊处理 83 if (parser.getAttributeName(0).equals("rel")) { 84 mBlog.setBlogLink(parser.getAttributeValue(1)); 85 } 86 } else if ("diggs".equals(parser.getName())) { 87 parser.next(); 88 mBlog.setBlogDiggs(parser.getText()); 89 } else if ("views".equals(parser.getName())) { 90 parser.next(); 91 mBlog.setBlogViews(parser.getText()); 92 } else if ("comments".equals(parser.getName())) { 93 parser.next(); 94 mBlog.setBlogComments(parser.getText()); 95 } 96 break; 97 case XmlPullParser.END_TAG: 98 //当解析到entry标签结束的时候添加入Blogs集合,清空Blog对象 99 if ("entry".equals(parser.getName())) { 100 mBlogs.add(mBlog); 101 mBlog = null; 102 } 103 break; 104 105 } 106 //手动跳转第一次遍历 107 eventType = parser.next(); 108 } 109 110 111 return mBlogs; 112 113 } 114 115 }
在JAVA中解析XML一般有三种方式(SAX,DOM,PULL),上面代码采用的是最后一种PULL方式的解析,前面两种SAX,DOM一般用于JAVAEE里,PULL方式的解析相对前两者来得比较轻量,安卓内部对XML的解析也是采用的PULL,所以没必要引入新的JAR包,关于这三种方式的解析,这里就不再多说了,不是今天的重点。(PS:之前一直做的是Json解析,XML解析几乎没用过,可能大家有更好的更有效率的解析方式,如果有可以在文章评论里帮我指点下迷津)。
好了,上面的代码已经对XML解析封装完成,我们只需要传入一个输入流和编码格式,就可以把我们想要的数据装在到List集合了。
这里是List集合里的实体类:
1 package com.lcw.rabbit.myblog.entity; 2 3 /** 4 * 博客实体类 5 * Created by Lichenwei 6 * Date: 2015-08-17 7 * Time: 13:34 8 */ 9 public class Blog { 10 //文章id 11 private String blogId; 12 //文章标题 13 private String blogTitle; 14 //文章概要 15 private String blogSummary; 16 //更新时间 17 private String blogPublished; 18 //博主昵称 19 private String authorName; 20 //博主头像地址 21 private String authorAvatar; 22 //博主博客地址 23 private String authorUri; 24 //博文链接 25 private String blogLink; 26 //博文评论数 27 private String blogComments; 28 //博文浏览数 29 private String blogViews; 30 //博文推荐数 31 private String blogDiggs; 32 33 public Blog() { 34 } 35 36 public Blog(String blogId, String blogTitle, String blogSummary, String blogPublished, String authorName, String authorAvatar, String authorUri, String blogLink, String blogComments, String blogViews, String blogDiggs) { 37 this.blogId = blogId; 38 this.blogTitle = blogTitle; 39 this.blogSummary = blogSummary; 40 this.blogPublished = blogPublished; 41 this.authorName = authorName; 42 this.authorAvatar = authorAvatar; 43 this.authorUri = authorUri; 44 this.blogLink = blogLink; 45 this.blogComments = blogComments; 46 this.blogViews = blogViews; 47 this.blogDiggs = blogDiggs; 48 } 49 50 public String getBlogId() { 51 return blogId; 52 } 53 54 public void setBlogId(String blogId) { 55 this.blogId = blogId; 56 } 57 58 public String getBlogTitle() { 59 return blogTitle; 60 } 61 62 public void setBlogTitle(String blogTitle) { 63 this.blogTitle = blogTitle; 64 } 65 66 public String getBlogSummary() { 67 return blogSummary; 68 } 69 70 public void setBlogSummary(String blogSummary) { 71 this.blogSummary = blogSummary; 72 } 73 74 public String getBlogPublished() { 75 return blogPublished; 76 } 77 78 public void setBlogPublished(String blogPublished) { 79 this.blogPublished = blogPublished; 80 } 81 82 public String getAuthorName() { 83 return authorName; 84 } 85 86 public void setAuthorName(String authorName) { 87 this.authorName = authorName; 88 } 89 90 public String getAuthorAvatar() { 91 return authorAvatar; 92 } 93 94 public void setAuthorAvatar(String authorAvatar) { 95 this.authorAvatar = authorAvatar; 96 } 97 98 public String getAuthorUri() { 99 return authorUri; 100 } 101 102 public void setAuthorUri(String authorUri) { 103 this.authorUri = authorUri; 104 } 105 106 public String getBlogLink() { 107 return blogLink; 108 } 109 110 public void setBlogLink(String blogLink) { 111 this.blogLink = blogLink; 112 } 113 114 public String getBlogComments() { 115 return blogComments; 116 } 117 118 public void setBlogComments(String blogComments) { 119 this.blogComments = blogComments; 120 } 121 122 public String getBlogViews() { 123 return blogViews; 124 } 125 126 public void setBlogViews(String blogViews) { 127 this.blogViews = blogViews; 128 } 129 130 public String getBlogDiggs() { 131 return blogDiggs; 132 } 133 134 public void setBlogDiggs(String blogDiggs) { 135 this.blogDiggs = blogDiggs; 136 } 137 138 @Override 139 public String toString() { 140 return "Blog{" + 141 "blogId='" + blogId + '\'' + 142 ", blogTitle='" + blogTitle + '\'' + 143 ", blogSummary='" + blogSummary + '\'' + 144 ", blogPublished='" + blogPublished + '\'' + 145 ", authorName='" + authorName + '\'' + 146 ", authorAvatar='" + authorAvatar + '\'' + 147 ", authorUri='" + authorUri + '\'' + 148 ", blogLink='" + blogLink + '\'' + 149 ", blogComments='" + blogComments + '\'' + 150 ", blogViews='" + blogViews + '\'' + 151 ", blogDiggs='" + blogDiggs + '\'' + 152 '}'; 153 } 154 }