Android入门第55天-在Android里使用OKHttp组件访问网络资源

news/2024/11/24 20:45:40/

简介

今天的课程开始进入高级课程类了,我们要开始接触网络协议、设备等领域编程了。在今天的课程里我们会使用OKHttp组件来访问网络资源而不是使用Android自带的URLConnection。一个是OKHttp组件更方便二个是OKHttp组件本身就带有异步回调功能。

下面就进入课程。

课程目标

我们的课程目标有4个点:

  1. 使用OKHttp组件;
  2. 使用OKHttp组件加载网络图片显示在APP的ImgView里;
  3. 使用OKHttp组件加载给定网页代码显示在ScrollView里;
  4. 使用OKHttp组件加载给定网页显示在WebView里;

以上过程都为异步加载。

代码前在gradle里要先声明对于OKHttp组件的引用

要使用OKHttp组件,我们必须要在build.gradle中加入以下语句:

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

 以下是加完上述语句后的build.gradle。

 访问网络资源需要给到APP以权限

我们因为要访问网络资源,因此我们需要给到APP以相应的权限。编辑AndroidManifest.xml文件,并加入以下两行声明。

    <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WAKE_LOCK" />

 加完后的AndroidManifest.xml长这样

 代码

菜单res\menu\pop_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><item android:id="@+id/menuItemDisplayPic" android:title="加载图片" /><item android:id="@+id/menuItemDisplayHtmlCode" android:title="加载网页代码" /><item android:id="@+id/menuItemDisplayHtmlPage" android:title="加载网页" />
</menu>

主UI界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><Buttonandroid:id="@+id/buttonShowMenu"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/textColor"android:layout_centerHorizontal="true"android:layout_marginTop="10dp"android:text="展示弹出菜单" /><ImageViewandroid:id="@+id/imgPic"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone" /><ScrollViewandroid:id="@+id/scroll"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"><TextViewandroid:id="@+id/htmlTxt"android:layout_width="wrap_content"android:layout_height="wrap_content" /></ScrollView><WebViewandroid:id="@+id/webView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

MainActivity

package org.mk.android.demo.http;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.ScrollView;
import android.widget.TextView;import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import okhttp3.OkHttpClient;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
public class MainActivity extends AppCompatActivity {private String TAG = "DemoOkHttp";private Button buttonShowMenu;private TextView htmlTxt;private ImageView imgPic;private WebView webView;private ScrollView scroll;private Bitmap bitmap;private String htmlContents;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);buttonShowMenu = (Button) findViewById(R.id.buttonShowMenu);htmlTxt = (TextView) findViewById(R.id.htmlTxt);imgPic = (ImageView) findViewById(R.id.imgPic);webView = (WebView) findViewById(R.id.webView);scroll = (ScrollView) findViewById(R.id.scroll);buttonShowMenu.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {PopupMenu popup = new PopupMenu(MainActivity.this, buttonShowMenu);popup.getMenuInflater().inflate(R.menu.pop_menu, popup.getMenu());popup.setOnMenuItemClickListener(new MenuItemClick());popup.show();}});}// 定义一个隐藏所有控件的方法:private void hideAllWidget() {imgPic.setVisibility(View.GONE);scroll.setVisibility(View.GONE);webView.setVisibility(View.GONE);}private class MenuItemClick implements PopupMenu.OnMenuItemClickListener {@Overridepublic boolean onMenuItemClick(MenuItem item) {String imgPath = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.alicdn.com%2Fi2%2F2542318073%2FO1CN01fJvTi029VTwR16EvP_%21%212542318073.jpg&refer=http%3A%2F%2Fimg.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1673938156&t=69e5ee87fbf4b81b5f6eea53ed5b5158";String htmlPagePath = "https://www.baidu.com";switch (item.getItemId()) {case R.id.menuItemDisplayPic:downLoadImgFromPath(imgPath);break;case R.id.menuItemDisplayHtmlCode:getHtmlAsync(htmlPagePath, 102);break;case R.id.menuItemDisplayHtmlPage:getHtmlAsync(htmlPagePath, 103);break;}return true;}}private Handler httpHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(@NonNull Message msg) {Log.i(TAG, ">>>>>>receive handler Message msg.what is: " + msg.what);switch (msg.what) {case 101:hideAllWidget();imgPic.setVisibility(View.VISIBLE);Log.i(TAG, "begin to show img from bitmap type's data");imgPic.setImageBitmap(bitmap);break;case 102:hideAllWidget();Log.i(TAG, "begin to show html contents");scroll.setVisibility(View.VISIBLE);Log.d(TAG, ">>>>>>htmlContents->\n" + htmlContents);htmlTxt.setText(htmlContents);break;case 103:hideAllWidget();Log.i(TAG, "begin to show html page in webview");webView.setVisibility(View.VISIBLE);Log.d(TAG, ">>>>>>htmlContents->\n" + htmlContents);webView.loadDataWithBaseURL("", htmlContents, "text/html", "UTF-8", "");break;}return false;}});/*** 使用okhttp 异步下载图片*/private void downLoadImgFromPath(String path) {OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(path).build();Log.i(TAG, ">>>>>>into doanloadImgFromPath method");try {Call call = client.newCall(request); // 使用client去请求call.enqueue(new Callback() { // 回调方法,>>> 可以获得请求结果信息InputStream inputStream = null;@Overridepublic void onFailure(Call call, IOException e) {Log.e(TAG, ">>>>>>下载失败", e);}@Overridepublic void onResponse(Call call, Response response) throws IOException {Log.i(TAG, ">>>>>>into onResponse method");try {inputStream = response.body().byteStream();Log.i(TAG, ">>>>>>the response code is: " + response.code());if (200 == response.code()) {bitmap = BitmapFactory.decodeStream(inputStream);Log.i(TAG, ">>>>>>sendEmptyMessage 101 to handler");httpHandler.sendEmptyMessage(101);} else {Log.i(TAG, ">>>>>>下载失败");}} catch (Exception e) {Log.e(TAG, ">>>>>>okHttp onResponse error: " + e.getMessage(), e);} finally {try {inputStream.close();} catch (Exception e) {}}}});} catch (Exception e) {Log.e(TAG, ">>>>>>OkHttp调用失败", e);}}//异步不需要创建线程private void getHtmlAsync(String path, int handlerCode) {OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(path).build();//请求的call对象Call call = client.newCall(request);//异步请求call.enqueue(new Callback() {//失败的请求@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {Log.e(TAG, ">>>>>>加载path失败", e);}//结束的回调@Overridepublic void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {//响应码可能是404也可能是200都会走这个方法Log.i(TAG, ">>>>>>the response code is: " + response.code());if (200 == response.code()) {try {ResponseBody responseBody = response.body();BufferedSource source = responseBody.source();source.request(Long.MAX_VALUE);Buffer buffer = source.buffer();Charset UTF8 = Charset.forName("UTF-8");htmlContents = buffer.clone().readString(UTF8);Log.i(TAG, ">>>>>>sendEmptyMessage " + handlerCode + " to handler");httpHandler.sendEmptyMessage(handlerCode);Log.i(TAG, "getAsyncHtmlGet成功");} catch (Exception e) {Log.e(TAG, ">>>>>>read htmlPage error: " + e.getMessage(), e);}}}});}
}

核心代码导读

我们使用的是

Call call = client.newCall(request);

它本身就是支持异步的一个调用。 然后在得到相应的Http报文后使用一个Handler向APP主界面发起改变界面中内容的调用。

这边有一点需要注意的是OKHttp在返回的response.body()这个API,在一次请求里只能被使用一次。即如果你已经有以下一句类似的调用:

inputStream = response.body().byteStream();

你就不能再在它以下的语句中调用一次response.body()了。

自己动一下手试试看效果吧。


http://www.ppmy.cn/news/6149.html

相关文章

HackTheBox Soccer 通过WebSockets进行SQL注入,Doas与Dstat插件提权

靶机网址&#xff1a; https://app.hackthebox.com/machines/Precious枚举 使用nmap枚举靶机 nmap -sC -sV 10.10.11.194机子开放了22&#xff0c;80和9091端口&#xff0c;我们本地dns解析这个域名 echo "10.10.11.194 soccer.htb" >> /etc/hosts然后fuzz…

基于Springboot+Mybatis+mysql+element-vue高校就业管理系统

基于SpringbootMybatismysqlelement-vue高校就业管理系统一、系统介绍二、功能展示1.用户登陆注册2.个人信息(学生端)3.查看企业岗位信息&#xff08;学生端&#xff09;4.我的应聘(学生端)5.学生信息管理&#xff08;辅导员&#xff09;6.三方协议书审核&#xff08;辅导员&am…

IDEA创建kotlin项目

今天新建了一个kotlin项目&#xff0c;竟然不能导入jar包&#xff0c;原因是新建项目的时候&#xff0c;选择了kotlin作为Gradle的开发语音&#xff0c;kotlin语音里面&#xff0c;下面这行配置识别不了&#xff1a; implementation fileTree(dir: libs, include: [*.jar])所以…

《编译原理》实验一:熟悉实验环境VSCode并完成正则表达式转换为NFA

目录 实验一 熟悉实验环境VSCode并完成正则表达式转换为NFA 一、实验目的 二、预备知识 三、实验内容 VSCode的基本使用方法 安装和启动VSCode VSCode的窗口布局 使用VSCode将项目克隆到本地磁盘 使用VSCode登录平台 查看项目中的文件 实验源代码 演示程序的执行过程 四、实验过…

快速部署PHP Web环境(nginx php mysql redis)

先看最终效果&#xff0c;如下&#xff1a; 它是什么&#xff1f; 它是 docker 容器虚拟化技术。总共只有几KB大小的描述文件&#xff0c;文件里定义了要安装什么、配置什么&#xff0c;一执行就全自动处理好了。 它有什么用&#xff1f; 解决新来同事搭环境搭半天的问题解…

概要设计说明书(GB8567——88)基于协同的在线表格forture-sheet

概要设计说明书 1引言 1.1编写目的 为了帮助用户更好的了解和使用本在线表格&#xff0c;提高用户与软件的亲和度。 用户手册描述配置和使用改在线表格&#xff0c;以及该软件使用过程中应该注意的一下问题。 1.2背景 说明&#xff1a; 本用户手册所描述的软件系统的名称…

Mycat2(一)简介、分库分表概念

文章目录mycat是什么&#xff1b;为什么要用&#xff1b;mycat的作用原理分库分表的意义数据库优化的层次&#xff1a;数据切分的方式&#xff0c;带来的问题和解决方案分库分表带来的问题mycat的特性与详细配置含义mycat2与mycat1.6区别mycat2映射模型多数据源解决方案mycat核…

数字三角形问题

数字三角形问题一、题目描述二、题目分析1、问题分析2、思路分析&#xff08;1&#xff09;状态转移方程状态表示状态转移&#xff08;2&#xff09;循环的设计三、代码实现一、题目描述 二、题目分析 1、问题分析 这道题给我们的第一眼感觉就是情况太多了&#xff0c;太复杂…