Android开发--Lesson09--网络编程
Android网络编程的概念
HttpURLConnection
是 Java 提供的一个用于执行 HTTP 请求的类,它允许你通过 HTTP 或 HTTPS 协议与网络服务器进行通信。下面是 HttpURLConnection
的工作原理、执行原理以及执行流程的详细说明。
工作原理
HttpURLConnection
作为 Java 标准库的一部分,提供了一种简单的方式来发送和接收 HTTP 请求和响应。它封装了底层的网络通信细节,使开发者能够专注于构建请求和处理响应,而不需要深入了解 TCP/IP 或 HTTP 协议的具体实现。
主要功能
- 发送 HTTP 请求(GET, POST, PUT, DELETE等)
- 接收 HTTP 响应
- 管理连接状态(如设置超时时间)
- 处理输入输出流(读取响应数据、写入请求体)
执行原理
当你使用 HttpURLConnection
进行网络操作时,实际上是通过以下步骤来完成的:
- 建立连接:首先,你需要创建一个 URL 对象,并通过调用
openConnection()
方法获取一个HttpURLConnection
实例。 - 配置请求:根据需要设置请求的方法(GET, POST 等)、请求头(如 Content-Type)、超时时间等属性。
- 发送请求:如果是 POST 或 PUT 请求,则需要向服务器发送数据;可以通过
OutputStream
写入数据到服务器。 - 接收响应:一旦请求被发送出去,就可以通过
InputStream
来读取服务器返回的数据。 - 关闭连接:无论请求是否成功,都应当关闭连接以释放资源。
WebView
<WebView android:id="@+id/wv" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
在Android开发中,WebView
控件是一个非常强大的组件,它允许你在应用中嵌入网页内容。通过 WebView
,你可以加载远程的网页、显示在线资源或渲染本地HTML内容。以下是 WebView
的一些主要作用和用途:
- 使用
WebView
可以加载任何有效的URL,就像在浏览器中打开网页一样。这非常适合展示经常更新的内容或者需要频繁维护的信息,比如新闻文章、帮助文档等。
WebView webView = findViewById(R.id.webview);
webView.loadUrl("https://www.baidu.com");
- 除了加载远程网页之外,
WebView
还可以用来显示存储在设备上的HTML文件。这对于离线阅读或展示静态内容特别有用。
webView.loadUrl("file:///android_asset/filename.html");
需要注意的是 android_asset 指代的是assets包下面的静态资源文件,它只会扫描assets包下的文件,此包应该创建在app/src/main下
WebView
支持与JavaScript进行交互,使得开发者可以通过编写JavaScript代码来动态地控制网页内容,甚至可以从Java代码调用JavaScript函数,反之亦然。这为创建复杂的用户界面和功能提供了可能。
WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true);
只有配置上面的文件之后,才可以启动JS在andrid界面之上,对于一些大型网站,如百度这些网站必有JS文件,故而不开启上面的配置webView反而打开不了这个网站
WebView
的loadDataWithBaseURL
方法用于加载包含基础 URL 和历史记录标题的数据。这个方法对于需要从字符串加载 HTML 内容到 WebView 中非常有用,并且允许你指定一个基础 URL 来解析相对 URL 链接。
public void loadDataWithBaseURL (String baseUrl, String data, String mimeType, String encoding, String historyUrl)
- baseUrl:用于解析页面中的相对 URL 链接的基础 URL。如果为
null
或者为空字符串,则认为所有链接都是绝对的。 - data:要加载的 HTML 数据内容。
- mimeType:数据的 MIME 类型。通常为
"text/html"
。 - encoding:字符编码格式,如
"utf-8"
或"iso-8859-1"
。 - historyUrl:用于历史记录的 URL。可以是
null
。这影响了当用户使用“后退”按钮时的行为,如果提供了这个参数,它将作为加载内容的虚拟URL存入浏览器的历史记录中。
测试
测试注意点,需要先完成网络的相关配置:
测试如上的WebView提供的相关方法:
loadUrl加载assets文件夹的html:
WebView wv = findViewById(R.id.wv);
wv.loadUrl("file:///android_asset/qq_moment.html");
运行之后
测试loadDataWithBaseURL
WebView wv = findViewById(R.id.wv); String s = "<p><font color='red'>今天星期一</font></p>"; wv.loadDataWithBaseURL(null, s,null,"utf-8",null);
运行之后:
测试loadUrl并且开始JS
// 获取WebView对象 WebView wv = findViewById(R.id.wv); // 启用JavaScript wv.getSettings().setJavaScriptEnabled(true); // 设置WebChromeClient wv.setWebChromeClient(new WebChromeClient()); // 加载网页 wv.loadUrl("https://www.baidu.com");
运行测试
注意:loadDataWithBaseURL 和 loadUrl是对 WebView 同级加载,同时出现会发生覆盖的情况
HttpURLConnection加载网络资源
在android API10之后从网络加载资源就不允许在主线程中了,故而我们需要为其单独创建一个新的线程来加载网络资源
需要注意的是HttpURLConnection其实是Java的资源库实现的,故而Android的网络加载还是使用的Java的API
class MyThread extends Thread{ @Override public void run() { try { // 创建 URL 对象 URL url = new URL("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"); // 打开连接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置请求方法 conn.setRequestMethod("GET"); // 设置连接超时时间 conn.setConnectTimeout(5000); // 获取输入流 InputStream is = conn.getInputStream(); // 解码成 Bitmap bitmap = BitmapFactory.decodeStream(is); // 关闭资源 is.close(); conn.disconnect(); } catch (Exception e) { e.printStackTrace(); // 打印错误信息 Log.i("MyThread", "error:" + e.getMessage()); } } }
然后如上实现之后了就可以在主线程中启动这个线程,并且将其加载的bitmap图像加载在ImageView中
private Bitmap bitmap; private ImageView iv; //start()方法启动一个新的线程,run方法,在主线程普通运行方法 new MyThread().start(); iv = findViewById(R.id.iv); //设置bitmap到ImageView中 iv.setImageBitmap(bitmap);
点击运行
JSON数据解析
在 Android 开发中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它主要用于客户端与服务器之间的数据传输。Android 中的 JSON 数据解析指的是将从网络或其他来源获取的 JSON 格式字符串转换为 Java 对象或集合,以便于在应用中使用;反之亦然,即序列化 Java 对象为 JSON 字符串发送给服务器。
解析JSON数据需要使用到Goole的Gson开发工具包,可以在Gradle中导入
// 确保版本号是最新的 implementation 'com.google.code.gson:gson:2.8.9'
完成导入之后就可以调用其方法解析数据:
我们的JSON数据是:
解析JSON对象为Java对象需要为JSON格式对应一个实体类:
public class WeatherInfo { private String id; private String temp; private String weather; private String name; private String wind; @Override public String toString() { return "WeatherInfo{" + "id='" + id + '\'' + ", temp='" + temp + '\'' + ", weather='" + weather + '\'' + ", name='" + name + '\'' + ", wind='" + wind + '\'' + '}'; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTemp() { return temp; } public void setTemp(String temp) { this.temp = temp; } public String getWeather() { return weather; } public void setWeather(String weather) { this.weather = weather; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getWind() { return wind; } public void setWind(String wind) { this.wind = wind; } }
然后这个json数据是放在assets包下的
则可以使用getAssets()方法直接获得到这个包,然后打开包下对应的文件:
InputStream inputStream = getAssets().open("weather.json");
接下来可以使用一个创建一个WeatherService用来专门处理这里的json文件输入流:
public class WeatherService { // 从输入流中获取JSON数据,并解析为WeatherInfo对象列表 public static List<WeatherInfo> getJSON(InputStream is) throws Exception{ // 创建一个字节数组,用于存储从输入流中读取的数据 //is.available() 可不阻塞地从此输入流读取(或跳过)的字节数 byte[] buffer = new byte[is.available()]; // 从输入流中读取数据,并存储到字节数组中 is.read(buffer); // 关闭输入流 is.close(); // 将字节数组转换为字符串 String json = new String(buffer,"utf-8"); // 创建Gson对象 Gson gson = new Gson(); // 创建Type对象,用于指定解析后的数据类型 Type listType = new TypeToken<List<WeatherInfo>>(){}.getType(); // 使用Gson对象将JSON字符串解析为WeatherInfo对象列表 List<WeatherInfo> weatherInfos = gson.fromJson(json,listType); // 返回解析后的WeatherInfo对象列表 return weatherInfos; } }
接着在调用此对象的getJSON方法,将刚刚读取到的流传入,让其转换为我们定义的WeatherInfo的Java对象处理:
InputStream inputStream = getAssets().open("weather.json");
List<WeatherInfo> weatherInfoList = WeatherService.getJSON(inputStream);
然后就可以循环的读取这个list中的对象信息,并且将其输出到页面上:
TextView tv = findViewById(R.id.tv); try{ InputStream inputStream = getAssets().open("weather.json"); List<WeatherInfo> weatherInfoList = WeatherService.getJSON(inputStream); String s = ""; for (int i=0;i<weatherInfoList.size();i++){ s +="编号:"+weatherInfoList.get(i).getId() + ",城市:" + weatherInfoList.get(i).getName() + ",温度:" + weatherInfoList.get(i).getTemp() + ",天气:" + weatherInfoList.get(i).getWeather() + ",风力:" + weatherInfoList.get(i).getWind() + "\n"; } // 将拼接好的天气信息设置到 TextView 上显示 tv.setText(s); }catch (Exception e){ e.printStackTrace(); }
测试结果:
多学一招:解析JSON的其它方式
使用原生 org.json
Android SDK 自带了对 JSON 的支持,主要通过 JSONObject
和 JSONArray
类来实现。
- JSONObject: 用于表示一个对象(键值对的无序集合)。
- JSONArray: 用于表示一个数组(值的有序列表)。
String jsonData = "{\"name\":\"Tom\",\"age\":25}"; try { JSONObject jsonObject = new JSONObject(jsonData); String name = jsonObject.getString("name"); int age = jsonObject.getInt("age"); } catch (JSONException e) { e.printStackTrace(); }
-----END-----