安卓app、微信小程序等访问多个api时等待提示调用与关闭问题

安卓app、微信小程序访问webapi,将需要一时间,我们称之为耗时操作,其它诸如密集型计算、访问文件与设备等亦是如此。在这个期间我们应该跳出提示,告知用户正在等待,并且很多时候,在等待时不允许用户再对UI进行操作,直到耗时操作结束(无论是否成功,下同)
在安卓app中可以定义一个继承自Dialog的“等待对话框 WaItDialog”,并且设置setCanceledOnTouchOutside(false),如此会设置一个“遮罩层”,这样,当在耗时操作开始前开启(Show)WaItDialog直到结束关闭(dismiss),用户就不能点击UI了。
微信小程序可以直接用wx.showLoading与wx.hideLoading,并将mask设为true,实现类似功能。
当我们只有一个耗时操作时,问题很容易,但如果是多个呢?下面便讲解如何在进行多个耗时操作时,开关等待提示的问题。我们以访问api为例,假定以下场景,访问三个api,第一个get请求、第二个post请求、第三个故意访问一个不存在的api。当其中遇到错误时,应不能影响其它api的响应。所以我们需要先分别建立一个get请求的api与post请求的api。你可以任意语言来实现接口,我这里用传统的asp.net frameworks(visault studio 2019有asp.net core,可以跨平台,而frameworks只能在windows部署,请注意区分) 的一般处理程序(ashx)来实现。
第一个get请求的api

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace WebApi
{/// <summary>/// HellloHandler 的摘要说明/// </summary>public class HellloHandler : IHttpHandler{public void ProcessRequest(HttpContext context){context.Response.ContentType = "text/plain";if ( context.Request.QueryString["name"]!=null){context.Response.Write("你好"+ context.Request.QueryString["name"].ToString());}else{context.Response.Write("Hello World");}}public bool IsReusable{get{return false;}}}
}

第二个post请求api
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApi
{
///
/// PostHandler 的摘要说明
///
public class PostHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context){context.Response.ContentType = "text/plain";// context.Response.Write("Hello World");if (context.Request.HttpMethod != "POST"){context.Response.Write("非法请求");return;}string name = context.Request.Form["name"];if (string.IsNullOrEmpty(name)){context.Response.Write(" hello Post");}else{context.Response.Write("post:"+name);}}public bool IsReusable{get{return false;}}
}

}
接下来,就可以实现微信小程序、安卓app的访问了。
微信小程序,是单线程的,实现较为简单,因为我们要访问三个api,所以总数设为3,然后定义m=0 当wx.request complete时m+1,当m>=3时表示,所以三个api访问结束,调用 wx.hideLoading。注意在调试阶段,请勾选不校验合法域名选项。

  wxml代码
<!--pages/index/index.wxml-->
<view class="container">
<view>{{view1}}</view>
<view>{{view2}}</view>
<view>{{view3}}</view>
</view>

js代码,注意将接口地址替换为你自己实际的地址

Page({/*** 页面的初始数据*/data: {view1: '',view2: '',view3: '',errors: [] // 用于存储错误信息},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.getMultipleApis();},completeCount: 3,m:0,gethelloapi() //get请求{var that=this;wx.request({url: 'http://192.168.2.102:59597/HellloHandler.ashx?name=Jim',success:function(res){var data=""if (res.statusCode==200){data=res.data}else{data="http错误:"+res.statusCode}console.log("get"+data)that.setData({view1:data,},)},fail:function(e){that.setData({view1:e.message})},complete:function(){that.m++;if (that.m>=that.completeCount){wx.hideLoading();}}},)},getpostoapi() //post请求{var that=this;wx.request({url: 'http://192.168.2.102:59597/PostHandler.ashx',method:"POST",header: {'content-type': 'application/x-www-form-urlencoded'  // 关键设置},data:{name:'WangHua',},success:function(res){var data=""if (res.statusCode==200){data=res.dataconsole.log("接收"+data)}else{data="http错误:"+res.statusCode}that.setData({view2:data,},console.log("应答"+res.statusCode))},fail:function(e){that.setData({view2:e.message})},complete:function(){that.m++;if (that.m>=that.completeCount){wx.hideLoading();}}},)},getnoexistapi() //不存在的请求{var that=this;wx.request({url: 'http://192.168.2.102:59597/NoExistHandler.ashx?name=Lucy',success:function(res){var data=""if (res.statusCode==200){data=res.data}else{data="http错误:"+res.statusCode}that.setData({view3:data,},console.log("应答"+res.statusCode))},fail:function(e){that.setData({view3:e.message})},complete:function(){that.m++;if (that.m>=that.completeCount){wx.hideLoading();}}},)},// 处理多个不同类型的API请求getMultipleApis() {// 显示加载提示wx.showLoading({title: '加载中...',mask: true});this.gethelloapi();this.getpostoapi();this.getnoexistapi();}})

接下来安卓app代码,安卓不允许在主线程,要用分线程来调用,分线程又不能操控UI,另外分线程还有考虑共享资源的安全访问,所以情况要比微信小程序复杂多,在编写代码前我们要做一些准备设置。
第一步要在AndroidManifest添加相关网络权限。



并且因为是调试下进行,还要application节点下,设置android:usesCleartextTraffic=“true”(默认网络访问必须https,ftps等有ssl的接口,设置此选项后可以解除限定)。
第二步,在Build.gradle引入okthhp(用来访问网络)、我封装好的WaitDialog.aar的包以及Glide (我在WaitDialog引用了Glide ,一个图片加载库)。
做完准备设置,就是代码了
布局文件

<?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"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="get api"android:id="@+id/BtnApi"/>
<TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/TV1"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/TV2"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/TV3"/></LinearLayout>

Java代码,这里有两个要注意的地方,前面也提及过。一是分线程不能操作UI,要在runOnUiThread中操作,二是,分线程安全访问共享资源的问题,我们不能直接像微信小程序一样m++来增加“计数器”。我们可以通过AtomicInteger类实现安全访问共享资源,实现类似m++的功能,以上两点代码都会体现。
package person.yin.mutiapi;

import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import org.json.JSONObject;import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.atomic.AtomicInteger;import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import swaddle.yinzhenwei.waitdialog.WaitDialog;public class MainActivity extends AppCompatActivity implements View.OnClickListener{private WaitDialog waitDialog;private Button btnapi;private String TAG="APITest";private TextView tv1;private  TextView tv2;private  TextView tv3;private AtomicInteger requestCounter = new AtomicInteger(0);private static final int apicount=3; //最大三个api访问@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv1=findViewById(R.id.TV1);tv2=findViewById(R.id.TV2);tv3=findViewById(R.id.TV3);findViewById(R.id.BtnApi).setOnClickListener(this);}//***************private  void test(){waitDialog=new WaitDialog(this);waitDialog.setText("查询中,稍候");waitDialog.show();waitDialog.show();requestCounter.set(0);gethelloapi("Bill",tv1);getpostapi("Bob",tv2);getnoexistapi("Liu",tv3);}private void gethelloapi(String name,TextView tv) //访问helloapi get请求{OkHttpClient client = new OkHttpClient.Builder().build();RequestBody rbody = new FormBody.Builder().add("username", "admin").add("password", "12345").build();Request request = new Request.Builder().url("http://192.168.2.102:59597/HellloHandler.ashx?name="+name).post(rbody)
//                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36")
//                .header("Accept", "text/plain") // 匹配服务器响应类型
//                .header("Connection", "close") // 避免长连接问题.build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e(TAG, "请求失败: " + e);// e.printStackTrace();// 获取完整的堆栈信息StringWriter sw = new StringWriter();//e.printStackTrace(new PrintWriter(sw));Log.e(TAG, "完整异常信息: " + sw.toString());runOnUiThread(() ->{tv.setText("网络出现错误: " + e.getMessage());requestCounter.incrementAndGet();checkAllRequestsCompleted();});}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 打印完整的响应信息用于调试Log.d(TAG, "收到响应: " + response.code());if (!response.isSuccessful()) {String errorBody = response.body() != null ? response.body().string() : "无响应体";Log.e(TAG, "HTTP错误 " + response.code() + ": " + errorBody);runOnUiThread(() ->{tv.setText("HTTP错误: " + response.code() );requestCounter.incrementAndGet();checkAllRequestsCompleted();});return;}String responseData = response.body().string();Log.d(TAG,  responseData);runOnUiThread(() ->{//textViewResult.setText( responseData);tv.setText(responseData);requestCounter.incrementAndGet();checkAllRequestsCompleted();});}});}private void getnoexistapi(String name,TextView tv) //故意访问一个不存在api{OkHttpClient client = new OkHttpClient.Builder().build();RequestBody rbody = new FormBody.Builder().add("username", "admin").add("password", "12345").build();Request request = new Request.Builder().url("http://192.168.2.102:59597/NoExistHandler.ashx?name="+name).post(rbody)
//                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36")
//                .header("Accept", "text/plain") // 匹配服务器响应类型
//                .header("Connection", "close") // 避免长连接问题.build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e(TAG, "请求失败: " + e);// e.printStackTrace();// 获取完整的堆栈信息StringWriter sw = new StringWriter();//e.printStackTrace(new PrintWriter(sw));Log.e(TAG, "完整异常信息: " + sw.toString());runOnUiThread(() ->{tv.setText("网络出现错误: " + e.getMessage());requestCounter.incrementAndGet();checkAllRequestsCompleted();});}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 打印完整的响应信息用于调试Log.d(TAG, "收到响应: " + response.code());Log.v(TAG,"ok");if (!response.isSuccessful()) {String errorBody = response.body() != null ? response.body().string() : "无响应体";Log.e(TAG, "HTTP错误 " + response.code() + ": " + errorBody);runOnUiThread(() ->{tv.setText("HTTP错误: " + response.code() );requestCounter.incrementAndGet();checkAllRequestsCompleted();});return;}String responseData = response.body().string();Log.d(TAG,  responseData);runOnUiThread(() ->{//textViewResult.setText( responseData);tv.setText(responseData);requestCounter.incrementAndGet();checkAllRequestsCompleted();});}});}private void getpostapi(String name, TextView tv)  //访问postapi post请求{// 创建带调试信息的OkHttpClientOkHttpClient client = new OkHttpClient.Builder().build();RequestBody rbody = new FormBody.Builder().add("name", name).build();Request request = new Request.Builder().url("http://192.168.2.102:59597/PostHandler.ashx").post(rbody).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e(TAG, "请求失败: " + e);// e.printStackTrace();// 获取完整的堆栈信息StringWriter sw = new StringWriter();//e.printStackTrace(new PrintWriter(sw));Log.e(TAG, "完整异常信息: " + sw.toString());runOnUiThread(() ->{tv.setText("网络出现错误: " + e.getMessage());requestCounter.incrementAndGet();checkAllRequestsCompleted();});}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 打印完整的响应信息用于调试Log.d(TAG, "收到响应: " + response.code());if (!response.isSuccessful()) {String errorBody = response.body() != null ? response.body().string() : "无响应体";Log.e(TAG, "HTTP错误 " + response.code() + ": " + errorBody);runOnUiThread(() ->{tv.setText("HTTP错误: " + response.code() );requestCounter.incrementAndGet();checkAllRequestsCompleted();});return;}String responseData = response.body().string();Log.d(TAG,  responseData);runOnUiThread(() ->{tv.setText( responseData);requestCounter.incrementAndGet();checkAllRequestsCompleted();});}});}private void checkAllRequestsCompleted() {if (requestCounter.get() >= apicount) {//runOnUiThread(this::dismissLoading);//runOnUiThread(()->waitDialog.dismiss());waitDialog.dismiss();}}@Overridepublic void onClick(View v){switch (v.getId()){case R.id.BtnApi:test();break;}}
}  	

至此所有代码均已完成,我打包了微信小程序和安卓app的代码,因为api接口可以用多种语言实现,就不打包了,如果需要复制黏贴吧。代码地址 https://download.csdn.net/download/wstcl/91725186?spm=1001.2014.3001.5503

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/94135.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/94135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个状态机如何启动/停止另一个状态机

一个状态机如何启动/停止另一个状态机 这个过程主要依赖于动作列表&#xff08;Action List&#xff09; 中的特定动作项和状态管理服务&#xff08;ARA::SM&#xff09;提供的API。 1. 通过动作列表&#xff08;Action List&#xff09;进行预配置控制 这是最常见的方式&#…

基于IPO智能粒子优化的IIR滤波器参数识别算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.部分程序 4.算法理论概述 5.完整程序 1.程序功能描述 IIR&#xff08;Infinite Impulse Response&#xff09;滤波器即无限冲激响应滤波器&#xff0c;其输出不仅与当前和过去的输入有关&#xff0c;还与过去的输出…

欧州服务器String 转 double 有BUG?

string 转 double 的常见问题通常与文化差异、格式解析或特殊值处理相关&#xff0c;而非框架本身的 “BUG”。以下是可能导致转换异常的常见场景及解决方案&#xff1a; 文化差异导致的解析问题 现象&#xff1a;同样的字符串&#xff08;如 “1.23” 或 “1,23”&#xff09;…

鸿蒙中网络诊断:Network分析

上面的图很熟悉吧 Network 面板的表格列出了所有请求&#xff0c;每一列都提供了关键信息&#xff1a; Name: 请求的资源名称和路径。 Status: HTTP 状态码&#xff08;诊断核心&#xff09;。200成功&#xff0c;304未修改&#xff08;缓存&#xff09;&#xff0c;404找不到…

HarmonyOS 实战:6 种实现实时数据更新的方案全解析(含完整 Demo)

摘要 在当下的应用开发中&#xff0c;用户体验越来越依赖“实时性”。消息要第一时间送达、订单状态要立刻刷新、数据变化不能延迟……这些需求推动了“实时数据更新”成为应用的必备功能。在鸿蒙系统&#xff08;HarmonyOS&#xff09;中&#xff0c;我们既可以用系统内置的数…

第十六届蓝桥杯青少组C++省赛[2025.8.10]第二部分编程题(4、矩阵圈层交错旋转)

参考程序&#xff1a;#include <bits/stdc.h> using namespace std;const int MAXN 105; int a[MAXN][MAXN];int main() {int n;if (!(cin >> n)) return 0;for (int i 0; i < n; i)for (int j 0; j < n; j)cin >> a[i][j];int layers n / 2; // 每…

AI供应链情报预警 | 恶意Py包伪装AI框架库开展数据窃密及应用劫持攻击

AI供应链情报概述近日&#xff08;18th Aug. , 2025&#xff09;&#xff0c;悬镜安全情报中心在Python官方仓库中捕获1起伪装成知名AI框架库pytensor&#xff08;https://pypi.org/project/pytensor&#xff09;的组件投毒事件。在北京时间8月18日凌晨&#xff0c;投毒者连续发…

AI需要防火墙,云计算需要重新构想

Akamai创始人Tom Leighton欲终结云膨胀&#xff0c;从内到外守护AI安全 Akamai创始人Tom Leighton 当前超大规模云服务商主导着企业IT市场&#xff0c;鲜有人敢挑战云计算经济模式、AI基础设施和网络安全架构的现状。但Akamai联合创始人兼CEO Tom Leighton正是这样的挑战者。他…

线段树详解【数据结构】

简介 线段树是一种应用极其广泛&#xff0c;使用范围较广并且非常知名的树形数据结构&#xff0c;主要用于进行区间操作&#xff0c;如区间修改&#xff0c;区间查询等。这种数据结构唯一的不足就是巨大的代码量&#xff0c;因此处理一些较简单的问题时建议用树状数组。 原理…

Maven 入门与进阶:聚合、继承与生命周期详解

Maven 是 Java 项目管理的核心工具&#xff0c;其强大的依赖管理、项目构建和模块化设计能力&#xff0c;极大地提升了开发效率。本文将深入探讨 Maven 的 聚合&#xff08;Multi-module&#xff09;、继承&#xff08;Inheritance&#xff09; 和 生命周期&#xff08;Lifecyc…

手搓MCP客户端动态调用多MCP服务,调用哪个你说了算!

01 引言 前两天&#xff0c;有个粉丝朋友咨询MCP服务如何动态调用&#xff0c;动态加载MCP服务的链接&#xff1f;我们都知道MCP客户端可以配置多个MCP服务的地址&#xff1a; spring.ai.mcp.client.sse.connections.server1.urlhttp://localhost:xxxx spring.ai.mcp.client.ss…

Go语言中的优雅并发控制:通道信号量模式详解

在Go语言的并发编程中&#xff0c;“通过通信共享内存”的设计哲学贯穿始终。当面对高并发场景时&#xff0c;无限制创建goroutine可能导致资源耗尽、CPU过载等问题&#xff0c;通道信号量模式&#xff08;Channel Semaphore Pattern&#xff09; 正是一种基于Go通道特性的优雅…

鸿蒙 NEXT开发中轻松实现人脸识别功能

大家好&#xff0c;我是 V 哥。 今天给大家介绍在 HarmonyOS 原生鸿蒙开发中&#xff0c;实现人脸识别功能&#xff0c;这个功能在常用的 APP 开发中上镜率还是很高的&#xff0c;在传统的 Android 或 iOS 开发中&#xff0c;通常我们要借助第三方库来实现&#xff0c;而在鸿蒙…

华为开发者空间训练营-优秀作品公布

排名标题总分奖品1手把手教你开发一个地区智能查询MCP&#xff0c;赋能地理位置类MCP服务的“零输入”无感交互95华为 freebuds 6i 蓝牙耳机2基于华为开发者空间云主机DeepSeek助力电商企业AI海报文案驱动的最佳实践落地 94华为 freebuds 6i 蓝牙耳机32小时基于华为开发者空间和…

基于Python与Tkinter开发的微博多功能自动化助手

文章目录 摘要 1. 背景与意义 2. 需求分析 3. 核心架构设计 3.1. 技术选型 3.2. 核心思想:UI与逻辑分离的异步架构 4. 深度模块化剖析 4.1. 微博核心API交互模块 4.2. 健壮性设计:代理与重试机制 4.3. GUI界面模块 (WeiboApp 类) 4.4. 异步任务处理模块 5. 难点分析与解决方案…

效果驱动复购!健永科技RFID牛场智能称重项目落地

近日&#xff0c;北京某养殖企业持续下单电子耳标识读器&#xff0c;在牛场智能称重中落地应用&#xff0c;通过自动、准确地识别牛只并记录体重数据&#xff0c;显著提升效率和数据精准度&#xff0c;实现了“效果驱动复购”的良性循环。健永科技RFID技术在北京某养殖企业智能…

计算机网络:2、TCP和UDP

2、TCP和UDP 简介 TCP(transmission Control Protocol)&#xff1a;是一种通信标准&#xff0c;它使应用程序和计算设备能够在网络上交换消息。它的设计目的是在互联网上发送数据包&#xff0c;并确保数据和信息在网络上的成功传递。UDP(the User Datagram Protocol)&#xf…

WEB安全篇:浏览器攻击原理及防护

1、XSS&#xff1a;跨站脚本攻击就是攻击者想尽一切办法将可以执行的代码注入到网页中。攻击者在web页面恶意插入HTML或script标签&#xff0c;当用户浏览该页面时&#xff0c;恶意代码就会被执行&#xff0c;从而达到攻击的目的。XSS利用的是用户对指定网站的信任。比如&#…

汇编语言学习2---GNU Debugger (GDB)

学习记录&#xff0c;在汇编语言 &#xff0c;我们面对的是机器码&#xff08;以汇编指令形式展现&#xff09;&#xff0c;所以断点要设置在机器码被加载到内存中的位置。 GEF插件使用 安装插件wget -O ~/.gdbinit-gef.py -q https://gef.blah.cat/pyecho source ~/.gdbinit-g…

谈谈架构的内容

一、架构的定义架构是一个界定不清的东西&#xff0c;我们很难讲清楚哪些东西是架构&#xff0c;哪些东西不是架构。但软件行业里其实人人都在搞架构&#xff0c;软件设计就是架构本身。架构这个词出现得很早&#xff0c;有些人认为是 NASA&#xff08;也可能是NATO&#xff09…