当前位置: 首页 > news >正文

安卓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.dtcms.com/a/342214.html

相关文章:

  • 为什么会“偶发 539/500 与建连失败”
  • 如何通过传感器选型优化,为设备寿命 “续航”?
  • 微服务介绍及Nacos中间件
  • java⽇志体系
  • 桌面挂件不能承受之重——GIF
  • Windows 系统中,添加打印机主要有以下几种方式
  • 聚铭安全管家平台2.0实战解码 | 安服篇(四):重构威胁追溯体系
  • 新手向:Python开发简易网络服务器
  • 解决springai 项目中引入多个chatModel存在冲突问题
  • 服务器间大文件迁移
  • SparkSQL、FlinkSQL与普通sql比较
  • Git项目报错git@gitlab.com: Permission denied (publickey).【已解决】
  • Jenkins+GitLab在CentOS7上的自动化部署方案
  • iOS混淆工具实战 金融支付类 App 的安全防护与合规落地
  • 飞牛系统总是死机,安装个工具查看一下日志
  • Python爬虫的基础启航
  • 微算法科技(NASDAQ:MLGO)构建去中性化区块链预言机,实现跨链信息互通
  • 消息中间件(RocketMQ+RabbitMQ+Kafka)
  • 14. 多线程(进阶1) --- 常见的锁策略和锁的特性
  • 大模型自我进化框架SE-Agent:开启软件工程自动化新时代
  • Confluent 实时代理:基于 Kafka 流数据的创新实践
  • git 常用命令整理
  • 拂去尘埃,静待花开:科技之笔,勾勒城市新生
  • Linux基础(1) Linux基本指令(二)
  • 大模型推理并行
  • 机器学习7
  • 以往内容梳理--HRD与MRD
  • 《深入探索 Java IO 流进阶:缓冲流、转换流、序列化与工具类引言》
  • 事件驱动流程链——EPC
  • Metrics1:Intersection over union交并比