分享一个Cnblogs简易APP
最近在学习Android app的开发,俗话说万事开头难,本人也不例外。计算机编程是属于一门要求动手能力和动脑能力都很强的学科,相信很多人都会有这样的经历,看得懂不去用,过不了几天也就忘记了。因而,在学习android开发的时候总想找个项目来实践实践。思来想去也没有找到什么好的点子,索性在此拿cnblogs来开刀。这是一个非常简单的应用,高手请自动飘过;初学者共勉之。
此次的例子包含了客户端和服务器端,具体情况如下。
一、开发环境:
服务器端:采用PHP + Python的方式。
数据来源:采用scrapy进行抓取的数据,见:http://www.cnblogs.com/rwxwsblog/tag/%E7%88%AC%E8%99%AB/。
Json数据:采用ThinkPhp写的简单页面
测试环境:小米4
开发工具:Android Studio、PhpStudy
compileSdkVersion:23
二、功能:
1、最新消息
2、图片轮播
3、收藏
4、查看原文
5、分享
目前只有这几个简单的功能,更多功能会在后续的开发中陆续引入。有什么好建议请给我留言吧。


三、知识点:
1、Navigation Drawer的用法
2、SharedPreferences
3、SQLite
4、AsyncTask的运用
5、主线程UI更新Handler
6、PullToRefresh的运用
7、Volley库的运用
8、轮播图ViewPager等
四、怎么可以少得了代码
1、Handler更新UI主线程,见:Android app主线程UI更新间歇性崩溃的问题
private Handler handlerListView = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = (Bundle) msg.obj;
int refreshType = (int) bundle.get("refreshType");
LinkedList<Article> list = (LinkedList<Article>) bundle.get("article");
for (Article article : list){
if (REFRESH_TYPE_UP == refreshType){
listData.add(article);
}else if (REFRESH_TYPE_DOWN == refreshType){
listData.add(0, article);
}
}
pullToRefreshView.onRefreshComplete();
adapter.notifyDataSetChanged();
}
};
2、PullToRefresh上拉和下拉刷新,更多内容见:Android PullToRefreshListView上拉刷新和下拉刷新
pullToRefreshView = (PullToRefreshListView) rootView.findViewById(R.id.pull_to_refresh_listview);
pullToRefreshView.setMode(PullToRefreshBase.Mode.BOTH);//两端刷新
// pullToRefreshView.setMode(PullToRefreshBase.Mode.PULL_FROM_START);//上拉刷新
// pullToRefreshView.setMode(PullToRefreshBase.Mode.PULL_FROM_END);//下拉刷新
pullToRefreshView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() { @Override
public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {
refreshView.getLoadingLayoutProxy().setRefreshingLabel(getString(R.string.loading));
refreshView.getLoadingLayoutProxy().setPullLabel(getString(R.string.downnloadmore));
refreshView.getLoadingLayoutProxy().setReleaseLabel(getString(R.string.startload));
// refreshView.getLoadingLayoutProxy().setLastUpdatedLabel("最后加载时间:");
if (1 == position) {
getArticleList(1, REFRESH_TYPE_DOWN);
} else if (2 == position) {
new GetDataTask().execute(1, REFRESH_TYPE_DOWN);
}
} @Override
public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
refreshView.getLoadingLayoutProxy().setRefreshingLabel(getString(R.string.loading));
refreshView.getLoadingLayoutProxy().setPullLabel(getString(R.string.uploadmore));
refreshView.getLoadingLayoutProxy().setReleaseLabel(getString(R.string.startload));
// refreshView.getLoadingLayoutProxy().setLastUpdatedLabel("最后加载时间:");
if (1 == position) {
int localPage = (int) (articleDao.getArticleCount(where, whereArgs) / ArticleDao.PAGE_ROW);
if (localPage > curPage) {
new GetDataTask().execute(curPage + 1, REFRESH_TYPE_UP);
} else {
getArticleList(curPage + 1, REFRESH_TYPE_UP);//如果本地没有则从服务器中获取
}
} else if (2 == position) {
new GetDataTask().execute(curPage + 1, REFRESH_TYPE_UP);
}
}
});
3、Volley获取json格式数据,更多内容见:Android Volley获取json格式的数据
final LinkedList<Article> newsArticleList = new LinkedList<Article>();
final RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
String url = Article.ARTICLE_LIST_JSON_URL + "?p=" + page;
final JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET,
url, null, new Response.Listener<JSONArray>() { @Override
public void onResponse(JSONArray response) {
int length = response.length();
try {
JSONObject jsonObject;
Article article;
for (int i = 0; i < length; i++) {
jsonObject = response.getJSONObject(i);
article = new Article();
article.setTitle(jsonObject.getString("title"));
article.setLink(jsonObject.getString("link"));
article.setLinkmd5id(jsonObject.getString("linkmd5id"));
article.setDesc(jsonObject.getString("desc"));
article.setView(jsonObject.getInt("view"));
article.setComment(jsonObject.getInt("comment"));
article.setDiggnum(jsonObject.getInt("diggnum"));
newsArticleList.add(article);
} for (Article acl : newsArticleList) {
boolean flag = false;
for (Article articleLocal : listData) {
if (acl.getLinkmd5id().equals(articleLocal.getLinkmd5id())) {
flag = true;
break;
}
}
if (!flag) {
articleDao.addArticleToDb(acl);
if (REFRESH_TYPE_DOWN == refreshType) {
listData.add(0, acl);
} else if (REFRESH_TYPE_UP == refreshType) {
listData.add(acl);
}
}
} pullToRefreshView.onRefreshComplete();
//刷新数据
adapter.notifyDataSetChanged();
curPage = page;
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() { @Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
requestQueue.add(jsonArrayRequest);
就举这几个例子吧。
五、代码看完了,说说几点经历吧:
1、万事开头难。从开始到这个简易App的诞生,首先要面临的是数据如何提供的问题。当然可以用线程的通用系统如ecshop、wordpress等的现成程序,但由于懒得填充文章。采用的是scrapy直接抓取内容入库的方式。因而,首先搞定的事情是数据的获取。
2、如何获取服务器数据。由于涉及到异步加载的问题,所以采用了google提供的volley;当然你也可以采用AsyncTask结合HttpClient进行获取。然而采用Volley的方式最为简易。
3、主UI的设计和刷新加载问题。主UI采用的是Android Studio提供的Navigation Drawer;然而上拉刷新和下拉刷新秉承着不重复造轮子的原则找来了PullToRefresh,然而PullToRefresh的整合(见Android Studio项目整合PullToRefresh的问题记录)由于对Gradle不熟悉,又大费周折。陆续地也就实现了上拉和下拉刷新的功能。
4、由于涉及到数据存储和收藏的问题,因而采用的Sqlite进行数据的存储和收藏的标记。
5、然而这只是粗略的一点记录。在开发中,随着功能的引入免不了代码的重构,因而很多代码看起来已经不是最初的样子了。当然,现在的代码仍然需要重构才能显得更为优雅。然而丑媳妇总要见公婆的嘛,后续加入功能再逐步加以优化吧。
6、应用间歇性崩溃的问题。由于一开始没有采用Handler的方式进行主UI的更新,因而导致主UI间歇性地出现崩溃的现象。更多内容见:Android app主线程UI更新间歇性崩溃的问题
好了,就先说这么多吧。大家有什么建议呢?请给我留言,谢谢!代码更新在这,https://github.com/jackgitgz/CnblogsApp。共勉之。。。
分享一个Cnblogs简易APP的更多相关文章
- (福利)分享一个用android编写的简单的APP——爱吖天气
这是本人随便编写的一个天气的APP,超级简单. 项目已同步至:https://github.com/nanchen2251/AiYaWeatherDemo 基本实现了天气查看,闪屏引导,天气基本信息, ...
- 分享一个常用Adb命令
分享一个常用Adb命令 首先 首先感谢@xuxu的常用adb命令,收益良多,但是已经不能满足于我,所以补充了下. 再者 好久没发帖了,最近论坛老司机们都在讨论/总结,我就用这个干货回报吧. 最后 基于 ...
- 分享一个oraclehelper
分享一个拿即用的oraclehelper 首先要引用本机中的oralce access,如果是64位的话,也必须是64位运行,不然会报连接为空connection 等于null. using Orac ...
- 分享一个批量导出当前实例下的所有linkedserver脚本
分享一个批量导出当前实例下的所有linkedserver脚本 很多时候,我们都需要导出实例下面的登录用户,job,linkedserver等等 导出job比较复杂,下午写了一个脚本把所有的linked ...
- 分享一个漂亮的ASP.NET MVC界面框架
本文分享一个插件化的界面框架,该框架提供了用户.角色.权限管理功能,也提供了插件的管理和插件中心.下图是该界面框架的样式(全部源码和原理介绍下一篇分享,推荐越多,源码放的越早,呵呵). 要使用该界面框 ...
- [Unity3D入门]分享一个自制的入门级游戏项目"坦克狙击手"
[Unity3D入门]分享一个自制的入门级游戏项目"坦克狙击手" 我在学Unity3D,TankSniper(坦克狙击手)这个项目是用来练手的.游戏玩法来自这里(http://ww ...
- Git.Framework 框架随手记-- 分享一个"比较垃圾"的项目
本文主要分享一个Git.Framework 开发的一个项目的部分源码,此项目代码"比较垃圾",所以请各位码农,码畜,码神,码圣勿喷!发此文只为记录工作问题以及分享问题! 一. 项目 ...
- (转)分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)
分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...
- 移动跨平台开发框架Ionic开发一个新闻阅读APP
移动跨平台开发框架Ionic开发一个新闻阅读APP 前言 这是一个系列文章,从环境搭建开始讲解,包括网络数据请求,将持续更新到项目完结.实战开发中遇到的各种问题的解决方案,也都将毫无保留的分享给大家. ...
随机推荐
- netbeans 快捷键
前言:今天开始学习使用netbeans , 在此之前,我习惯性的使用 Eclipse 的快捷键,所以,我要改造下~ 1.Application应用程序的参数args的设置,在Build->Set ...
- 洛谷P1136 迎接仪式
题目描述 LHX教主要来X市指导OI学习工作了.为了迎接教主,在一条道路旁,一群Orz教主er穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字.一旁的Orzer依次摆出“欢迎欢迎欢迎欢迎……”的 ...
- [转]基于overlayfs的硬盘资源隔离工具troot
原文在这里:http://blog.donghao.org/tag/overlayfs/ 某些开发测试团队会有这样的需求:多个开发或测试人员在一台物理机上搭环境.装rpm包.测试等,目录很可能互相干扰 ...
- jsp学习一
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1&q ...
- Longest Common Subsequence (LCS)
最长公共子序列(LCS)是经典的DP问题,求序列a[1...n], b[1..m]的LCS. 状态是DP[i][j],表示a[1..i],b[1..j]的LCS. DP转移方程是 DP[i][j]= ...
- Jquery的初识
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 深入理解 Javascript 面向对象编程
一:理解构造函数原型(prototype)机制 prototype是javascript实现与管理继承的一种机制,也是面向对象的设计思想.构造函数的原型存储着引用对象的一个指针,该指针指向与一个原型对 ...
- 线性判别分析(LDA)准则:FIsher准则、感知机准则、最小二乘(最小均方误差)准则
准则 采用一种分类形式后,就要采用准则来衡量分类的效果,最好的结果一般出现在准则函数的极值点上,因此将分类器的设计问题转化为求准则函数极值问题,即求准则函数的参数,如线性分类器中的权值向量. 分类器设 ...
- C#实现eval 进行四则运算
昨天在园子里看到有园友,写了相同标题的一篇文章.重点讲的是中缀表达式转换为后缀表达式的算法,但是实现的四则运算 有bug.其实我没看之前也不懂什么是 中缀和后缀表达式,之前有用过js eval 内置函 ...
- CSS+JS实现兼容性很好的无限级下拉菜单
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DT ...