CH9-网络编程

这篇具有很好参考价值的文章主要介绍了CH9-网络编程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目标

  • 了解HTTP协议通信简介,能够说出什么是HTTP协议
  • 掌握HttpURLConnection的使用方法,能够使用HttpURLConnection访问网络
  • 掌握WebView控件的使用方式,能够使用WebView控件加载不同的网页
  • 掌握JSON数据的解析,能够通过不同的方式解析JSON数据
  • 熟悉Handler消息机制的概述,能够归纳Handler消息机制的原理

​ 在移动互联网时代,手机联网实现信息互通是最基本的功能体验。例如,在上下班的途中或旅行时,只要有时间人们就会拿出手机上网,通过手机接收新资讯、搜索网络资源。Android作为智能手机市场中主流的操作系统,它的强大离不开其对网络功能的支持。Android系统提供了多种实现网络通信的方式。接下来,我们从最基础的HTTP协议开始,到Android中原生的HttpURLConnection、WebView控件的使用以及网络数据的解析进行详细讲解。

一、通过HTTP访问网络

  • 了解HTTP协议通信简介,能够说出什么是HTTP协议
  • 掌握HttpURLConnection的使用方法,能够使用HttpURLConnection访问网络

1.1 HTTP协议通信简介

HTTP(Hyper Text Transfer Protocol)即超文本传输协议,它规定了浏览器服务器之间相互通信的规则。

HTTP协议是一种请求/响应式的协议

  • 当客户端与服务器端建立连接后,向服务器端发送的请求,称作HTTP请求

  • 服务器端接收到请求后会做出响应,称为HTTP响应

​ 使用手机客户端访问百度时,会发送一个HTTP请求,当服务器端接收到请求后,会做出响应并将百度页面(数据)返回给客户端浏览器,这个请求响应的过程就是HTTP通信的过程。

CH9-网络编程

1.2 使用HttpURLConnection访问网络

GET与POST请求

(1)GET方式

GET方式是以实体的方式得到由请求URL所指向的资源信息,它向服务器提交的参数跟在请求URL后面。使用GET方式访问网络URL的长度一般要小于1KB

(2)POST方式

POST方式向服务器发出请求时需要在请求后附加实体。它向服务器提交的参数在请求后的实体中,POST方式对URL的长度是没有限制的。

​ 采用POST方式提交数据时,用户在浏览器中看不到向服务器提交的请求参数,因此POST方式要比GET方式相对安全。

GET方式提交数据

//将用户名和密码拼在指定资源路径后面,并对用户名和密码进行编码
String path = "http://192.168.1.100:8080/web/LoginServlet?username="
                  + URLEncoder.encode("zhangsan")
                  +"&password="+ URLEncoder.encode("123");  
URL url =  new  URL(path);                      
HttpURLConnection  conn  =  (HttpURLConnection)url.openConnection();  
conn.setRequestMethod("GET");                  
conn.setConnectTimeout(5000);                  
int responseCode = conn.getResponseCode();  //获取到状态码
if(responseCode == 200){          //状态码为200,表示访问成功获取返回内容的输入流         
        InputStream is = conn.getInputStream(); 
}

POST方式提交数据

URL url = new URL("http://192.168.1.100:8080/web/LoginServlet");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);                
conn.setRequestMethod("POST");               
//准备数据并给参数进行编码
String data = "username=" + URLEncoder.encode("zhangsan")
                  + "&password=" + URLEncoder.encode("123");
//设置请求头数据提交方式以及提交数据的长度,这里是以form表单的方式提交
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
conn.setRequestProperty("Content-Length", data.length() + ""); 
//以流的形式将数据写到服务器上
conn.setDoOutput(true); 
OutputStream os = conn.getOutputStream(); 
os.write(data.getBytes()); 
int code = conn.getResponseCode(); 
if (code == 200) {
    InputStream is = conn.getInputStream(); 
}

注意

​ 在实际开发中,手机端与服务器端进行交互的过程中避免不了要提交中文到服务器,这时就会出现中文乱码的情况。无论是GET方式还是POST方式提交参数时都要给参数进行编码,编码方式必须与服务器解码方式一致。同样在获取服务器返回的中文字符时,也需要用指定格式进行解码。

二、使用WebView进行网络开发

目标

  • 掌握WebView的使用方式,能够使用WebView浏览不同网页、执行HTML代码和支持JavaScript

2.1 使用WebView浏览网页

​ 在Android程序中,WebView控件可以在XML布局文件中使用标签来添加,也可以在Java文件中通过new关键字来创建。

​ 通常会采用在XML布局文件中添加标签的形式,具体代码如下

<!--WebView控件的id-->
<WebView
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

​ 控件的常用方法如下表所示。

属性名称 功能描述
loadUrl(String url) 用于加载指定URL对应的网页
loadData(String data, String mimeType, String encoding) 用于将指定的字符串数据加载到浏览器中
loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding,String historyUrl) 基于URL加载指定的数据
capturePicture() 用于创建当前屏幕的快照
goBack() 用于执行后退操作,相当于浏览器上后退按钮的功能
goForward() 用于执行前进操作,相当于浏览器上前进按钮的功能
stopLoading() 用于停止加载当前页面
reload() 用于刷新当前页面
emulator.exe -list-avds
emulator.exe -avd Nexus_4_API_28 -dns-server 192.168.1.1
setprop net.dns1 192.168.1.1
setprop net.eth0.dns1 192.168.1.1
setprop net.eth0.gw 192.168.1.1

接下来通过一个案例来演示如何使用WebView控件加载网页,本案例的界面效果如下图所示。

CH9-网络编程

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

编写界面交互代码 webview\MainActivity.java

package cn.itcast.webview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.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.webView);
        webview.loadUrl("http://m.itheima.com/"); // 指定要加载的网页
    }
}

​ 在MainActivity中实现WebView控件浏览网页的功能,通过WebView控件的loadUrl()方法来加载指定的网页,主要代码如下。

WebView webview=(WebView)findViewById(R.id.webView); 
webview.loadUrl("http://www.itheima.com/"); 	//通过加载网页地址加载网页
	 需要在清单文件(AndroidManifest.xml)的< manifest>标签中<font color='cornflowerblue'>添加允许访问网络资源的权限</font>。

注 意

​ 如果想让上述WebView控件具备放大和缩小网页的功能,则需要对该控件进行如下设置:

//设置WebView控件支持使用屏幕控件或手势进行缩放
webview.getSettings().setSupportZoom(true);
//设置WebView控件使用其内置的变焦机制,该机制集合屏幕缩放控件使用
webview.getSettings().setBuiltInZoomControls(true);

2.2 使用WebView执行HTML代码

​ WebView类提供了loadData()和 loadDataWithBaseURL()方法加载HTML代码。当使用loadData()方法来加载带中文的HTML内容时会产生乱码,但是使用loadDataWithBaseURL()方法就不会出现这种情况。loadDataWithBaseURL()方法的定义方式如下:

CH9-网络编程

​ 接下来通过一个案例来演示如何使用WebView控件加载HTML代码,本案例的界面效果如下图所示。

CH9-网络编程

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

实现加载HTML的功能 webviewhtml\MainActivity.java

package cn.itcast.webviewhtml;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.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.webView);
        // 创建一个字符串构建器,将要显示的HTML内容放置在该构建器中
        StringBuilder sb = new StringBuilder();
        sb.append("<div>请选择您要学习的课程:</div>");
        sb.append("<ul>");
        sb.append("<li>新媒体课程</li>");
        sb.append("<li>大数据课程</li>");
        sb.append("<li>人工智能课程</li>");
        sb.append("</ul>");
        // 加载数据
//        null      表示默认的空白页面
//        sb.toString()     sb中的数据
//        "text/html"       指定要显示内容的MIME类型
        webview.loadDataWithBaseURL(null, sb.toString(), "text/html", "utf-8",
                null);
    }
}

2.3 设置WebView支持JavaScript

​ 为了解决WebView控件在默认情况下不支持JavaScript代码的问题,我们需要通过setJavaScriptEnabled()方法来设置WebView控件,使其可以支持JavaScript代码

WebSettings settings= webview.getSettings(); // 获取WebSettings对象
settings.setJavaScriptEnabled(true); 		//设置JavaScript可用
//使WebView控件显示带有JavaScript代码的提示框
webview.setWebChromeClient(new WebChromeClient());	

​ 接下来通过一个案例来演示如何使用WebView控件支持一个带有JavaScript代码的网页,本案例的界面效果如下图所示。

CH9-网络编程

CH9-网络编程

导入JS文件 src\main\assets\alert.html和alert.js

<!DOCTYPE html>
<html>
<head>
<title>alert.html</title>
<meta charset="UTF-8">
<meta name="content-type" content="text/html; charset=UTF-8">
</head>
<body>
	This is my HTML page.
	<br>
	<script type="text/javascript" src="alert.js"></script>
	<script type="text/javascript">
alert("我是一个消息提示框");
</script>
</body>
</html>
window.alert = function(msg, callback) {
	var div = document.createElement("div");
	div.innerHTML = "<style type=\"text/css\">"
			+ ".nbaMask { position: fixed; z-index: 1000; top: 0; right: 0; left: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); }                                                                                                                                                                       "
			+ ".nbaMaskTransparent { position: fixed; z-index: 1000; top: 0; right: 0; left: 0; bottom: 0; }                                                                                                                                                                                            "
			+ ".nbaDialog { position: fixed; z-index: 5000; width: 80%; max-width: 300px; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); background-color: #fff; text-align: center; border-radius: 8px; overflow: hidden; opacity: 1; color: white; }"
			+ ".nbaDialog .nbaDialogHd { padding: .2rem .27rem .08rem .27rem; }                                                                                                                                                                                                                         "
			+ ".nbaDialog .nbaDialogHd .nbaDialogTitle { font-size: 17px; font-weight: 400; }                                                                                                                                                                                                           "
			+ ".nbaDialog .nbaDialogBd { padding: 0 .27rem; font-size: 15px; line-height: 1.3; word-wrap: break-word; word-break: break-all; color: #000000; }                                                                                                                                          "
			+ ".nbaDialog .nbaDialogFt { position: relative; line-height: 48px; font-size: 17px; display: -webkit-box; display: -webkit-flex; display: flex; }                                                                                                                                          "
			+ ".nbaDialog .nbaDialogFt:after { content: \" \"; position: absolute; left: 0; top: 0; right: 0; height: 1px; border-top: 1px solid #e6e6e6; color: #e6e6e6; -webkit-transform-origin: 0 0; transform-origin: 0 0; -webkit-transform: scaleY(0.5); transform: scaleY(0.5); }               "
			+ ".nbaDialog .nbaDialogBtn { display: block; -webkit-box-flex: 1; -webkit-flex: 1; flex: 1; color: #09BB07; text-decoration: none; -webkit-tap-highlight-color: transparent; position: relative; margin-bottom: 0; }                                                                       "
			+ ".nbaDialog .nbaDialogBtn:after { content: \" \"; position: absolute; left: 0; top: 0; width: 1px; bottom: 0; border-left: 1px solid #e6e6e6; color: #e6e6e6; -webkit-transform-origin: 0 0; transform-origin: 0 0; -webkit-transform: scaleX(0.5); transform: scaleX(0.5); }             "
			+ ".nbaDialog a { text-decoration: none; -webkit-tap-highlight-color: transparent; }"
			+ "</style>"
			+ "<div id=\"dialogs2\" style=\"display: none\">"
			+ "<div class=\"nbaMask\"></div>"
			+ "<div class=\"nbaDialog\">"
			+ "	<div class=\"nbaDialogHd\">"
			+ "		<strong class=\"nbaDialogTitle\"></strong>"
			+ "	</div>"
			+ "	<div class=\"nbaDialogBd\" id=\"dialog_msg2\">弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内</div>"
			+ "	<div class=\"nbaDialogHd\">"
			+ "		<strong class=\"nbaDialogTitle\"></strong>"
			+ "	</div>"
			+ "	<div class=\"nbaDialogFt\">"
			+ "		<a href=\"javascript:;\" class=\"nbaDialogBtn nbaDialogBtnPrimary\" id=\"dialog_ok2\">确定</a>"
			+ "	</div></div></div>";
	document.body.appendChild(div);
 
	var dialogs2 = document.getElementById("dialogs2");
	dialogs2.style.display = 'block';
 
	var dialog_msg2 = document.getElementById("dialog_msg2");
	dialog_msg2.innerHTML = msg;
 
	// var dialog_cancel = document.getElementById("dialog_cancel");
	// dialog_cancel.onclick = function() {
	// dialogs2.style.display = 'none';
	// };
	var dialog_ok2 = document.getElementById("dialog_ok2");
	dialog_ok2.onclick = function() {
		dialogs2.style.display = 'none';
		callback();
	};
};

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/btn_dialog"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="执行JAVASCRIPT代码并弹出提示框"
        android:layout_margin="8dp"
        android:textColor="@android:color/white"
        android:background="@drawable/btn_dialog_selector"/>
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

创建背景选择器 res\drawable\btn_dialog_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/btn_dialog_selected"
        android:state_pressed="true" />
    <item android:drawable="@drawable/btn_dialog_normal" />
</selector>

实现加载JS代码功能 webviewjs\MainActivity.java

package cn.itcast.webviewjs;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final WebView webview = findViewById(R.id.webView);
        Button btn = findViewById(R.id.btn_dialog);
        webview.loadUrl("file:///android_asset/alert.html"); //指定要加载的网页
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 设置webview控件支持JavaScript代码
                webview.getSettings().setJavaScriptEnabled(true);
                // 显示网页中通过JavaScript代码弹出的提示框
                webview.setWebChromeClient(new WebChromeClient());
                webview.loadUrl("file:///android_asset/alert.html");
            };
        });
    }
}

三、JSON数据解析

目标

  • 掌握JSON数据的解析,能够通过不同的方式解析JSON数据

3.1 JSON数据

JSON数据的特点

(1)JSON即JavaScript Object Notation(对象表示法),是一种轻量级的数据交换格式

(2)JSON是基于纯文本的数据格式,它可以传输String、Number、Boolean类型的数据,也可以传输数组或者Object对象。

(3)JSON文件的扩展名为.json

(4)JSON分为JSON对象和JSON数组两种数据结构。

对象结构的JSON数据

​ 以“{”开始,以“}”结束。中间部分由0个或多个以“,”分隔的key:value对构成,注意关键字和值之间以“:”分隔。

​ 关键字key必须为String类型,值value可以是String、Number、Object、Array等数据类型。

CH9-网络编程

CH9-网络编程

数组结构的JSON数据

​ 以“[”开始,以“]”结束。中间部分由0个或多个以“,”分隔的值的列表组成。

值value可以是String、Number、Boolean、null等数据类型。

CH9-网络编程

CH9-网络编程

注意:

​ 使用JSON存储单个数据(如“abc”),一定使用数组结构,因为对象结构必须是由“key:value”的形式构成。

CH9-网络编程

3.2 JSON解析

两种解析方式

  • org.json
    • Android SDK中为开发者提供的,通过使用JSONObject和JSONArray两个类完成对JSON数据的解析。
  • Gson
    • 由Google公司提供的,在使用Gson库之前,首先需要将gson.jar添加到项目中,然后才能调用其提供的方法。

解析JSON对象

例如,要解析的JSON数据如下:

{ "name": "zhangsan", "age": 27, "married":true }         //json1 一个json对象
[{"name": "lisi","age": 25},{"name": "Jason","age": 20}]  //json2 一个json数组

使用JSONObject解析JSON对象

optXXX()方法在解析数据时比getXXX()方法更安全,如果对应字段不存在,optXXX()方法会返回空值或者0,而getXXX()方法会抛出异常。

JSONObject   jsonObj  =  new JSONObject(json1); 
String name = jsonObj.optString("name"); 
int age = jsonObj.optInt("age"); 
boolean married = jsonObj.optBoolean("married");

解析JSON数组

​ 使用JSONArray解析JSON数组:

数组的解析方法和对象类似,只是将key值替换为数组中的下标。

JSONArray jsonArray = new JSONArray(json2); 
for(int i = 0; i < jsonArray.length(); i++) {
     JSONObject jsonObj = jsonArray.getJSONObject(i);
     String name = jsonObj.optString("name"); 
     int age = jsonObj.optInt("age");
}

Gson库解析JSON数据

​ 例如,要解析的JSON数据如下(与org.json解析数据相同):

使用Gson库前,首先需要将gson.jar添加到项目中,并且创建JSON数据对应的实体类Person1与Person2,需要注意的是,实体类中的成员名称要与JSON数据中的key值一致

{ "name": "zhangsan", "age": 27, "married":true }         //json1 一个json对象
[{"name": "lisi","age": 25},{"name": "Jason","age": 20}]  //json2 一个json数组

使用Gson解析JSON对象

 Gson gson = new Gson(); 
 Person person1 = gson.fromJson(json1, Person1.class);	//将JSON数据转换成对象

使用Gson解析JSON数组

 Gson gson = new Gson(); 
//TypeToken是Google提供的一个解析JSON数据的类
 Type listType = new TypeToken<List<Person2>>(){}.getType();
 List<Person2> person2 = gson.fromJson(json2, listType);

Android Studio添加库文件

​ 在Android程序中添加库文件进行讲解,具体操作步骤如下:

  1. 在Android Studio中,选择【File】à【Project Structure…】选项,此时会弹出一个Project Structure窗口,如下图所示。

CH9-网络编程

  1. 选中Project Structure窗口中的【Dependencies】选项卡,接着单击该窗口右上角的“ ”,选择Library dependency选项,此时会弹出一个Choose Library Dependency窗口,在该窗口中找到Gson库com.google.code.gson:gson:2.8.5并选中,如下图所示。

CH9-网络编程

3.3 实战演练—仿拼多多砍价界面

​ 本节我们将通过仿拼多多砍价界面的案例来演示如何解析JSON数据并将数据显示到界面上。本案例的界面效果如下图所示。

CH9-网络编程

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginRight="20dp"
        android:background="@drawable/title_bg"
        android:gravity="center_vertical"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="25dp"
            android:text="一刀砍成卡"
            android:textColor="#ce4032"
            android:textSize="24sp"
            android:textStyle="bold" />
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_margin="20dp"
            android:background="#af560e" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="商品直接带回家"
            android:textColor="#875a1e"
            android:textSize="18sp"
            android:textStyle="bold" />
    </LinearLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

搭建商品的条目布局 res\layout\goods_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="230dp"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="20dp"
    android:background="@android:color/black"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/goods_bg"
        android:gravity="center_horizontal"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_count"
            android:layout_width="wrap_content"
            android:layout_height="27dp"
            android:layout_gravity="center_horizontal"
            android:gravity="center"
            android:padding="5dp"
            android:textColor="#573516"
            android:textSize="12sp" />
        <TextView
            android:id="@+id/tv_goods_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:textColor="#573516"
            android:textSize="16sp"
            android:textStyle="bold" />
        <ImageView
            android:id="@+id/iv_img"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginTop="10dp" />
        <Button
            android:id="@+id/btn_free"
            android:layout_width="110dp"
            android:layout_height="35dp"
            android:layout_margin="10dp"
            android:background="@drawable/btn_free_bg"
            android:text="点击免费拿"
            android:textColor="@android:color/white"
            android:textSize="14sp"
            android:textStyle="bold" />
    </LinearLayout>
</LinearLayout>

封装商品信息的实体类 pinduoduo\GoodsInfo.java

package cn.itcast.pinduoduo;
public class GoodsInfo {
    private int id;             // 商品id
    private String count;      // 已砍商品的数量
    private String goodsName; // 商品名称
    private String goodsPic;  // 商品图片
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getCount() {
        return count;
    }
    public void setCount(String count) {
        this.count = count;
    }
    public String getGoodsName() {
        return goodsName;
    }
    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }
    public String getGoodsPic() {
        return goodsPic;
    }
    public void setGoodsPic(String goodsPic) {
        this.goodsPic = goodsPic;
    }
}

编写商品列表的适配器 pinduoduo\GoodsAdapter.java

package cn.itcast.pinduoduo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

public class GoodsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext;
    private List<GoodsInfo> GoodsList = new ArrayList<>();

    public GoodsAdapter(Context context) {
        this.mContext = context;
    }

    /**
     * 获取数据更新界面
     */
    public void setData(List<GoodsInfo> GoodsList) {
        this.GoodsList = GoodsList;     //获取从Activity界面传递过来的数据GoodsList
        notifyDataSetChanged();
    }

//    inflate()方法加载布局文件
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = null;
        RecyclerView.ViewHolder holder = null;
        itemView = LayoutInflater.from(mContext).inflate(R.layout.goods_item, parent, false);
        holder = new MyViewHolder(itemView);
        return holder;
    }

//    数据绑定
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        GoodsInfo bean = GoodsList.get(position);
//        将已砍的商品数量和商品名称设置到界面控件上
        ((MyViewHolder) holder).tv_count.setText("已砍" + bean.getCount() + "件");
        ((MyViewHolder) holder).tv_goods_name.setText(bean.getGoodsName());
//        将商品图片数据设置到图片控件iv_img上
        Glide.with(mContext)
                .load(bean.getGoodsPic())
                .error(R.mipmap.ic_launcher)
                .into(((MyViewHolder) holder).iv_img);
    }

//    获取条目总数
    @Override
    public int getItemCount() {
        return GoodsList.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tv_count, tv_goods_name;
        ImageView iv_img;
        Button btn_free;

        public MyViewHolder(View view) {
            super(view);
            tv_count = view.findViewById(R.id.tv_count);
            tv_goods_name = view.findViewById(R.id.tv_goods_name);
            iv_img = view.findViewById(R.id.iv_img);
            btn_free = view.findViewById(R.id.btn_free);
        }
    }
}

实现商品显示功能 pinduoduo\MainActivity.java

package cn.itcast.pinduoduo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {
    private GoodsAdapter adapter;             // 列表的适配器
    public static final int MSG_GOODS_OK = 1; // 获取数据
    private MHandler mHandler;
    // 内网接口
    public static final String WEB_SITE = "http://172.16.43.20:8080/goods";
    // 商品列表接口
    public static final String REQUEST_GOODS_URL = "/goods_list_data.json";
    private RecyclerView rv_list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MHandler();
        init();
        initData();
    }

    private void init() {
        rv_list = findViewById(R.id.rv_list);
//        this 表示上下文
//        2     表示商品列表的每个条目中显示两条商品信息
        GridLayoutManager manager = new GridLayoutManager(this, 2);
//        将manager对象设置到控件rv_list上
        rv_list.setLayoutManager(manager);
        adapter = new GoodsAdapter(MainActivity.this);
//        将数据适配器的对象adapter设置到控件rv_list上
        rv_list.setAdapter(adapter);
    }

    private void initData() {
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(WEB_SITE +
                REQUEST_GOODS_URL).build();
        Call call = okHttpClient.newCall(request);
        // 开启异步线程访问网络,从服务器上获取商品列表的数据
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String res = response.body().string(); // 获取商品数据
                Message msg = new Message();
                msg.what = MSG_GOODS_OK;
                msg.obj = res;
                mHandler.sendMessage(msg);
            }

            @Override
            public void onFailure(Call call, IOException e) {
            }
        });
    }

    /**
     * 事件捕获
     */
    class MHandler extends Handler {
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            switch (msg.what) {
                case MSG_GOODS_OK:
                    if (msg.obj != null) {
//                        获取传递过来的JSON数据vlResult
                        String vlResult = (String) msg.obj;
                        // 解析获取的JSON数据vlResult,并将解析后的数据存放在集合goodsInfos中
                        List<GoodsInfo> goodsInfos = getGoodsList(vlResult);
//                        将集合goodsInfos设置到数据适配器的对象adapter中
                        adapter.setData(goodsInfos);
                    }
                    break;
            }
        }
    }

    public List<GoodsInfo> getGoodsList(String json) {
        Gson gson = new Gson(); // 使用gson库解析JSON数据
        // 创建一个TypeToken的匿名子类对象,并调用对象的getType()方法
        Type listType = new TypeToken<List<GoodsInfo>>() {
        }.getType();
        // 把获取到的集合数据存放到goodsInfos中
        List<GoodsInfo> goodsInfos = gson.fromJson(json, listType);
        return goodsInfos;
    }
}

3.4 安装配置Tomcat服务器

​ Tomcat运行稳定、可靠、效率高,不仅可以和目前大部分主流的Web服务器(如Apache、IIS服务器)一起工作,还可以作为独立的Web服务器软件。

1.下载Tomcat

​ 在Tomcat官网上下载apache-tomcat-8.5.59-windows-x64.zip文件,解压该文件可以看到Tomcat的目录结构,如下图所示。

CH9-网络编程

2. 启动Tomcat

在Tomcat安装目录的bin目录下,存放了许多脚本文件,其中startup.bat就是启动Tomcat的脚本文件,如下图所示。

CH9-网络编程

双击startup.bat文件,便会启动Tomcat服务器,Tomcat启动信息窗口如下图所示。

CH9-网络编程

Tomcat服务器启动后,在浏览器的地址栏中输入http://localhost:8080访问Tomcat服务器,如果浏览器中的显示Tomcat页面如下图所示,则说明Tomcat 服务器安装部署成功了。

CH9-网络编程

3. 关闭Tomcat

在Tomcat根目录下的bin文件夹中,运行shutdown.bat脚本文件即可关闭Tomcat或者直接关闭Tomcat启动信息窗口。

四、Handler消息机制

目标

  • 熟悉Handler消息机制的概述,能够归纳Handler消息机制的原理

Handler是一种异步回调机制,主要负责与子线程进行通信

Handler机制主要包括四个关键对象:

  • Message:是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

  • Handler:是处理者的意思,它主要用于发送消息和处理消息。

  • MessageQueue:是消息队列的意思,它主要用来存放通过Handler发送的消息。通过Handler发送的消息会存在MessageQueue中等待处理,每个线程中只会有一个MessageQueue对象。

  • Looper:是每个线程中的MessageQueue的管家。调用Looper的loop()方法后,就会进入到一个无限循环中。每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。

CH9-网络编程文章来源地址https://www.toymoban.com/news/detail-487174.html

到了这里,关于CH9-网络编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Qt网络编程】实现TCP协议通信

    传输控制协议(TCP,Transmission Control Protocol)是 一种面向连接的、可靠的、基于字节流的传输层通信协议 ,由IETF的RFC 793 定义。 TCP建立连接前,需要进行三次握手,如下图所示: TCP断开连接前,需要进行四次挥手,如下图所示: Qt中提供了QTcpSocket类和QTcpServer类分别用于创

    2024年02月16日
    浏览(39)
  • 【网络编程】深入了解UDP协议:快速数据传输的利器

    (꒪ꇴ꒪ ),Hello我是 祐言QAQ 我的博客主页:C/C++语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍 快上🚘,一起学习,让我们成为一个强大的攻城狮! 送给自己和读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,请在评论区指

    2024年02月09日
    浏览(38)
  • 网络编程day2——基于TCP/IP协议的网络通信

            计算机S                                                 计算机C      创建socket对象                                   创建socket对象      准备通信地址(自己的ip(非公网ip))      准备通信地址                                     (计算

    2024年02月10日
    浏览(51)
  • Java网络编程之IP,端口号,通信协议(UDP,TCP)

    ① C/S :客户端/服务器 在用户本地需要下载安装客户端程序,在远程有一个服务器端程序。 优点:画面精美,用户体验好 缺点:用户需要下载更新 ② B/S :浏览器/服务器 只需要一个浏览器,用户通过指定网址访问对应的服务器。 优点:不需要开发客户端,只需要页面+服务

    2024年02月03日
    浏览(49)
  • linux【网络编程】TCP协议通信模拟实现、日志函数模拟、守护进程化、TCP协议通信流程、三次握手与四次挥手

    Tcp通信模拟实现与Udp通信模拟实现的区别不大,一个是面向字节流,一个是面向数据报;udp协议下拿到的数据可以直接发送,tcp协议下需要创建链接,用文件描述符完成数据的读写 1.1.1 接口认识 1.1.1.1 listen:监听socket 1.1.1.2 accept:获取连接 通信就用accept返回的文件描述符,

    2024年02月06日
    浏览(41)
  • 网络编程——深入理解TCP/IP协议——OSI模型和TCP/IP模型:构建网络通信的基石

    TCP/IP协议,即 传输控制协议/互联网协议 ,是一组用于在计算机网络中实现通信的协议。它由两个主要的协议组成:TCP(传输控制协议)和IP(互联网协议)。TCP负责确保数据的可靠传输,而IP则负责路由数据包以在网络中传递。TCP/IP协议簇还包含其他辅助协议,如UDP(用户数

    2024年02月14日
    浏览(43)
  • python基于http的网络通信和网站端口暴露;Python网络编程之HTTP协议的python应用

    HTTP(Hypertext Transfer Protocol)即超文本传输协议,是Web应用程序使用的协议,在Web浏览器和Web服务器之间传递HTML页面和数据。HTTP是基于TCP/IP协议来传输数据的,是一种无状态的协议。 关键特点: 支持客户/服务器模式:Web浏览器作为HTTP客户端通过URL向HTTP服务器发送HTTP请求,

    2024年02月04日
    浏览(38)
  • 【深入浅出C#】章节 8: 网络编程和远程通信:网络编程和远程通信

    计算机网络是指连接多台计算机设备,通过通信链路共享资源和信息的系统。它构建了一个相互连接的世界,使得人们可以在不同地点进行数据交换和资源共享。网络编程是指在计算机网络中,使用编程语言进行通信和数据传输的技术。现代应用中,网络编程发挥着重要作用

    2024年02月12日
    浏览(49)
  • Java网络编程 - 网络编程介绍 - 网络通信三要素

    什么是网络编程 ? 网络编程可以让程序与网络上的其他设备中的程序进行数据交互。 网络编程基本模式 : 常见的通信模式有如下2种形式:Client-Server( CS: 客户端与服务器模式 ) 、 Browser/Server( BS: 浏览器与服务器模式 ) Client-Server(CS)模式 Browser/Server(BS)模式 实现网络编程关键的三

    2024年02月02日
    浏览(47)
  • Java 网络编程 —— 安全网络通信

    SSL(Secure Socket Layer,安全套接字层)是一种保证网络上的两个节点进行安全通信的协议。IETF(Interet Engineering Task Force)国际组织对 SSL 作了标准化,制定了 RFC2246 规范,并将其称为传输层安全(Transport Layer Security,TLS) SSL 和 TLS 都建立在 TCP/IP 的基础上,一些应用层协议,如

    2024年02月11日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包