一步步教你为网站开发Android客户端

news/2024/5/20 15:30:47/文章来源:https://blog.csdn.net/mypanlong/article/details/42966861
本文面向Android初级开发者,有一定的Java和Android知识即可。

文章覆盖知识点:HttpWatch抓包,HttpClient模拟POST请求,Jsoup解析HTML代码,动态更新ListView

 

背景介绍:客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。而android系统上的90%客户端软件都有一个共性,就是为了改善网页在android系统上体验不佳而生,最具有影响力的软件有:新浪微博、人人网、淘宝等,这类软件最突出的特点就是,先有网站再有软件。由于网络技术发展的多样性,手机浏览器往往无法跟随它的步伐,为改善用户体验,网站客户端软件印运而生。

 

开发Android网站客户端通常有两种方法:第一种,通过服务端的开放平台,调用提供的API接口来开发,比如说open sina;第二种,服务端没有提供任何接口,你也没有服务端任何数据库访问权限,就是一个纯纯粹粹的网站,要你做客户端。今天,我要和大家分享的正是第二种情况。

QQ截图20111129094559.png



这是一个简单的示意图,告诉我们,数据是由网页从数据库中取出,我们要为这个系统做客户端,我们就应该这样去改造它。

QQ截图20111129094624.png




通过这样间接的方法来访问数据库,只要网页能看到的内容,我们的客户端都能获取到,而UI是由你自行制作,就可以使使用体验上一个台阶。
既然网页是我们的数据枢纽,我们就从网页分析着手。

该教程来自本人项目-掌上民大-真实经验,所以用项目中的”掌上图书馆”板块来示范。

 

该项目任务为中南民族大学图书馆图书查询功能制作客户端。

 

首先打开该网址http://www.lib.scuec.edu.cn/,我们会看到主界面

QQ截图20111129094753.png




正中间就是查询入口,我们输入”android”进行查询

QQ截图20111129094829.png




得到结果的网页,但我们能发现,这个页面是ILAS图书管理系统,所以真正的入口并不是上面红圈的地方。
所以我继续找,经过短暂的观察,发现入口在这里

QQ截图20111129094848.png




我们点击进入

QQ截图20111129095321.png




果然就是这货,我们点击书目查询

 

QQ截图20111129095339.png




就是它了。真正的入口就在这里,这时我们打开HttpWatch软件,点”Record”,在搜索框里输入”android”,点击查询,抓取以”android”为关键字搜索时浏览器的所有包。待结果界面载入完成后,HttpWatch上就会出现如下信息

QQ截图20111129095358.png



我们先看Summary选项卡,我们可以初步了解,这是一个POST请求(Http请求中的一种,另一种是GET),POST到的网址是http://coin.lib.scuec.edu.cn/cgi-bin/IlaswebBib。
这样我们的思路就清晰了,我们的客户端需要模拟浏览器,向上述地址POST一个包,那个地址肯定会返回一个Content给我们,不出意外的话,Content里面就是我们要的书目信息。那么,浏览器POST上去的内容是什么呢?我们点击这条POST请求,看详细信息,


QQ截图20111129095406.png



由于是POST请求,我们先看POST DATA,里面是以键值对的形式存储的,这里显示了我们浏览器在我们搜索”android”时,POST的所有数据。那这些键值对又代表了什么呢,我们打开这个网页的源码来一探究竟。

QQ截图20111129095541.png



从这段可以看出v_index是表示查找途径的它有TITLE,AUTHOR,SUBJECT,CLASSNO,ISBN,CALLNO六种值

QQ截图20111129095645.png



FLD_DAT_BEG和FLD_DAT_END分别是开始和结束年份

QQ截图20111129095655.png



v_value表示用户在搜索框中输入的内容

QQ截图20111129095702.png



v_paggnum表示每页显示的书目条数,有10 15 20三种

QQ截图20111129095712.png



v_seldatabases是检索库  有0 1 2三种值v_LogicSrch是检索方式   有0 1两种值

QQ截图20111129095718.png



Submit是查询或重填,有 查 询 和 重 填 两种值

至此,我们弄清楚了POST Data里所有内容的含义和取值可能。但我们模拟POST请求为什么,其实就是为了得到搜索的书目信息,所以我们看一下返回的Content是不是我们要的东西


QQ截图20111129095738.png



果然,就是我们搜到的书目信息,就以String的形式放在Content里面。最后我们查看一下Stream,截图,以防等下我们需要这里面的东西

QQ截图20111129095745.png



好了,这个页面的工作原理我们已经弄清楚了:用户在网页中输入搜索内容后,点击查询,浏览器会POST一个Data到目标网址,该网址的返回信息就是搜到的书目。 
我们开始编写代码,模拟这个过程,先打开eclipse建立一个Java项目(注意是Java项目,因为Java项目可以完美移植到Android项目中且调试方便,并且模拟Http请求这一过程没有用到任何Android功能)。
导入HttpClient的4个包commons-codec、commons-httpclient、commons-logging、log4j。

?
//实例化HttpClient
HttpClient client = new HttpClient();
//Stream页面里面有Host地址 端口是80
client.getHostConfiguration().setHost("http://coin.lib.scuec.edu.cn", 80);
//用目标地址 实例一个POST方法
PostMethod post = new PostMethod("http://coin.lib.scuec.edu.cn/cgi-bin/IlaswebBib");
//将需要的键值对写出来
NameValuePair beg = new NameValuePair("FLD_DAT_BEG" , “”);
NameValuePair end = new NameValuePair("FLD_DAT_END" , “”);
NameValuePair submit = new NameValuePair("submit" , "查 询"));
NameValuePair vIndex = new NameValuePair("v_index" , “TITLE”);
NameValuePair vLogicSrch = new NameValuePair("v_LogicSrch" , "0");
NameValuePair vPagenum = new NameValuePair("v_pagenum" , "10");
NameValuePair vSeldatabase = new NameValuePair("v_seldatabase" , "0");
NameValuePair vValue = new NameValuePair("v_value" ,”android”);
  
//给POST方法加入上述键值对
post.setRequestBody(new NameValuePair[] {beg , end , submit , vIndex , vLogicSrch , vPagenum , vSeldatabase , vValue});
//执行POST方法
client.executeMethod(post);
//将POST返回的数据以流的形式读入,再把输入流流至一个buff缓冲字节数组 
//StreamTool类是我自己写的一个工具类,其内容将在下文附出
byte[] buff = StreamTool.readInputStream(post.getResponseBodyAsStream());
//将返回的内容格式化为String存在html中
String html = new String(buff);
//任务完成了,释放连接
post.releaseConnection();

  

?
//StreamTool类如下
public class StreamTool {
        /**
         * 从输入流中获取数据
         * @param inputStream 输入流
         * @return 字节数组
         * @throws Exception
         */
        public static byte[] readInputStream(InputStream inputStream) throws Exception
        {
//实例化一个输出流
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//一个1024字节的缓冲字节数组
                byte[] buffer = new byte[1024];
                int len = 0;
//读流的基本知识
                while ((len=inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, len);
                }
//用完要关,大家都懂的
                inputStream.close();
                return outputStream.toByteArray();
        }
}

  现在,我们得到了POST方法返回的String,我们输出到控制台看看是什么

?
System.out.println(html);

  

QQ截图20111129095849.png



没错,就是我们上文看到的HttpWatch 抓到的返回Content,也就是一段HTML代码,这说明,我们模拟浏览器POST请求成功了!
我们再试试别的搜索内容,来一个”Android开发”(即将v_value键值对的值改成”android开发”),这时运行后,我们却从控制台得到了这样的结果:


QQ截图20111129095912.png



经过几次试验后,发现一个规律,只要搜索内容中包括中文,就搜不到。
所以可以判定是中文编码的问题,(在开发这类客户端时候,中文编码往往是个很具困难的问题。安卓巴士开发3群的某群友提到:服务器交流用的编码是”ISO-8859-1”,跟我起初用到的编码一致,但真实性仍需考证)所以我们修改上面的代码,将代表搜索内容的v_value对应的值编码为”ISO-8859-1”

就将上段代码中的

?
NameValuePair vValue = new NameValuePair("v_value" ,”android”);

  改为

?
NameValuePair vValue = new NameValuePair("v_value" , new String(“android开发”.getBytes(),"ISO-8859-1"));

  这时再运行,控制台成功输出以” android开发”为关键字的Content。

至此,我们POST请求才真正完成。 观察控制台的HTML后发现,我们需要的书目信息就在里面,只不过被一些HTML标签包裹住了,下一步我们就要解放这些信息,存储到容器里。
这里我们要用到Jsoup,一个Java开源HTML解析器(来自org.jsoup包)。
我们直接上代码,逐行解释(大家最好对应上面的HTML代码来理解)
首先我们建一个容器来装这些解析到的数据,由于我的项目是将这些数据以ListView呈现给用户,而ListView的数据是由Adapter提供,Adapter需要传一个特殊容器-包含HashMap的ArrayList(Android基础知识)

?
//所以有
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
//开始使用Jsoup
//Jsoup支援一个Document类   将刚才的html转化成Document
Document document = Jsoup.parse(html);
//一个Document又由elements组成  我们选择”tr”开头的标签,存入 trs元素群中
Elements trs = document.select("tr");
//得到整个HTML中包含tr的标签的个数
int totalTrs = trs.size();
//我们可以观察上面没有搜索结果的那个HTML。发现,如果totalTrs<=3就表示没结果。
//只要有书目结果totalTrs必定大于3,于是
if(totalTrs > 3)
for(int i = 0;i < totalTrs - 3;i++)
{
//观察HTML,从第i+2个tr开始,包含的才是我们要的书目信息
//我们从每个tr中选出td标签元素群
                        Elements tds = trs.get(i + 2).select("td");
//得到每个tr中td的个数
                        int totalTds = tds.size();
//一个临时的HashMap,里面是String-Object键值对
                        Map<String,Object> map = new HashMap<String,Object>();
//j是一个标识数
                        for(int j =0;j < totalTds ;j++)
                        {
                                switch (j) {
//0表示第一个,即书名
//put方法即向map加入一条键值对
//html()方法就得到标签括起来的内容
                                case 0:
                                        map.put("book_title", tds.get(j).html().toString());
                                        break;
                                case 1:
//1表示第二个,即作者
                                        map.put("book_author", tds.get(j).html().toString());
                                        break;
                                case 2:
//2表示第三个,即出版信息
                                        map.put("book_press", tds.get(j).html().toString());
                                        break;
                                case 3:
//3表示第四个,即页数
                                        map.put("book_page", tds.get(j).html().toString());
                                        break;
                                case 4:
//4表示第五个,即价格
                                        map.put("book_price", tds.get(j).html().toString());
                                        break;
                                case 5:
//5表示第六个,即索取号
                                        map.put("book_noFor", tds.get(j).html().toString());
                                        break;
                                case 6:
//6表示第七个,即那段网址
//那段网址td中又包含一个a标签,a标签的href属性的值就是网址
//attr(“href”)可以返回href属性的值
                                        map.put("book_detail", tds.get(j).select("a").attr("href").toString());
                                        break;
                                default:
                                        break;
                                }
                        }
                        list.add(map);
}

  list就是我们需要的ArrayList啦

上面所有代码调通后,我们只需一些简单的复制粘贴,就可以放在我们的Android工程中,加上一段简单的代码就可以让ListView显示这个ArrayList。(由于没有任何技术含量,以及该项目暂未上线,此段代码不予以展示,敬请谅解) 

接下来,我们一个页面最多只包含10个书目信息,而我们校图书馆,光以”Java”为关键字的书就超过1000本,怎么来显示完全呢,一次显示所有的书肯定不现实。首先数据量太大,手机无法承受;消耗流量过大,用户体验极差。所以,我们就需要ListView能够动态加载数据,即一开始显示十项,如果用户此时拉动ListView显示完十项之后,自动联网,再加载十项(如果还有十项的话),这样的用户体验会非常顺畅。
这个功能的核心是,我们的ListView需要实现OnScrollListener接口。
如果你的ListView所在的Activity继承的是ListActivity的话,只需在extends ListActivity后面加上implements OnScrollListener,这时你需要复写onScroll和onScrollStateChanged。如果你的ListView是从XMLgetView 得到的,你只需为它setOnScrollListener,也会需要你复写onScroll和onScrollStateChanged。

不管你用哪种方法,我们只用修改onScroll方法

?
@Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                        int visibleItemCount, int totalItemCount) {
                // TODO Auto-generated method stub
//关键的判断代码,这句话表示用户将ListView拉至最底部
                if(firstVisibleItem + visibleItemCount == totalItemCount)
//你只需要把继续得到下面十项的代码写在这里,就可以实现上述功能了。
//同样再使用一次POST方法,不再赘述
//代码由于同样原因不予以展示,敬请谅解

  至此,文章开头的几个知识点已经全部讲解完毕,时间仓促,事物繁忙,可能会影响文章质量,还请大家多多包涵。 如果有问题,可以直接回帖、发论坛信息或通过Email:anliupeinye@gmail.com联系我。

项目成品展示:

device-2011-11-29-161307.png 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_814223.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android模拟登陆带验证码的网站客户端

首先获取验证码并保存Cookie&#xff0c;登陆时将Cookie和账号密码一同发送出去&#xff0c;返回状态码200&#xff0c;登陆成功&#xff0c;接下来再去访问其他需要登录权限的页面时附上Cookie发送出去即可。 要实现模拟登陆&#xff0c;首先需要了解登陆网站时请求中都包含什…

使用jsoup做任意网站的客户端

jsoup是一个解析网页源码的开源库&#xff0c;他能按照给定的规则提取出一个网页中的任意元素&#xff0c;和其他网页解析库不同的是&#xff0c;他提取网页内容的方式和css、jquery的选择器非常相似。因此如果你懂得前端的知识&#xff0c;只需根据以下的代码样例就可以在3分钟…

原来我们不懂百度seo排名和百度竞价

2013年即将结束&#xff0c;高富白美在欢乐着自己的年假和年终奖&#xff0c;而我等只能继续苦逼的为梦想坚持到除夕放假&#xff0c;或许这是假日组在淬炼我们的精神吧&#xff0c;笑一笑有啥&#xff0c;切入主题。网络营销千千万&#xff0c;我们今天只看百度系&#xff0c;…

免费主机备案带宽_怎样自己建立一个网站,免费建站靠不靠谱

一、网站的组成网站主要由域名、服务器、网页三个部分组成。如果把网站比作一个房子的话&#xff0c;那么域名&#xff1a;相当于网站的地址&#xff0c;或者说是门牌号&#xff0c;用来找到网站&#xff0c;网站上的网页都是以网站的域名开头的&#xff0c;例如网站域名是www.…

Flink 指定时间范围内网站总浏览量(PV)的统计

基于Flink 统计每小时内的网站PV。 public class Flink03_Practice_PageView_Window2 {public static void main(String[] args) throws Exception {//1.获取执行环境StreamExecutionEnvironment env StreamExecutionEnvironment.getExecutionEnvironment();//2.读取文本数据…

JavaScript网站设计实践(六)编写live.html页面 改进表格显示

一、编写live.html页面&#xff0c;1、JavaScript实现表格的隔行换色&#xff0c;并且当鼠标移过时当前行高亮显示&#xff1b;2、是输出表格中的abbr标签的内容 实现后的效果图是这样的&#xff1a; 1、实现思路 在输出表格的时候&#xff0c;给出一个判断&#xff0c;如果偶数…

分享10个最佳的WordPress教程免费学习网站

WordPress是用于发布信息的最热门平台之一。 WordPress可用于个人或商业博客&#xff0c;也可以为你用于你的在线业务。WordPress最大的优点是&#xff0c;你可以轻松地去进行自定义设置&#xff0c;而且不必懂太多编程方面的知识。你对WordPress的一些知识懂的越多&#xff0c…

Python爬虫:使用正则表达式爬取网站电影信息

以爬取电影天堂喜剧片前5页信息为例&#xff0c;代码如下&#xff1a; 1 # coding:UTF-82 3 import requests4 import re5 6 def mov():7 headers{User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/53…

流量排名前一千万网站,三分之一使用 WordPress

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> WordPress 在官博发文&#xff0c;庆祝它在流量排名前一千万网站中的市场占有率达到了三分之一。据 W3Techs 的数据&#xff0c;WordPress 在前一千万网站的市场份额从一年前的 29…

node的系统核心模块实现服务器功能、用nodejs做动态网站(后端渲染)

1、初步实现服务器功能详解 a、静态服务器功能---提供静态网页&#xff08;不管什么路径访问的响应只有ok&#xff09; b、优化a做的功能 ---处理路径的分发&#xff08;我们期待结果是不同路径对应不同响应处理&#xff08;页面&#xff09;&#xff09; 通过postman工具可以…

网站速度测试

为什么80%的码农都做不了架构师&#xff1f;>>> |国内 卡卡网&#xff1a;http://www.webkaka.com/ &#xff08;可以设置国内测试点和全球测试点 奇云测速&#xff1a;http://ce.cloud.360.cn/ |国外 PINGDOM &#xff1a;http://tools.pingdom.com/fpt/ |导航…

大型网站技术架构(四)网站的高性能架构

2019独角兽企业重金招聘Python工程师标准>>> 网站性能是客观的指标&#xff0c;可以具体体现到响应时间、吞吐量、并发数、性能计数器等技术指标。 1、性能测试指标 1.1 响应时间 指应用执行一个操作需要的时间&#xff0c;指从发出请求到最后收到响应数据所需要的时…

偷情网站被黑 无隐私的互联网下如何保护自己

用户隐私信息被盗&#xff0c;似乎是自互联网诞生以来&#xff0c;一直盘旋在头顶挥散不去的阴影——最为普及的Windows系统自身存在的各种问题&#xff0c;网站被黑、数据被窃事件层出不穷。即使目前是目前最为火爆的移动互联网&#xff0c;安卓系统的病毒应用及各种堵之不及的…

spark读取 kafka nginx网站日志消息 并写入HDFS中(转)

原文链接&#xff1a;spark读取 kafka nginx网站日志消息 并写入HDFS中 spark 版本为1.0 kafka 版本为0.8 首先来看看kafka的架构图 详细了解请参考官方 我这边有三台机器用于kafka 日志收集的 A 192.168.1.1 为server B 192.168.1.2 为producer C 192.168.1.3 为consumer 首先…

Linux环境下部署Jpress大型博客网站

Jpress简介 一个类似 WordPress 的产品&#xff0c;使用Java开发。 开始部署 1.环境准备 1.1.搭建tomcat jdk安装 #这里的eof使用单引号引起来是为了让特殊符号也写入文件 #PATH 存放命令的路径&#xff0c;如果不小心改错了/etc/profile文件那么命令就不能使用了&#xf…

使用 Asp(vbs) 来读取 XML 数据岛 来制作网站菜单

总的来说还得使用到Microsoft的ActiveX创建XML对象&#xff1a;createObject("Microsoft.XMLDOM")读取节点&#xff1a;selectSingleNode("nodename") //nodename为节点名。读取属性&#xff1a;attributes.getNamedItem("attribute") //attribu…

部署论坛项目并使用redis缓存加速网站访问流量

部署discuz并使用redis加速 1.部署LNMP环境 1.1.准备yum环境 [rootjiangxl ~]# rm -rf /etc/yum.repos.d/* [rootjiangxl ~]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo ;curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.…

《大型网站技术架构:核心原理与案例分析》读书笔记 - 网站的技术升级路线...

本文描述网站从小到大演变过程中的技术升级路线&#xff1b;1.初始架构一台服务器&#xff0c;应用、DB、文件都在一块&#xff0c;使用经典的LAMP模式构建整个站点&#xff1b; 优点很明显&#xff0c;开发部署都简单&#xff0c;船小好掉头&#xff0c;做不起来也亏不了多少&…

filebeat收集多个域名网站日志并存储到不同的es索引库(五)

filebeat收集多个域名日志并创建不同索引 1.为什么要针对不同的应用系统创建不同的索引 公司生产环境中一台机器上一定会运行着多个域名的应用&#xff0c;web应用也是集群的方式&#xff0c;如果filebeat收集来的日志都是分散存储&#xff0c;且在es上建立的索引也都是分散的…

域名,网站名和URL区别

要写一个正则表达式来验证输入域名是否有正确&#xff0c;一直以为例如http://www.baidu.com类似于这种才是网站域名&#xff0c;经过百度才发现自己的认知是错误的。 以下转载于百度经验&#xff1a;http://jingyan.baidu.com/article/2c8c281df0afd00008252aa7.html 方法/步…