本帖最后由 王震阳老师 于 2015-3-23 22:21 编辑
Android基础-05网络&消息机制&开源框架
pdf附件回复可见:
1. Android网络编程(★★★)在当今互联网时代,我们在公司写的Android程序基本不可能不联网的,网络编程是任何一个Android程序员必备的技能。 1.1网络编程的预备知识![]() 访问网络的Android应用都必须加上访问互联网的权限: ![]() 开启子线程执行网络或者耗时的操作 ![]() :在Android中凡是对UI的更新、“耗时”操作等都需要在子线程中进行。 ★ 1.Android4.0以上版本,Google更加在意UI界面运行的流畅性,强制要 求访问网络的操作不允许在主线程中执行,只能在子线程中进行,在主线程请求网络时,会报如下错误: ★ 2.ANR异常:Application Not Response,应用程序无响应。在主线程中做一些耗时的操作,阻塞了主线程,当用户点击其时,主线程无法响应,这是就会出ANR异常。 ![]() 子线程不能修改UI 主线程也叫UI线程,Activity中的onCreate方法和点击事件的方法都是运行在主线程中的。主线程创建的界面,只有主线程才能修改,别的线程不允许修改UI,否则会报如下错误: 如果子线程修改了UI,系统会验证当前线程是不是主线程,如果不是主线程,就会终止运行。 ![]() :既然子线程不能修改主线程的UI那么,我们的子线程如果需要修改UI该怎么办呢? 解决方式:使用Handler实现子线程与主线程之间的通信。 消息处理机制原理:所有使用UI界面的操作系统,后台都运行着一个死循环(Looper),在不停的监听和接收用户发出的指令,一旦接收指令就立即执行。关于Handler的使用会在接下来的案例中介绍,这里先点到为止。 ![]() 模拟器如何访问本地Tomcat 模拟器把它自己作为了localhost,也就是说,代码中使用localhost或者127.0.0.1来访问,都是访问模拟器自己!若想在模拟器上面访问我们的电脑,那么就使用android内置的IP: 10.0.0.2,10.0.0.2是模拟器设定的特定ip,在模拟器上用 10.0.0.2就能成功访问我们的电脑本机。 1.2案例-网络图片查看器需求:实现一个网络图片查看器,在页面输入框填入网络图片的地址,点击访问按钮,可以访问网络并获取图片,并显示在界面上。 ![]() 新创建一个工程,工程名字《网络图片查看器》。 ![]() 在工程清单文件(AndroidManifest.xml)中添加访问网络权限 ![]() 使用并修改默认的布局文件(activity_main.xml)。 ![]() 使用并编辑默认的Activity(MainActivity.java)
![]() 运行上面的工程,效果图如下:输入百度图片的一个网址
1.3案例-网页源码查看器需求:实现一个网页源码查看器,在页面输入框填入网页的地址,点击访问按钮,可以读取网页并显示在界面上。 ![]() :该案例跟1.2章节案例类似,因此可以直接在1.2章节中创建的工程中修改,当然新建工程也可以。使用Button按钮、EditText控件、TextView控件设置布局,在网络访问时,将接收到的二进制流转换成字符串,将字符串交由handler修改TextView的显示即可。 因为布局比较简单,处于节约篇幅的考虑就不再给出布局清单,这里只给出Activity类代码清单。MainActivity.java代码清单如下: 运行以上程序,结果图如下: 1.4案例-新闻客户端需求:使用ListView控件实现一个新闻客户端,新闻信息以XML文件的格式存储,通过网络访问存放新闻信息的XML文件,解析此文件,逐条信息生成ListView的item,添加到ListView中,在界面上呈现出来。 ![]() 创建一个新工程,工程名为《新闻客户端》,包名为com.itheima.news,在清单文件中添加访问网络权限。 ![]() 使用并编辑默认布局文件activity_main.xml,布局文件清单如下: ![]() 在res/layout目录下创建item.xml文件,作为第二步骤中ListView的item布局文件。该布局文件采用相对布局,布局清单如下: ![]() :在上面的布局文件中我们采用了开源框架SmartImageView控件来显示图片。在布局文件声明此控件时需写全包路径,否则将无法找到。关于SmartImageView的用法将会在下面的撞见中详细介绍。该框架很小巧,只需将如下文件添加到工程中。 ![]() 编写一个JavaBean用于封装新闻对象。类名:News ![]() 在本地tomcat的webapps目录下创建news文件夹,然后将news.xml和image文件添加到改文件夹中。查看本机的IP地址,并修改news.xml文件。然后启动tomcat。部署后的tomcat目录结构如下截图。 其中news.xml的文件清单如下: ![]() 使用并编辑默认MainActivity.java,在该类中实现所有方法。 运行上面的程序,效果图如下:
1.5案例-向服务器提交数据该案例模拟Android客户端给服务器端发送登录申请,客户端将用户名和密码发给服务器,由服务器来验证登录是否成功。在该案例中我们分别用GET和POST两种方式提交数据。 在该案例前我们需要做一些前期工作,首先在本地tomcat服务器上发布一个用户登录的服务。服务端用JavaWEB阶段学过的Servlet实现。这里直接给出Servlet代码,关于JavaWEB的其他知识这里不再涉及。 ![]() 以GET方式向客户端提交数据 ![]() LoginServlet核心业务代码清单如下: ![]() 将该Servlet发布到本地tomcat,然后运行tomcat,首先通过浏览器测试服务,发现发布成功。 ![]() 新创建一个Android工程,工程名《用户登录》。使用默认的布局文件和Activity。 布局文件清单如下: MainActivity 代码清单文件如下: ![]() 运行上面的工程,输入账号heima,密码123456,发现登录成功。 运行截图如下: ![]() 以POST方式向客户端提交数据 该方式跟以POST方式提交数据只有稍微的区别,因此为了方便演示,我们直接在上面的工程中修改代码。 在上面的代码清单中,蓝色部分为老的内容,需要替换,黄色的部分是新添加的部分。 运行上面的代码会得到跟以GET方式提交同样的结果。 ![]() :在上面的2个案例中,如果我们如果提交的用户名是中文,我们可能会遇到乱码问题,因此下面将结合上面的案例介绍一下常见的中文乱码问题。 1.6中文乱码问题Android操作系统默认使用的编码是UTF-8,解决中文乱码问题的关键是确保服务器和客户端使用的编码一致。 1.6.1 GET方式中文乱码的解决客户端:在拼接字符串的时候,对传递的数据通过URLEncoder类进行一下编码,使用的编码方式与服务器约定的编码方式一致。这里假设服务端的编码方式为UTF-8,发送数据到服务器的处理代码如下: 接收来自服务器的数据时,处理代码如下:
服务端:Tomcat默认采用iso-8859-1的编码接收客户端传递来的数据,因此在获取request请求中传递来的参数时,需先用iso-8859-1对参数进行解码,然后再以客户端传递的数据的编码方式进行编码。这里假设客户端发送的数据其编码方式为UTF-8,获取请求参数时处理代码如下: 发送数据给客户端时,处理代码如下:
1.6.2 POST方式中文乱码的解决客户端:发送数据给服务器的时候,对发送的数据进行编码。 接收数据时的处理逻辑与GET方式相同。 服务端:发送数据给客户端时的处理逻辑与GET方式相同,接收request请求发送来的参数时,可以采用先使用iso-8859-1解码再使用客户端的编码方式进行编码,也可以通过如下处理代码实现: 2. Android消息处理机制(★★★★)2.1 Looper、Message、Handler的关系[/url]当我们的Android应用程序的进程一创建的时候,系统就给这个进程提供了一个Looper,Looper是一个死循环,它内部维护这个一个消息队列。Looper不停地从消息队列中取消息(Message),取到消息就发送给了Handler,最后Handler根据接收到的消息去修改UI。Handler的sendMessage方法就是将消息添加到消息队列中。 2.2 runOnUiThreadActivity中提供了一个runOnUiThread方法,用于进行消息处理。此方法是通过线程合并——join来实现消息处理的。 线程合并:主线程将子线程的任务拿到自己这里来执行并终止子线程。 实例代码如下: 2.3 postDelayed该方法是Handler对象提供的,Handler给消息队列发送一个消息,发送成功则返回true,否则返回false,如果返回false一般是由于looper进程不存在导致的。该方法主要用于定时任务。如果返回true也不一定代表着我们的定时任务就执行了,因为很可能在定时任务的时间未到之前我们的looper进程退出了,那么消息也就丢失了。 执行该任务的线程用的就是Handler对象所在的线程。 2.4 postAtTime该方法也属于Handler对象,唯一不同的是该方法设置的定时任务是一个绝对时间,指的是Android系统的开机时间,如果想设置从当前时间算起2秒后执行该任务则可以将时间这样写:SystemClock.uptimeMillis()+2000,其中SystemClock.uptimeMillis()是系统运行时间。
3. 网络编程中常用的框架(★★★)3.1开源框架SmartImageView此框架提供很多实用的功能,其中可使用setImageUrl方法将一个网络图片的地址赋值给此控件,此控件内部的处理逻辑将访问网络获取指定URL的图片资源,并显示到客户端。该框架的使用很简单。 ★使用步骤: - 登录github开源大仓库,下载此开源控件。或者使用我在百度云盘上提供的附件。http://pan.baidu.com/s/1o6MDhJs。
- 添加此开源框架的包到工程下
- 在布局页面使用此控件:必须使用包名.类名这样的全路径,否则无法找到
- 调用setImageUrl,将图片的网络地址赋值给控件即可
3.2 HttpClientHttpClient是apache开源组织研发的一个API,被Android引入使用。(URL以及HttpUrlConnection是java自带的API)。 HttpClient设计的思想是模拟浏览器的操作来实现网络访问。 使用步骤: - 定义一个客户端对象:即获得一个HttpClient对象(打开浏览器)
- 定义请求方法(输入网址):Get——HttpGet/POST——HttpPost
- 设置请求的参数/请求头信息/连接超时时间/读取数据超时时间等
- 执行请求(敲回车):execute方法——此方法会返回一个HttpResponse对象
- 获取状态码:response.getStatusLine().getStatusCode()
- 若状态码是200,获取服务器返回的数据:
InputStream is=response.getEntity().getContent() client.getConnectionManager().shutdown() 3.2.1 使用HttpClient发送GET请求为了方便演示,我们直接使用本文档1.5章节的工程,只需修改发送用户数据的核心方法即可。 代码清单如下:
3.2.2 使用HttpClient发送POST使用上节中的工程,只需修改核心功能代码即可。代码清单如下:
3.3开源框架AsyncHttpClientAsyncHttpClient是一个Android的异步HTTP函数库,使用此开源项目访问网络时,无需开启子线程,因为调用其方法时传递的接口参数中的方法就是执行在主线程中的,使用起来非常方便。登录github,搜索async-http,下载此开源项目,添加jar包到工程下的lib目录,直接使用即可。百度云盘下载地址:[color=rgb(87, 137, 220) !important] http://pan.baidu.com/s/1qWz80Ew为了演示AsyncHttpClient的使用,我们依然使用上一个章节的《用户登陆》工程,只需将下载的jar包添加到工程中,如图所示。 3.3.1使用GET方式提交数据给服务器[/url]这里只在原有工程的基础上修改核心代码,代码清单如下: 3.3.2使用POST方式提交数据给服务器基本逻辑与GET方式相同,不同的是GET方式调用的是GET方法,POST方式调用的是POST方法;GET方式将请求参数拼接在URL后面传输给服务器,POST方式需要使用RequestParams对象封装请求参数给post。 3.3.3上传文件到服务器[/url]上传文件其实用的就是POST方法,只需要给RequestParams对象设置一个File类型的参数即可。实例代码如下:
至此,本文档完!
|