第九章 看看精彩世界——使用网络技术
我们需要考虑如何利用网络来编写更加出色的应用程序,像qq,微博,微信等常见的应用都会大量使用网络技术。本章主要将入如何在手机端使用HTTP协议和服务器进行网络交互,并对服务器返回的数据进行解析,这也是Android中最常使用到的网络技术。
9.1 WebView的用法
有时候我们可能会碰到一些比较特殊的需求,比如说要求在应用程序里展示一些网页。但是需求里又明确指出,不允许打开系统浏览器,而我们当然也不可能自己去编写一个浏览器出来,这时候怎么办呢?
Android提供了一个WebView控件,借助它我们就可以在自己的应用程序里嵌入一个浏览器,从而非常轻松的展示各种各样的网页。
- //新建一个WebViewTest项目
- //修改activity_main文件
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <WebView //给它设置一个id,并让它充满整个屏幕
- android:id="@+id/web_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- LinearLayout>
- //这段代码的作用是,当需要从一个网页跳转到另一个网页时,我们希望目标网页仍然在当前WebView中显示,而不是打开浏览器
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- WebView webView = (WebView) findViewById(R.id.web_view);
- webView.getSetting().setJavaScriptEnabled(true); //getSetting设置浏览器属性,setJavaScriptEnabled让WebView支持JavaScript脚本
- webView.setWebViewClient(new WebViewClient()); //调用setWebViewClient来获取WebViewClient的实例
- webView.loadUrl("http://www.baidu.com");
- }
- }
- //最后需要注意的是,由于本程序使用到了网络功能,而访问网络是需要声明权限的,因此我们还需要修改AndroidManifest文件
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.webviewtest">
- <user-permission android:name="android.perrmission.INTERNET" />
- ...
- manifest>
9.2 使用HTTP协议访问网络
HTTP协议的工作原理非常简单,就是客户端向服务器发出一条HTTP请求,服务器收到请求之后会返回一些数据给客户端,然后客户端再对这些数据进行解析和处理就可以了。
WebView以及在后台帮我们处理好了发送HTTP请求,接收服务响应,解析返回数据,以及最终的页面展示这几步工作,不过由于他封装的实在太好了,反而使得我们不能那么直观地看出HTTP协议到底是如何工作的。因此下面我们就使用手动发送HTTP请求的方式,来更加深入地理解一下这个过程。
9.2.1 使用HttpURLConnection
在过去,Android上发送HTTP请求一般有两种方式:HttpURLConnection和HttpClient。目前HttpClient的功能由于缺点太多在Android6.0中已经被完全移除了。
HttpURLConnection的用法:
1)首先需要获取到HttpURLConnection的实例,一般只需要new出一个URL对象,并传入目标的网络地址,然后调用openConnection()方法即可
URL url = new URL("http://www.baidu.com");HttpURLConnection connection = (HttpURLConnection) url.openConnection();
2)得到HttpURLConnection实例后,可以设置HTTP请求方法
GET:从服务器获取数据 POST:提交数据给服务器
connection.setRequestMethod("GET");
3)接下来就可以进行一些自由的定制,比如设置连接超时,读取超时的毫秒数。
connection.setConnectTimeout(8000); //连接超时
connection.setReadTimeout(8000); //读取超时的毫秒数
4)之后再调用getInputStream()方法就可以获取到服务器返回的输入流了
InputStream in = connection.getInputStream();
5) 剩下的任务是对输入流进行读取
6)最后调用disconnect()方法将这个HTTP连接关闭掉
connection.disconnect();
- //新建一个NetworkTest项目
- //修改activity_main文件
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <Button //用于发送HTTP请求
- android:id="@+id/send_request"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Send Request" />
- <ScrollView //借助ScrollView控件,实现以滚动的形式查看屏幕外的那部分内容
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <TextView //用于将服务器返回的数据显示出来
- android:id="@+id/response_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- ScrollView>
- LinearLayout>
- //修改MainActivity中的代码
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- TextView responseText;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Button sendRequest = (Button) findViewById(R.id.send_request);
- responseText = (TextView) findViewById(R.id.send_request);
- sendRequest.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.send_request) {
- sendRequestWithHttpURLConnection();
- }
- }
- private void sendRequestWithHttpURLConnection() {
- //开启线程来发起网络请求
- new Thread(new Runnable() { //开启子线程
- @Override
- public void run() {
- HttpURLConnection connection = null;
- BufferedReader reader = null;
- try {
- URL url = new URL("http://www.baidu.com");
- connection = (HttpURLConnection) url.openConnetion(); //获取连接对象
- connection.setRequestMethod("GET"); //设置请求方式
- connection.setConnectTimeout(8000); //设置连接的超时时间
- connection.setReadTimeout(8000); //设置传递数据的超时时间
- InputStream in = connection.getInputStream(); //获取服务器的响应流
- //下面对获取到的输入流进行读取
- reader = new BufferedReader(new InputStreamReader(in));
- StringBuilder reponse = new StringBuilder();
- String line;
- while((line = reader.readLine()) != null) {
- response.append(line); //一行行的读取追加到StringBuilder中
- }
- showResponse(response.toString()); //将方法子线程切换到主线程
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch {
- e.printStackTrace();
- }
- }
- if (connection != null) {
- connection.disconnect(); // 关闭连接
- }
- }
- }
- }).start();
- }
- private void showResponse(final String response) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- //在这里进行UI操作,将结果显示到界面上
- responseText.setText(response);
- }
- });
- }
- }
- //最后一定不能忘记声明网络权限
- <manifest ...>
- <user-permission android:name="android.permission.INTERNET"/>
- ...
- manifest>
注意:如果想要提交数据给服务器,只需要将HTTP请求的方法改写成POST,并在获取输入流之前把要提交的数据写出即可。注意每条数据都要以键值对的形式存在,数据与数据之间用&隔开。
- //例如像服务器提交用户名和密码
- connection.setRequestMethod("POST");
- DataOutputStream out = new DataOUtputStream(connection.getOutputStream);
- out.writeBytes("username=admin&password=123456");
9.2.2 使用OkHttp
有许多出色的网络通信库都可以替代原生的HttpURLConnection,而其中OkHttp无疑是做的最出色的一个。
OkHttp不仅在接口封装上面做的简单易用,就连在底层实现上也是自成一派。
OkHttp的项目主页地址是:https://github.com/square/okhttp
1)在使用OkHttp之前,我们需要先在项目中添加OkHttp库的依赖,编辑app/build.gradle文件
dependencied {
compile fileTree(dir:'libs,include:['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1
testCompile 'junit:junit:4.12'
compile 'com.squareup.okhttp3:okhttp:3.4.1'}
上述依赖会自动下载两个库,一个是OkHttp库一个是Okio库,后者是前者的通信基础
2)接下来使用OkHttp需要创建一个OkHttpClient实例
OkHttpClient client = new OkHttpClient();
GET请求步骤:3)接下来如果想要发起一条HTTP请求,需要创建一个Request对象
Request request = new Request.Builder().build();
4)上述代码只是创建了一个空的Request对象,并没有什么实际作用,我们可以在最终的build方法之前连缀很多其他方法来丰富这个Request对象,比如可以通过url()方法来设置目标的网络地址
Request request = new Request.Builder().url("http://www.baidu.com").build();POST请求步骤:
3)需要先构建出一个RequestBody对象来存放待提交的参数
RequestBody requestBody = new FormBody.Builder().add("username","admin").add("password","123456").build();
4)然后在Request.Bulder中调用一下post方法,并将RequestBody对象传入Request request = new Request.Builder().url("http://www.baidu.com").post(requestBody).build();
5)之后调用OkHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();6)response就是服务器返回的数据
String responseData = response.body().string();
- //修改MainActivity中的代码
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- ...
- @Override
- public void onCilck(View v) {
- if(v.getId() == R.id.send_request) {
- sendRequestWithOkHttp();
- }
- }
- private void sendRequestWithOkHttp() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- OkHttpClient client = new OkHttpClient();
- Request request = new Request.Builder().url("http://www.baidu.com").build();
- Response response = client.newCall(request).execute();
- String responseData = reaponse.body().string();
- showResponse(responseData);
- } catch {
- e.printStackTrace()
- }
- }
- }).start();
- }
- ...
- }