android+网络详解2
上小节我们以简单的两个小实例讲解了在ANDROID系统上去操作网络数据的过程,下面我们继续以小案例来深入讲解关于在ANDROID系统上对网络的实际操作,在这里我就以一个通过获取服务端最新信息来实时的显示最新的数据在ANDROID手机客户端为列,类似于现在一些手机应用的资讯显示方式,如,通过服务端信息的更新来实时监测自己的应用信息的最新信息,对其匹配否来判断更新点,下面我们就来详细讲解要实现的全过程吧:
环境描述:首先有一个显示列表:XXX文件,大小XXXM,文件格式XXX,如果是视频的话,就会多添加一项,播放长度XXXX小时/分钟,在这里,我们采取判断,如果播放时间大于一个小时的话,就以小时计算,如果小于小时的话,就以分钟计算,这时当客户端关注服务器的数据有所更新时,ANDROID客户端就会发一个通知告诉浏览的用户是否更新,在处理这个更新时,我采用的是用户可自定义,如用户可以自己定制接受文件更新的方式有:默认为提示1分钟后自动更新,可设置不需要提示直接更新,与弹出对话框提示更新,或收到提示后按时5分钟提示一次希望你手动更新,并显示更新的记录
环境描述完了,下面我就来描述一下我们怎么去实现上面这个环境要求呢,这就需要我们去了解更多的关于网络知识与ANDROUD本地组件服务机制了,先我们假设列表已经正常显示,此时我们需要搭建服务端,相对来说服务端会做很复杂的工作,只是特别注意的是,在这里我讲解在服务端存储信息的方式分为XML与JSON格式,而在其文件头请一定要把<?XML VERSION="1.0" ENCODING="UTF-8"?>写在头放,不管你的头行有多少数据,你都不能把它写在其它行,不然会报错的,其次在服务端做的工作我就不多说了,如安全验证,等,当然我会简单对数据更新提示与编码格式做些简单的介绍,我们先从第一次去获取服务端的信息开始讲起吧,在这里我们就不在使用HttpRULConnection做请求头发送访问响应了,而是直接采用SOCKET编程来实现,因为我们固定了服务端主机名与端口来提供访问,然而在服务端,我们采用的是多线程并发访问机制来接收的,主要信息就是提供一个线程池:ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().avilableProcessors()*100)提供一百个线程并发的访问量,其次就是服务端特别提供的监听端口XXX.再次就是存放断点数据用来在传输信息时假如信息传输在某一个时刻失败的话就会记住当前断点并在再次开启传输时获取之前断点继续传输,只是这个功能是在这个讲解中多处来的,为什么是多出来的了,它用在服务器端,主要是实现上传文件时使用,如果我们在下载文件时只需要在客户端保存断点即可,OK,多点知识不是坏处嘛,其次就是单独开启一个方法来启动这些线程,在服务端,我们采用了数据采集的方式去获取网络上最新的信息,另外添加了人工处理数据的方式对其数据分别进行更新,当然这里数服务器端技术,主要使用的是J2EE方面的技术,由于我之前做J2EE比较长,所以在之前的项目中两方面都有兼任,在这里我就大体介绍一下我们其中的项目在J2EE上的架构吧,说到这里不说也不行了,只是我不会说出具体项目与详细细节,因为项目还在保密其,其架构我就说个基本的,相对来说这个架构比较简单,但是内部机制不是你想象的那么简单,呵呵,有点调胃口的感觉,废话不多说了,不然谁看到这样的文章都受不了的,甚至给我痛骂一顿,首先我们后台管理显示层页面使用JSP,其次是数据控制层,数据控制层实现了数据缓存与数据服务机制,再次就是业务逻辑层,使用MEMBERSHIP与RBAC提供对业务逻辑的处理,再次据是资源访问层,使用J2EE技术构建实体并对其实体进行管理控制,采用SubSonic机制来实现,这层主要是对资源层,即数据库资源做控制输入输出,在J2EE里的基本架构也就这样,如果是详细描述的话,那可能就是个糟糕的问题了,所以就简单描述在这里吧,还有就是在WEB最上层是提供了对手机客户端访问的验证需求,这是必要的,你可以采用SOAPHEADER+动态SESSIONID来对其操作,这是完全可以的,这就不知不觉好像谈起架构来了,前端时间做架构好像有点上瘾了,既然这样,我也就简单来介绍下我们手机客户端的大体架构模式吧,记住是大体,即以MVC模式的架构方式:在V层我们主要提供了数据显示与输入,所以需要一个VIEW来提供显示,还需要一个数据适配器来对数据进行配置显示,即Data Adapter,其次就是在C层,在这层主要是UI对其的控制,它主要的作用就是关注数据与对V层数据提供进行控制,其次就是M层,这层就是针对M层来讲的,它主要的作用就是获取数据来源并想C层提供数据,在获取数据来源的方式有几种,一种是内存缓存,一种是本地,另一种就是通过网络,即服务器端获取数据,对其也可以保存在本地,OK,基本架构就是这样了,可能有的人很关心我们在通过手机客户端与网络服务器进行数据交互时的过程,下面我们就来详细讲解了:在客户端服务线程,我们会发一个定时器,使用SOCKET方式去获得服务端的某地址XXXX,端口XXX,以Socket socket = new Socket(服务IP,端口);OutputStream outStream = Socket.getOutputStream()与服务端获得连接,然后把请求头信息组建成一个实体对象:String head = "Content-Type="+...."/r/n",然后通过outStream.write(head.getBytes())进行写入并请求,只是需要注意的是我们在这里面使用了PushbackInputStream,因为我们在数据读取过程中,在头或者内容的最后都会跟上回车换行,我是说假如,当你读取到/R后/N没有读取到的话,这时候根据文件读取长度,就会多读到下一个内容的部分,那样的话,下一个文件内容就会出现不完整,然而普通流只能向前读不能向后读,所以我们使用PushbackInputStream里的一个unread()方法可以对其已读取的数据进行回退,只要经过是的判断,如判断读到当前内容最后为/N时结束第一段,否则的话返回重新读取当前字节,这样就可以避免我们在使用SOCKET编程实现数据传输的过程误读不能后退的弊端,只是我们在这里要尽量小心才是,由于我们是去获得信息,所以我们第一次不会有默认ID的唯一标志,这是需要在服务端进行分配,也就是服务端获得了相应的的请求并判断你是不是带有一个系统服务赋予的动态ID,如果没有的话,就会动态新创建一个SESSIONID,并为当前进行保留,同时把相应的信息附加到要传递给客户端信息的后面,作为信息对象传递给客户端,当客户端获取到这样的信息后就直接进行解析,由于我服务端采用的是JSON数据存储信息格式,所以在客户端,我们首先要去对信息进行解析,以对象对应格式做相应的处理,如获得的是图片格式,我们采用的是直接以二进制接收内容的方式进行显示:Bitmap bitmap = BitmapFactory.encodeArray(datas,0,data.lengt);如是一般文件就直接使用new String(file,"编码格式")来进行包装并返回与接收即可,只是在服务端对信息响应时,它不是单纯的只会去响应,而是定时的更新服务端信息,在提示,服务端信息是通过网络或者人工输入来更新的,所以在对数据进行服务更新时,需要对历史数据进行更新处理,这个过程比较复杂,在这里我就不继续介绍了,OK服务端基本就是这样了,然后就是客户端获得信息后,根据流输出后并组建标志读取位置来实现判读读取的问价内容以至于踩用不同的格式进行读取,并使用PushbackInputStream流防止误读机制来写入,这点非常重要,请牢记,因为我们每种格式的内容都做了标记,只有我们通过这个标记的判断才能知道我需要写入的内容为格式以至于错读方式的倒退,OK,严格控制它就可以获得不同的对象格式进行很好的分类来储存取了,如获得的是以MP3格式的文件内容,我们就需要
通过ANDROUD自带的解码器来接受并解码,当然,我是说,如果你需要播放的话,当然首先,你得把它保存在本地,然后就可以直接使用ANDROID自带的播放接口来实现更多的比ANDROID自己实现的跟票亮与复杂的播放效果,ANDROID的自带的只是一个很简单的DEMO,但是它提供了免费的结构可以让去施展它的尽可能:File autioFile = new File(Environment.getExtenalStorageDirectory(),fileName.getText().toString());MediaPlayer().release();MediaPlayer().setDataSource(audioFile.getAbsolutePath());MediaPlayer().prepare(); MediaPlayer().start();在这里我不会讲关于在ANDROID播放可能会存在哪些问题,在后面,我会讲到在ANDROID中在播放视频与音频时遇到的问题与问题的解决方案,以至于我们该怎么去实现一个实时播放的流媒体效果.OK,在流的传输机制中,我可能讲得很简单,只是流写入与写出我想大家读很了解了,所以我只是在这个过程中我们怎么去取得实时数据与可能遇到的问题进行了分析,以后在于遇到这样的问题时应该用什么样的思路去解决,最后在ANDROID客户端的显示我就不在介绍了,那是关于UI显示处理问题,再下来我就想说一下,当我们第一次获得数据并成功显示在手机客户端后,我们怎么去知道服务器数据有所更新了呢,在这里我们是这样做的:在手机客户端开启一个服务线程,这个服务线程用来定时方法,也就是所谓的实现了定时刷新的效果,也就是定时带上本地第一次重服务端带过来的SESSIONID以头的方式包装起来向服务端发出请求,当服务端获得请求后,会根据客户端带过来的SESSIONID与本地之前保存的SESSIONID进行对比,当然,本地之前保存的SESSIONID收服务端数据更新服务来控制,如果有数据更新就会重新生成一个动态的SESSIONID对其之前的SESSIONID进行替换,此时,如果客户端传过来的SESSIONID与服务端更新后的SESSIONID不匹配的话,就说明数据已经更新,此时,就会打开服务端流进行写入,客户端也相应的对其索取与更新,在项目之后,我突发灵感,下面是个人技术探索,没真正去试验与应用过,如果感兴趣的读者或技术偏爱可以根据思路去测试一下:就是在客户端使用BroadcastReceive来实现对数据进行监听,但是需要在服务端可以指定一个端口供客户端来实现监听,也就是当服务端有数据更新时,服务端会发送一个消息给那个端口,是监听那个端口的接收者通过某种方式获得这样的信息后并通知客户端数据服务线程,让他自动打开与服务器端对流连接的请求来获取最新的信息并更新自己.......等,好了,在这里我简单介绍一下,为什么我采用直接使用Socket编程而不直接使用HTTP协议封装后的组建来做呢,比如说可以使用HttpCilent来操作,如果你想在网络上指定某个功能单纯实现某样工作的话,然而你使用开源框架,它们都是对一些通用机制的封装,虽然也包含了你所要的功能,只是你需要的只是它很小的一部分功能,缺惯用了一些很不需要的代码,这样到来的直接后果会导致你的应用程序性能严重下降,除非你要使用到了开源框架里的所有功能,为了方便即可以去使用,毕竟人家开源的优化效果还是很明显的,再次我们在做请求数据传输的时候为什么不直接使用HttpURLConnection呢,因为,我们已经知道主机的IP与端口,这是长时间固定的,然而在实现这个功能时,只是应用的很小的一部分,还有别的功能也需要引入类似的实现,如要实现FTP上传文件等功能,这时我们就需要使用SOCKET支持的断点续传上传功能,然而HTTP协议是不支持,即使支持,在服务端也是限制传输大小的,比如一般的服务器可能只能上传到达2M,有的可能有5M或者更少,但是使用SOCKET是不受限制的,如就以FTP上传服务器为例:如果我们使用HttpURLConnection的话,HtttpURLConnection是继承了URLConnection,然而它使用了一个默认缓存机制限制了你在网络上的传输速率,一般它最大只支持1M,它传入的方式是以写入内存的方式进行传入,也就是供文件一次性传入与写出,然而这样使其内存是严重受限的,维持当你数传比较大的文件,如音频或者视频上G的文件时,就会报内存溢出,然而我们使用SOCKET流机制写入是不过分的依赖与内存的限制,它使用了一个ByteArrayOutputStream来实现缓冲机制的边读边写的方式据会把读入内存的数据第一时间读出来写入本地数据库或本地文件进行保存,同样,我们提到断点,在这里就多说几句吧,说为实现断点续传就是在当我们用手机下载或上传某个文件时,突然没了网络,或者手机没电了,此时文件下载或者上传就会被断开,这时,服务端与客户端都分别会记载其文件上传或者下载的文件节点位置并写入本地文件或者数据库,当我们再次启动这个应用的时候去在上次丢失的工作就会首先去获取本地之前保存的节点来寻找对应的节点来进行匹配,如果匹配的话就继续从匹配点开始读取或写入信息.好了今天就说在这里,下次我会对其部分以更详细的案例进行解说.....