【安卓笔记】RxJava的使用+修改功能+搭配retrofit+RxView防快速点击

0. 环境:

电脑:Windows10

Android Studio: 2024.3.2

编程语言: Java

Gradle version:8.11.1

Compile Sdk Version:35

Java 版本:Java11

1. 介绍RxJava

GitHub开源地址:https://github.com/ReactiveX/RxJava

依赖库:(两个都要)

implementation "io.reactivex.rxjava3:rxjava:3.1.10"

implementation "io.reactivex.rxjava3:rxandroid:3.0.2"

Rx即为响应式思想。GitHub上、网络上已经有很多介绍了。这边不赘述。

2. 使用RxJava加载图片案例

功能拆解:

1. 获得图片地址
2. 拿到图片地址后,下载图片。2.1下载为耗时操作,需要loading框2.2 通过网络请求,下载图片
3. 下载完成后,dismiss loading,并且使用imageView显示出来3.1 隐藏loading框3.2 imageView setImage

根据这个功能,来写代码:(了解观察者、被观察者、整条逻辑链路)

String PATH = "https://c-ssl.dtstatic.com/uploads/blog/202405/03/73SmDPGxIeB0Gel.thumb.1000_0.jpg"; // 图片地址
ProgressDialog progressDialog; //loading可以改为自定义的loading框
public void rxJavaDownloadImage() {// observable 为被观察者。被观察者为图片地址StringObservable.just(PATH)// 拿到图片地址后,通过网络请求下载图片.map(new Function<String, Bitmap>() {@Overridepublic Bitmap apply(String s) throws Throwable {// 网络下载图片URL url = new URL(PATH);HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout(5000);int responseCode = httpURLConnection.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {InputStream inputStream = httpURLConnection.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(inputStream);return bitmap;} else {Log.i("TAG", "apply: " + responseCode);}return null;}}).subscribeOn(Schedulers.io()) //切换到子线程.observeOn(AndroidSchedulers.mainThread()) // 将观察者,切换到主线程.subscribe(// observer为观察者,观察上一个动作结束时的结果new Observer<Bitmap>() {//订阅刚开始时@Overridepublic void onSubscribe(@NonNull Disposable d) {//加载loading框progressDialog = new ProgressDialog(getActivity());progressDialog.setTitle("downloading...");progressDialog.show();}// 获取到上个事件的结果时@Overridepublic void onNext(@NonNull Bitmap bitmap) {// imageView setBitmapbinding.imageView.setImageBitmap(bitmap);}// 出现错误时@Overridepublic void onError(@NonNull Throwable e) {// 如果出现错误,则显示裂开图片 error.pngif (progressDialog != null) {progressDialog.dismiss();}Log.i("----log----", "onError: ");e.printStackTrace();}// 事件结束时@Overridepublic void onComplete() {// 隐藏loading框if (progressDialog != null) {progressDialog.dismiss();}}});
}

我们再来回顾一下刚刚拆解的功能:

// 这边设置成常量PATH,实际应用中为变量
// Observable.just(PATH) 传递给下一个卡片String对象
1. 获得图片地址。// 在 .map(new Function<String, Bitmap>() 中操作,并且传递给下一个卡片bitmap对象
2. 拿到图片地址后,下载图片。// 这边使用ProgressDialog,实际应用中,会使用自定义UI// 在onSubscribe中操作,即订阅开始时2.1下载为耗时操作,需要loading框// 这边使用HttpURLConnection,实际应用中,会使用网络框架2.2 通过网络请求,下载图片// 在 subscribe中,new Observer<Bitmap>()新建一个观察者,用于观察上一个卡片给的bitmap对象
3. 下载完成后,dismiss loading,并且使用imageView显示出来// 在onComplete中操作,即事件完成时、事件结束时。3.1 隐藏loading框// 这边使用了binding来操作:binding.imageView.setImageBitmap(bitmap);详情请框ViewBinding框架// 在onNext中操作,即拿到上一张卡片给的bitmap对象3.2 imageView setImage

当然,代码中的方法:rxJavaDownloadImage(),我们通过按钮的点击事件来实现就好了。

这样,就完成了RxJava来加载图片的简单功能。

3. RxJava的修改案例

仅仅只是使用,还不够。

3.1 增加需求时的修改(了解.map)

此时有一个新需求:需要给图片增加水印。又该如何修改呢?

功能拆解

1. 获得图片地址
2. 拿到图片地址后,下载图片。2.1下载为耗时操作,需要loading框2.2 通过网络请求,下载图片
3. 下载完成后,dismiss loading,3.1 隐藏loading框
4. 给图片设置水印,并且使用imageView显示出来 //显示图片之前,增加“设置水印”的动作4.1 设置水印 //增加设置水印的动作4.2 imageView setImage

增加水印的功能,只需要在下载完图片后,插入“给图片增加水印”的map即可

// 增加水印的卡片
.map(new Function<Bitmap, Bitmap>() {@Overridepublic Bitmap apply(Bitmap bitmap) throws Throwable {// 在这里增加自定义的水印Paint paint = new Paint();paint.setTextSize(88);paint.setColor(Color.RED);return drawTextToBitmap(bitmap, "水印设置", paint, 88, 88);}
})

 完整代码如下:

    String PATH = "https://c-ssl.dtstatic.com/uploads/blog/202405/03/73SmDPGxIeB0Gel.thumb.1000_0.jpg"; // 图片地址ProgressDialog progressDialog; //loading可以改为自定义的loading框public void rxJavaDownloadImage() {// observable 为被观察者。被观察者为图片地址StringObservable.just(PATH)// 拿到图片地址后,通过网络请求下载图片.map(new Function<String, Bitmap>() {@Overridepublic Bitmap apply(String s) throws Throwable {// 网络下载图片URL url = new URL(PATH);HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout(5000);int responseCode = httpURLConnection.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {InputStream inputStream = httpURLConnection.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(inputStream);return bitmap;} else {Log.i("TAG", "apply: " + responseCode);}return null;}})// 增加水印的卡片.map(new Function<Bitmap, Bitmap>() {@Overridepublic Bitmap apply(Bitmap bitmap) throws Throwable {// 在这里增加自定义的水印Paint paint = new Paint();paint.setTextSize(88);paint.setColor(Color.RED);return drawTextToBitmap(bitmap, "水印设置", paint, 88, 88);}}).subscribeOn(Schedulers.io()) //切换到子线程.observeOn(AndroidSchedulers.mainThread()) // 将观察者,切换到主线程.subscribe(// observer为观察者,观察上一个动作结束时的结果new Observer<Bitmap>() {//订阅刚开始时@Overridepublic void onSubscribe(@NonNull Disposable d) {//加载loading框progressDialog = new ProgressDialog(getActivity());progressDialog.setTitle("downloading...");progressDialog.show();}// 获取到上个事件的结果时@Overridepublic void onNext(@NonNull Bitmap bitmap) {// imageView setBitmapbinding.imageView.setImageBitmap(bitmap);}// 出现错误时@Overridepublic void onError(@NonNull Throwable e) {// 如果出现错误,则显示裂开图片 error.pngif (progressDialog != null) {progressDialog.dismiss();}Log.i("----log----", "onError: ");e.printStackTrace();}// 事件结束时@Overridepublic void onComplete() {// 隐藏loading框if (progressDialog != null) {progressDialog.dismiss();}}});}/*** 增加水印的函数。(不是这篇文章的重点)* @return bitmap*/public static Bitmap drawTextToBitmap(Bitmap bitmap,String gText,Paint paint,int x,int y) {android.graphics.Bitmap.Config bitmapConfig =bitmap.getConfig();if(bitmapConfig == null) {bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;}bitmap = bitmap.copy(bitmapConfig, true);Canvas canvas = new Canvas(bitmap);Rect bounds = new Rect();paint.getTextBounds(gText, 0, gText.length(), bounds);canvas.drawText(gText, x, y, paint);return bitmap;}

我们可以发现:需要增加功能,仅仅只需要在该链路中增加一个.map来修改,完全不会破坏原有的代码逻辑。而且该map也可以直接复制到其他代码去使用。这个就是优势了

3.2 封装相同代码(了解ObservableTransformer)

我们发现,每一条逻辑都会包含线程切换。相同代码比较多。我们可以将其进行封装

引入一个ObservableTransformer<Upstream, Downstream>对象

 查阅源码发现,ObservableTransformer 需要compose接口来调用。

Upstream:上游

Downstream:下游

所以,我们可以封装代码:

private final static <UD>ObservableTransformer<UD, UD> rxud() {return new ObservableTransformer<UD, UD>() {@Overridepublic @NonNull ObservableSource<UD> apply(@NonNull Observable<UD> upstream) {return upstream.subscribeOn(Schedulers.io()) //切换到子线程.observeOn(AndroidSchedulers.mainThread()) // 将观察者,切换到主线程;.map(new Function<UD, UD>() {@Overridepublic UD apply(UD ud) throws Throwable {// 甚至可以增加日志功能,此处为伪代码System.out.println("图片下载的时间" + System.currentTimeMillis());return ud;}});}};
}

可以看到return返回值 就是上游切换为子线程,下游切换为主线程。同时,我甚至可以在封装代码中,增加“日志功能”的卡片。这样每次下载图片的时间,都会被记录到日志当中。

要如何使用封装代码呢?使用.compose(rxud())即可。

请看下面的示例:

public void rxJavaDownloadImage() {// observable 为被观察者。被观察者为图片地址StringObservable.just(PATH)// 拿到图片地址后,通过网络请求下载图片.map(new Function<String, Bitmap>() {@Overridepublic Bitmap apply(String s) throws Throwable {// 网络下载图片URL url = new URL(PATH);HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout(5000);int responseCode = httpURLConnection.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {InputStream inputStream = httpURLConnection.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(inputStream);return bitmap;} else {Log.i("TAG", "apply: " + responseCode);}return null;}})// 增加水印的卡片.map(new Function<Bitmap, Bitmap>() {@Overridepublic Bitmap apply(Bitmap bitmap) throws Throwable {// 在这里增加自定义的水印Paint paint = new Paint();paint.setTextSize(88);paint.setColor(Color.RED);return drawTextToBitmap(bitmap, "水印设置", paint, 88, 88);}}).compose(rxud()) // 此处调用封装代码即可.subscribe(// observer为观察者,观察上一个动作结束时的结果new Observer<Bitmap>() {//订阅刚开始时@Overridepublic void onSubscribe(@NonNull Disposable d) {//加载loading框progressDialog = new ProgressDialog(getActivity());progressDialog.setTitle("downloading...");progressDialog.show();}// 获取到上个事件的结果时@Overridepublic void onNext(@NonNull Bitmap bitmap) {// imageView setBitmapbinding.imageView.setImageBitmap(bitmap);}// 出现错误时@Overridepublic void onError(@NonNull Throwable e) {// 如果出现错误,则显示裂开图片 error.pngif (progressDialog != null) {progressDialog.dismiss();}Toast.makeText(getActivity(), "download error", Toast.LENGTH_SHORT).show();Log.i("----log----", "onError: ");e.printStackTrace();}// 事件结束时@Overridepublic void onComplete() {// 隐藏loading框if (progressDialog != null) {progressDialog.dismiss();}}});}

这样我们就学会了封装代码。

后续开发过程中,如果出现功能A:下载图片、功能B:网络请求、 功能C:上传头像,我们都可以通过调用封装的代码来实现线程切换。

4. 网络请求替换成Retrofit

4.1 准备工作

依赖库:

// retrofit 核心依赖

implementation "com.squareup.retrofit2:retrofit:3.0.0"

// json解析工具依赖

implementation "com.squareup.retrofit2:converter-gson:3.0.0"

// rxjava转换处理工具

implementation "com.squareup.retrofit2:adapter-rxjava3:3.0.0"

项目api:即为网络请求接口

例子1:不带参数的网络请求

https://wanandroid.com/project/tree/json

例子2:带参数的网络请求

https://wanandroid.com/project/list/1/json?cid=294

其中,1为pageIndex;cid=294为body参数

4.2 创建bean

这里我使用插件(GsonFormatPlus)生成。没有安装过的,需要在marketplace搜索安装

 安装完成后,新建一个bean的Java文件,然后按快捷键,快捷键是alt+s (win), option + s(mac)

粘贴进json数据后,(左下角Setting可以自定义格式) 点完成OK,就会自动生成bean的内容

4.3 创建NetApi接口

比较简单,我直接贴代码:

package com.liosen.androidnote.api;import com.liosen.androidnote.bean.ItemBean;
import com.liosen.androidnote.bean.ProjectBean;import io.reactivex.rxjava3.core.Observable;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;public interface NetApi {// https://wanandroid.com/project/tree/json// 其中base为 wanandroid.com/// 所以只需要后续部分即可@GET("project/tree/json")Observable<ProjectBean> getProject();// https://wanandroid.com/project/list/1/json?cid=294// 1为动态页码,通过@Path 传参// cid为网址参数,通过@Query 传参@GET("project/list/{pageIndex}/json")Observable<ItemBean> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);
}

4.4 网络工具类

通过okhttp来进行网络请求。封装成工具类即可。

以下代码复制就好了。 

package com.liosen.androidnote.util;import com.google.gson.Gson;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;public class HttpUtils {public static String BASE_URL = "https://wanandroid.com/";public static Retrofit getOnlineCookieRetrofit() {OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();OkHttpClient client = httpBuilder.readTimeout(15, TimeUnit.SECONDS).connectTimeout(15, TimeUnit.SECONDS).writeTimeout(15, TimeUnit.SECONDS).build();return new Retrofit.Builder().baseUrl(BASE_URL)// okhttp请求.client(client)// rxJava 处理// 添加一个json解析工具.addConverterFactory(GsonConverterFactory.create(new Gson()))// 添加 RxJava处理工具.addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build();}
}

4.5 网络请求

    /*** 获取项目的网络请求*/public void getProjectHttp() {netApi.getProject().compose(rxud()) // 此处用到 3.2中封装的代码.subscribe(new Consumer<ProjectBean>() {@Overridepublic void accept(ProjectBean projectBean) throws Throwable {Log.i(TAG, "accept: " + projectBean);}});}/*** 获取item的网络请求*/public void getProjectItemHttp() {//实际项目中,需要传入这两个参数。暂时先用常量表示getProjectItemHttp(1, 294);}public void getProjectItemHttp(int pageIndex, int cid) {netApi.getProjectItem(pageIndex,cid).compose(rxud()) // 此处用到 3.2中封装的代码//同理,如果还封装了日志功能,此处一样可以插入卡片// .map() 这样插入即可。详情查看3.1.subscribe(new Consumer<ItemBean>() {@Overridepublic void accept(ItemBean itemBean) throws Throwable {Log.i(TAG, "accept: " + itemBean);}});}

 其中Consumer观察者为简易观察者,不像Observer一样,需要实现以下四种方法:

onSubscribe

onNext

onError

onComplete

仅需要实现accept() 即可。等同于onNext 

5. 防快速点击(RxJava实现)

5.1 依赖库

implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'

5.2 功能实现案例 

功能描述:点击button,点击事件触发获取项目信息的http

要求:防快速点击(防手指抖动)避免服务器连续收到http请求

代码关键部分:

// clicks 传入view, 也就是button这个view。此处是使用viewBinding框架
// Button btn = findViewById(R.id.button); 此处传入btn也是一样的
RxView.clicks(binding.buttonRequest).throttleFirst(2000, TimeUnit.MILLISECONDS) //防抖动,2秒内只响应第1次.subscribe(new Consumer<Unit>() {//此处的Unit可以不用接收@Overridepublic void accept(Unit unit) throws Throwable {// 网络请求,获取项目http。与getProjectHttp() 函数一样netApi.getProject().compose(rxud()).subscribe(new Consumer<ProjectBean>() {@Overridepublic void accept(ProjectBean projectBean) throws Throwable {Log.i(TAG, "accept: " + projectBean);// 此处可以通过获得的projectBean,继续请求Itemfor (ProjectBean.DataDTO data : projectBean.getData()) {getProjectItemHttp(1, data.getId());}}});}})
;

6. 写在最后

至此,我们学会了:

修改RxJava的修改(增加卡片、删除卡片)、

封装操作线程代码、

RxJava + Retrofit、

RxView实现防快速点击。

以上功能,基本上可以在项目中使用了。

关于RxJava,可以查看我其他文章:

【安卓笔记】RxJava的使用+修改功能+搭配retrofit+RxView防快速点击:https://blog.csdn.net/liosen/article/details/149340103

【安卓笔记】RxJava之flatMap的使用:https://blog.csdn.net/liosen/article/details/149343166

【安卓笔记】RxJava的onNextDo的使用:https://blog.csdn.net/liosen/article/details/149343321

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

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

相关文章

Windows 下原生使用 claude code + Kimi K2

搞定了kimi k2 claude code在windows下原生使用 Windows下使用claude code的障碍是shell环境&#xff08;命令行&#xff09;&#xff0c;非posix风格shell无法正常让claude code读取到url和key, 导致无法使用。解决问题的本质是使用符合posix风格的shell环境&#xff0c;我们…

Leetcode Easy题小解(C++语言描述)1

Leetcode Easy题小解&#xff08;C语言描述&#xff09; 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;**题目数据…

EP01:【NLP 第二弹】自然语言处理概述

一、NLP通向智能之路 1.1 图灵测试 1.1.1 提出背景 由计算机科学家阿兰・图灵于 1950 年提出&#xff0c;是早期衡量机器智能水平的重要概念。 1.1.2 提出目的 判断机器是否能表现出与人类相当的智能行为。 1.1.3 测试原理 场景设定&#xff1a;测试中存在一位人类测试者&#…

Ansible 查看PostgreSQL的版本

Ansible的基础知识就不说了直接贴剧本- name: Check PostgreSQL versionhosts: db_serversbecome: yesvars:ansible_python_interpreter: /usr/bin/python3db_name: postgresdb_user: postgresdb_password: your_passwordtasks:- name: Install psycopg2ansible.builtin.packag…

【视觉SLAM笔记】第9章 后端1

一、理论1. 状态估计的概率解释我们来深入探讨一下视觉SLAM中状态估计的概率解释。这可以说是理解现代SLAM算法&#xff08;尤其是后端优化&#xff09;的基石1. 问题的核心&#xff1a;不确定性SLAM&#xff08;同步定位与建图&#xff09;的本质是在一个未知环境中&#xff0…

(数据结构)复杂度

基本概念说明 数据结构 定义&#xff1a;数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有用途都有用&#xff08;要考虑适配、效率问题&#xff0c;在不同情况下使用合适的…

玩转Docker | 使用Docker部署bender个人导航页工具

玩转Docker | 使用Docker部署bender个人导航页工具 前言 一、bender介绍 Bender 简介 Bender 的主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署bender服务 下载bender镜像 编辑部署文件 创建容器 检查容器状态 检查服务端口 安全设置 四、…

解决了困扰我的upload靶场无法解析phtml等后缀的问题

本文章为解决困扰我的 upload 靶场无法解析 phtml 问题 ​ 这个问题直接让我过不了Upload-Pass-03这一关&#xff0c;一直卡着。 ​ 痛太痛了 &#xff0c;为什么无法解析上传之后的 phtml 后缀文件&#xff01;这块儿折磨了博主一天多&#xff0c;太不容易了&#xff0c;查找…

Leetcode百题斩-二分搜索

二分搜索也是一个很有趣的专题&#xff0c;被做过的题中&#xff0c;刚好一个Easy&#xff0c;一个Medium和一个Hard&#xff0c;刚好可以看看&#xff0c;二分搜索的三个难度等级都是啥样的。 124. Binary Tree Maximum Path Sum[Hard]&#xff08;详见二叉树专题&#xff09;…

【IDEA】格式化代码工具配置

格式化代码快捷键&#xff1a; CtrlAltL格式代码的时候不会再方法名与参数中间添加空格默认不勾选的情况下&#xff1a;代码样例&#xff1a;勾选之后的样例&#xff1a;选择不勾选&#xff0c;IDEA默认情况下就是不勾选的状态忽略加载文件有些非必要加载到开发工具中的文件我们…

驱动开发(3)|rk356x驱动GPIO基础应用之点亮led灯

点亮LED灯看似是一个基础的操作&#xff0c;但实际上&#xff0c;许多高级应用也依赖于高低电平的切换。例如&#xff0c;脉冲宽度调制&#xff08;PWM&#xff09;信号可以用来精确控制电机的转速&#xff0c;通过改变脉冲的频率和占空比&#xff0c;实现对电机的精确调节&…

手动搭建PHP环境:步步为营,解锁Web开发

目录一、引言二、准备工作2.1 明确所需软件2.2 下载软件三、Windows 系统搭建步骤3.1 安装 Apache 服务器3.2 安装 PHP3.3 集成 Apache 与 PHP3.4 安装 MySQL3.5 配置 PHP 连接 MySQL四、Linux 系统搭建步骤&#xff08;以 Ubuntu 为例&#xff09;4.1 更新系统4.2 安装 Apache…

DrissionPage:一款让网页自动化更简单的 Python 库

在网页自动化领域&#xff0c;Selenium 和 Playwright 早已是开发者耳熟能详的工具。但今天要给大家介绍一款更轻量、更易用的 Python 库 ——DrissionPage。它以 "融合 selenium 和 requests 优势" 为核心设计理念&#xff0c;既能像 requests 一样高效处理静态网页…

理解Grafana中`X-Scope-OrgID`的作用与配置

X-Scope-OrgID的作用 该HTTP Header用于标识Loki日志数据的所属租户&#xff08;组织&#xff09;。在多租户模式下&#xff0c;Loki通过此Header隔离不同团队或用户的数据&#xff0c;确保查询和存储的独立性。数据隔离&#xff1a; 租户A的日志标记为X-Scope-OrgID: team-a&a…

【PycharmPyqt designer桌面程序设计】

在 main.py 中调用 Qt Designer 生成的 windows.py&#xff08;假设它是 PySide2 版&#xff09;。 只要把两个文件放在同一目录即可直接运行。 ──────────────────── 1️⃣ windows.py&#xff08;Qt Designer 生成&#xff0c;已转码&#xff09; # -*-…

Unity Android Logcat插件 输出日志中文乱码解决

背景之前安卓真机调试看日志&#xff0c;一直用的是Android Studio自带的adb命令进行看日志&#xff0c;不太方便&#xff0c;改用Unity自带的安卓日志插件时&#xff0c;存在中文日志乱码问题。插件安装基于Unity6000.1.11版本&#xff1a;Window -> Package Management -&…

Halcon双相机单标定板标定实现拼图

1.Halcon图像拼接算法在之前的文章里也写过&#xff0c;主要是硬拼接和特征点拼接两种方式&#xff0c;今天增加另一种拼接图像的方式。应用场景是多个相机联合一起拍大尺寸的物体&#xff0c;并且相机视野之间存在重叠区域。通过在同一个标定板上面标定&#xff0c;计算两个相…

动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE

提示词在一个奇幻的童话森林里&#xff0c;所有的动物都像人类一样直立行走&#xff0c;穿着各种搞怪的衣服。 一只戴着超大眼镜、穿着背带裤的乌龟&#xff0c;正一本正经地站在一个蘑菇舞台上&#xff0c;拿着一根树枝当作麦克风&#xff0c;准备唱歌。它的眼镜总是往下滑&am…

SpringBoot(原理篇)

大家好&#xff0c;这里是 盛码笔记。 本篇我们来聊一聊 Spring Boot 的“魔法”是如何实现的。你可能已经用过 Spring Boot 快速搭建项目&#xff0c;但有没有想过&#xff1a;为什么只需要引入几个 starter&#xff0c;Spring Boot 就能自动配置好整个应用环境&#xff1f; …

数据结构:栈(区间问题)

码蹄集OJ-小码哥的栈 #include<bits/stdc.h> using namespace std; #define int long long const int N1e67; struct MOOE {int ll,rr; }; stack<MOOE>st; signed main( ) {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;while(n--){int opt…