Android开发补充内容

Android开发补充内容

  • fragment
    • 通信
    • 生命周期
  • Okhttp
    • 基本使用
    • websocket
  • Retrofit
    • 基本使用
  • RxJava
    • 基本使用
    • 定时任务
  • Hilt
    • 基本使用
    • 进阶使用
    • 例子
  • 组件库
    • Material Components
    • Jetpack Compose

fragment

通信

fragmentactivity通信的一种原生方法是使用Bundle

Bundle bundle = new Bundle();
bundle.putString('msg', "数据");
BlankFragment bf = new BlankFragment();
bf.setArguments(bundle);

生命周期

  1. 第一次显示:onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
  2. 按home:onPause -> onStop(界面显示的fragment不变)
  3. 重新显示:onStart -> onResume
  4. 按返回:onPause -> onStop -> onDestroyView -> onDestroy -> onDetach

使用了FragmentTransactionaddToBackStack方法

  1. 切换fragment:onPause -> onStop -> onDestroyView(但没销毁时,同栈切换)
  • 返回原fragment:onCreateView -> onActivityCreated -> onStart -> onResume(同栈返回)

Okhttp

基本使用

模块级的build.gradle导入依赖:

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

创建客户端:

client = OkHttpClient.Builder().addInterceptor {val request = it.request()val response = it.proceed(request)Log.d("biluo", request.url.toString())response}.connectTimeout(20, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build()

创建和使用请求:

val request = Request.Builder().url("http://localhost/user/list").build()
// 阻塞方式
val response = client.newCall(request).execute()
// 异步方式
val response = client.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {TODO("Not yet implemented")}override fun onResponse(call: Call, response: Response) {TODO("Not yet implemented")}
})

websocket

val observable = Observable.create<String> { emitter ->val request = Request.Builder().url("${AppConstant.WS_URL}/${user.username}").build()val ws = client.newWebSocket(request, object : WebSocketListener() {override fun onOpen(webSocket: WebSocket, response: Response) {wsObservable.ws = webSocketLog.d("biluo", "socket连接成功")}override fun onMessage(webSocket: WebSocket, text: String) {Log.d("biluo", "接收到消息:$text")emitter.onNext(text)}override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {Log.d("biluo", "socket连接准备断开")}override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {wsObservable.ws = nullLog.d("biluo", "socket连接已经断开")//emitter.onComplete()}override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {Log.e("biluo", "异常:${t.message}", t)emitter.onError(t)}})emitter.setDisposable(object : Disposable {override fun dispose() {Log.d("biluo", "dispose...")ws.close(1000, "Closing by dispose")}override fun isDisposed(): Boolean {return ws.close(1000, null)}})
}
wsObservable.observable = observable
return wsObservable

Retrofit

基于OkHttp,同时支持了RESTful API风格设计

基本使用

模块级的build.gradle导入依赖:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'

创建Retrofit实例:

添加了GsonConvert后,会自动把响应回来的Json字符串转换为对象。

val retrofit = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).client(client).build()

定义Api类:

interface UserApi {@GET("$USER_URL/{username}")fun getByUsername(@Path("username") username: String): Call<MsgResult<User>>@POST("$USER_URL/register")fun register(@Body user: User): Call<MsgResult<Nothing>>
}

创建Api类:

UserApi = retrofit.create(UserApi::class.java)

RxJava

可以结合Retrofit一起使用。

基本使用

前提:依赖在Retrofit中已经导入,并创建了RxJavaConvert到Retrofit中。

之前定义Api的返回值可以改为RxJava提供的类型。

它提供了:

  • Observable:流式数据类型,用于访问多个项的异步序列。

  • Flowable:与Observable类似,支持背压(backpressure)机制,即当数据生产速度超过消费速度时,能够控制数据的流动。

  • Single:单发数据类型,只能且必须发射一个数据。

  • Maybe:单发数据类型,可以发射零个或一个数据。

  • Completable:不发射任何数据,只通知流的结束。

之前的UserApi类变为:

interface UserApi {@GET("$USER_URL/{username}")fun getByUsername(@Path("username") username: String): Single<MsgResult<User>>@POST("$USER_URL/register")fun register(@Body user: User): Single<MsgResult<Nothing>>
}

使用:

val disposable: Disposable = single.subscribeOn(Schedulers.io()).observeOn(AndroidScheduler.mainScheduler).subscribe({ res ->//成功获取结果res,做什么}, { e ->//出现异常后做些什么})

Retrofix下的RxJava没有AndroidScheduler类,可以自己定义一个:

object AndroidScheduler : Executor {val mainScheduler: Scheduler = Schedulers.from(this)private val handler: Handler = Handler(Looper.getMainLooper())override fun execute(command: Runnable) {handler.post(command)}
}

定时任务

val disposable = Observable.interval(15L, TimeUnit.MINUTES).subscribe({ _ ->val json = Gson().toJson(Message("ping", null, appUser.username))wsObservable.ws?.send(json)Log.d("biluo", "发送了一个心跳包")}) { t ->Log.e("biluo", "异常:", t)wsObservable.ws?.close(1000, "心跳续约失败")}

Hilt

可以进行实例的管理,并进行依赖注入。类似spring IOC

项目级build.gradle导入插件:

id 'com.google.dagger.hilt.android' version '2.51.1' apply false

模块级build.gradle导入插件:

id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'

模块级build.gradle导入依赖:

implementation 'com.google.dagger:hilt-android:2.51.1'kapt 'com.google.dagger:hilt-compiler:2.51.1'

基本使用

参考教程:https://blog.csdn.net/Mr_Tony/article/details/124516871

使用Hilt必须要先用@HiltAndroidApp绑定Application

哪个类需要进行依赖注入,就得加上@AndroidEntryPoint进行绑定,然后注入的地方需要使用@Inject

  • @HiltAndroidApp:用于标注 Application 类,触发 Hilt 的代码生成操作,生成应用级别的组件。

  • @AndroidEntryPoint:用于标注 Android 组件(如 ActivityFragment 等),告知 Hilt 这些组件可以接收依赖注入。

  • @Inject

    • 用于标注需要注入的依赖项,可以是字段、构造函数或方法。
    • 对于字段,Hilt 会自动注入相应的依赖;对于构造函数,Hilt 会使用它来创建类的实例

注:@AndroidEntryPoint不仅仅可以绑定到Activity,还可以绑定到其他地方,请参考:https://developer.android.google.cn/training/dependency-injection/hilt-android

@HiltAndroidApp
class App: Application()// 类似spring的 @Component
class DateFormatter @Inject constructor() {fun testDateFormatter(){Log.e("YM--->","---->获取DateFormatter")}
}// 类似spring在类中进行依赖注入也需要当前类被spring管理
@AndroidEntryPoint
class HiltActivity : AppCompatActivity() {@Inject	// 类似spring的 @Autowirelateinit var dateFormatter: DateFormatteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_hilt)dateFormatter.testDateFormatter()}
}

进阶使用

  • @Module:用于标注提供依赖项的类。
  • @Provides:用于标注 Module 类中的提供依赖项的方法,Hilt 会在需要时调用这些方法。
  • @Binds:用于在Module类中绑定接口和实现类,告知 Hilt 在需要提供接口的实例时要使用哪种实现。
  • @InstallIn:用于标注 ModuleEntryPoint,指定其作用范围。
  • @Singleton:用于标注提供的依赖项为单例,即在整个应用程序的生命周期内只存在一个实例。
  • @HiltViewModel
    • 用于标注 ViewModel 类,使其可以使用 Hilt 进行依赖注入。
    • 注意:ViewModel 不能直接使用 @Inject 注解,需要使用 @HiltViewModel
  • @ActivityScoped:用于标注提供的依赖项为 Activity 级别的作用域,即依赖项的生命周期与 Activity 相同。

补充:

  • @HiltViewModel

    • 用于标注 ViewModel 类,使其可以使用 Hilt 进行依赖注入。

    • 注意:ViewModel 不能直接使用 @Inject 注解,需要使用 @HiltViewModel

  • @ViewModelScoped:用于标注提供的依赖项为 ViewModel 级别的作用域,即依赖项的生命周期与 ViewModel 相同。

  • @EntryPoint:用于获取 Hilt 提供的实例,特别是在不能直接使用 @AndroidEntryPoint 的类中(如 ContentProviderBroadcastReceiver)。

  • @Provides举例:
class HelloClass {fun hello() = "Hello"
}@Module
// 表示整个应用程序的生命周期内都是单例
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singleton	// 单例fun provideSomeOtherClass(): HelloClass {return HelloClass()}
}@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var helloClass: HelloClassoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)helloClass.hello()}
}
  • @Binds举例:在这个示例中,@Binds 注解用于将 ApiServiceImpl 绑定到 ApiService 接口上,这样当需要 ApiService 的实例时,Hilt 会提供 ApiServiceImpl 的实例。
interface ApiService {fun doSomething()
}class ApiServiceImpl @Inject constructor() : ApiService {override fun doSomething() {println("Doing something in ApiServiceImpl")}
}@Module
@InstallIn(SingletonComponent::class)
abstract class ApiServiceModule {@Bindsabstract fun bindApiService(apiServiceImpl: ApiServiceImpl): ApiService
}
  • @ActivityScope例子:
@Module
@InstallIn(ActivityComponent::class)
object ActivityModule {@Provides@ActivityScopedfun provideActivityDependency(): ActivityDependency {return ActivityDependency()}
}

例子

Application类:

@HiltAndroidApp
class MyApplication : Application() {}

模块类:

@InstallIn(SingletonComponent::class)
@Module
class AppModule {@Provides@Singletonfun okHttpClient(): OkHttpClient {return OkHttpClient.Builder().addInterceptor {val request = it.request()val response = it.proceed(request)Log.d("biluo", request.url.toString())response}.connectTimeout(20, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).retryOnConnectionFailure(false).build()}@Provides@Singletonfun retrofit(client: OkHttpClient): Retrofit {return Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).client(client).build()}@Provides@Singletonfun userApi(retrofit: Retrofit): UserApi = retrofit.create(UserApi::class.java)
}

使用:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var userApi: UserApi
}

组件库

Material Components

Material Components for Android:Google 官方提供的 Material Design 组件库。

  • 特点
    • 完全遵循 Material Design 规范。
    • 提供丰富的组件(如 ButtonCardViewBottomNavigationView 等)。
    • 与 AndroidX 库无缝集成。
  • 适用场景:需要遵循 Material Design 规范的项目。
  • GitHub:https://github.com/material-components/material-components-android

举例:BottomNavigationView——底部导航栏

  1. 编写菜单xml文件bottom_nav_menu.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/nav_home"android:icon="@drawable/home"android:title="@string/tab1" /><itemandroid:id="@+id/nav_tab2"android:icon="@drawable/tab2"android:title="@string/tab2" /><itemandroid:id="@+id/nav_tb3"android:icon="@drawable/tb3"android:title="@string/tab3" />
    </menu>
    
  2. 在相应的布局文件中引入BottomNavigationView,例如MainActivity。

    <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><androidx.fragment.app.FragmentContainerViewandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><com.google.android.material.bottomnavigation.BottomNavigationViewandroid:id="@+id/bottomNavigationView"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="bottom"android:background="@color/purple_200"app:menu="@menu/bottom_nav_menu"/>
    </LinearLayout>
    
  3. 准备好相应的Fragment,为BottomNavigationView设置点击事件,根据点击的项切换Fragment

    class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_navigation)val fragmentContainer = supportFragmentManager.beginTransaction()// 默认加载 HomeFragmentfragmentContainer.replace(R.id.fragment_container, HomeFragment())fragmentContainer.commit()bottomNavigationView.setOnItemSelectedListener { item ->when (item.itemId) {R.id.nav_home -> {supportFragmentManager.beginTransaction().replace(R.id.fragment_container, HomeFragment()).commit()true}R.id.nav_tb2 -> {supportFragmentManager.beginTransaction().replace(R.id.fragment_container, NavTb2Fragment()).commit()true}R.id.nav_tb3 -> {supportFragmentManager.beginTransaction().replace(R.id.fragment_container, NavTb3Fragment()).commit()true}else -> false}}}
    }
    

Jetpack Compose

Jetpack Compose Material:Jetpack Compose 的 Material Design 组件库。

  • 特点
    • 声明式 UI 开发。
    • 提供 Material Design 风格的组件(如 ScaffoldButtonTextField 等)。
    • 与 Jetpack Compose 生态完全兼容。
  • 适用场景:使用 Jetpack Compose 开发的项目。
  • 文档:Jetpack Compose 使用入门 | Android Developers (google.cn)

举例:

@AndroidEntryPoint
class LoginActivity : AppCompatActivity() {private lateinit var shared: SharedPreferences@Inject lateinit var userApi: VehicleOwnerApioverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)shared = getSharedPreferences("user", MODE_PRIVATE)val id = shared.getString("id", "")!!val password = shared.getString("password", "")!!setContent {MaterialTheme { loginScreen(id, password) }}}@Composablefun loginScreen(originId: String, originPwd: String) {val ID_REGEX = Regex("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$")val PWD_REGEX = Regex("^[a-zA-Z\\d]{4,16}$")var id by remember { mutableStateOf(originId) }var password by remember { mutableStateOf(originPwd) }var idErrorMsg by remember { mutableStateOf("") }var pwdErrorMsg by remember { mutableStateOf("") }var checked by remember { mutableStateOf(false) }fun checkIdFormat(): Boolean {idErrorMsg = if (id.isEmpty()) "身份证号不能为空" else {if (!ID_REGEX.matches(id)) "身份证号格式错误" else ""}return idErrorMsg.isEmpty()}fun checkPwdFormat(): Boolean {pwdErrorMsg = if (password.isEmpty()) "密码不能为空" else {if (!PWD_REGEX.matches(password)) "密码必须由4-16位的字母或数字组成" else ""}return pwdErrorMsg.isEmpty()}fun login() {if (!checkIdFormat() || !checkPwdFormat()) returnUtils.handleSingle(this, "token", userApi.login(VehicleOwner(id, password))) {GlobalData.token = it.toString()// 如果选择了记住用户,将身份证号和密码写入sharePreferencesif (checked) {shared.edit().putString("id", id).apply()shared.edit().putString("password", password).apply()} else {shared.edit().remove("id").apply()shared.edit().remove("password").apply()}// 登录成功,跳转到主页Utils.showToast(this, "登录成功")val intent = Intent(this, MainActivity::class.java)intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASKstartActivity(intent)}}Column(modifier = Modifier.padding(16.dp)) {TextField(  // 身份证输入框value = id,onValueChange = { id = it },label = { Text("身份证号") },placeholder = { Text("请输入身份证号") },isError = idErrorMsg.isNotEmpty(),trailingIcon = {if (idErrorMsg.isNotEmpty()) {    // 如果有错误提示,则显示错误图标Icon(Icons.Filled.Error, contentDescription = "Error")}},supportingText = { Text(idErrorMsg) },    // 显示在下方的错误提示modifier = Modifier.fillMaxWidth()/*.onFocusChanged { focusState -> // 进入页面时会直接显示错误提示,不友好;改为点击登录时再检查格式if (!focusState.isFocused) {idErrorMsg = if (id.isEmpty()) "身份证号不能为空" else {if (!ID_REGEX.matches(id)) "身份证号格式错误" else ""}}}*/)TextField(  // 密码输入框value = password,onValueChange = { password = it },label = { Text("密码") },placeholder = { Text("请输入密码") },isError = pwdErrorMsg.isNotEmpty(),trailingIcon = {if (pwdErrorMsg.isNotEmpty()) {    // 如果有错误提示,则显示错误图标Icon(Icons.Filled.Error, contentDescription = "Error")}},supportingText = { Text(pwdErrorMsg) },    // 显示在下方的错误提示modifier = Modifier.fillMaxWidth().padding(top = 4.dp))Row(verticalAlignment = Alignment.CenterVertically, // 行内元素垂直居中horizontalArrangement = Arrangement.spacedBy((-6).dp),  // 行内元素间距modifier = Modifier.clickable(interactionSource = remember { MutableInteractionSource() },indication = null   // 移除点击效果) { // 点击整个 Row 切换选中状态checked = !checked}) {Checkbox(checked = checked, onCheckedChange = { checked = it })	// 复选框Text("记住用户")	// 文本}Button(	// 按钮onClick = { login() },modifier = Modifier.fillMaxWidth()) {Text("登     录")}}}
}

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

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

相关文章

隐私计算框架FATE二次开发心得整理(工业场景实践)

文章目录 版本介绍隐私计算介绍前言FATE架构总体架构FateBoard架构前端架构后端架构 FateClient架构创建DAG方式DAG生成任务管理python SDK方式 FateFlow架构Eggroll架构FATE算法架构Cpn层FATE ML层 组件新增流程新增组件流程新增算法流程 版本介绍 WeBank的FATE开源版本 2.2.…

AI驱动的制造工艺:系统化探索与创新

DeepSeek 技术全景 在当今 AI 技术蓬勃发展的时代,DeepSeek 已成为该领域中一颗耀眼的明星。自 2023 年 7 月 17 日成立以来,这家由知名私募巨头幻方量化孕育而生的公司,迅速在 AI 领域崭露头角 。DeepSeek 的目标是开发顶尖的大语言模型(LLM),并利用数据蒸馏技术打造更精…

【嵌入式开发-LCD】

嵌入式开发-LCD ■ LCD简介 ■ LCD简介

java反射(2)

package 反射;import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays;public class demo {public static void main(String[] args) throws Exception {// 通过类的全限定名获取对应的 Class 对象…

使用 Cesium 构建 3D 地图应用的实践

CesiumJS 是一个功能强大的开源 JavaScript 库&#xff0c;能够帮助开发者快速构建高性能、高精度的 3D 地球和地图应用 。本文将介绍如何使用 Cesium 构建一个基本的 3D 地图应用&#xff0c;并加载自定义的 3D Tiles 模型。 初始化 Cesium Viewer 首先&#xff0c;在 Vue 的…

结合Splash与Scrapy:高效爬取动态JavaScript网站

在当今的Web开发中&#xff0c;JavaScript的广泛应用使得许多网站的内容无法通过传统的请求-响应模式直接获取。为了解决这个问题&#xff0c;Scrapy开发者经常需要集成像Splash这样的JavaScript渲染引擎。本文将详细介绍Splash JS引擎的工作原理&#xff0c;并探讨如何将其与S…

企业级可观测性实现:OpenObserve云原生平台的本地化部署与远程访问解析

文章目录 前言1. 安装Docker2. 创建并启动OpenObserve容器3. 本地访问测试4. 公网访问本地部署的OpenObserve4.1 内网穿透工具安装4.2 创建公网地址 5. 配置固定公网地址 前言 嘿&#xff0c;各位小伙伴们&#xff0c;今天要给大家揭秘一个在云原生领域里横扫千军的秘密法宝—…

将本地项目提交到新建的git仓库

方式一: # 登录git&#xff0c;新建git仓库和指定的分支&#xff0c;如master、dev# 下载代码&#xff0c;默认下载master分支 git clone http://10.*.*.67/performance_library/pfme-*.git # 切换到想要提交代码的dev分支 git checkout dev# 添加想要提交的文件 git add .#…

.NET平台用C#在PDF中创建可交互的表单域(Form Field)

在日常办公系统开发中&#xff0c;涉及 PDF 处理相关的开发时&#xff0c;生成可填写的 PDF 表单是一种常见需求&#xff0c;例如员工信息登记表、用户注册表、问卷调查或协议确认页等。与静态 PDF 不同&#xff0c;带有**表单域&#xff08;Form Field&#xff09;**的文档支持…

在macOS上安装windows系统

使用Boot Camp 1. 准备工作&#xff1a;确认Mac满足Boot Camp系统要求&#xff0c;准备好Windows安装光盘或ISO映像文件&#xff0c;以及一个至少8GB的空白USB闪存驱动器用于保存驱动程序。 2. 打开Boot Camp助理&#xff1a;在“应用程序”文件夹的“实用工具”中找到“Boot…

683SJBH基于J2EE的广州旅游管理系统

第1章  绪论 课题背景 自互联网internet成为一种革命性的大众媒体以来&#xff0c;其发展速度之快令人惊叹。而作为世界最大朝阳产业的旅游&#xff0c;当它与电子商务这一新兴模式相结合时&#xff0c;其潜藏的商业价值表露无遗。根据CNN&#xff08;美国有线电视新闻网&…

前端面试每日三题 - Day 27

这是我为准备前端/全栈开发工程师面试整理的第27天每日三题练习&#xff0c;涵盖了&#xff1a; CSS选择器的优先级与权重计算机制Angular中的依赖注入&#xff08;Dependency Injection&#xff09;机制设计一个支持实时协作编辑&#xff08;如Google Docs&#xff09;的前端…

PostgreSQL数据库操作SQL

数据库操作SQL 创建 创建数据库 create database db_test;创建并指定相关参数 with owner : 所有者encoding : 编码connection limit &#xff1a;连接限制 create database db_test1 with owner postgresencoding utf-8connection limit 100;修改 修改数据库名称 renam…

JSP HTTP 状态码详解

JSP HTTP 状态码详解 引言 HTTP 状态码是 HTTP 协议的一部分,用于表示客户端与服务器之间请求与响应的状态。在 JavaServer Pages (JSP) 技术中,HTTP 状态码同样扮演着重要的角色。本文将详细解析 JSP 中的 HTTP 状态码,帮助开发者更好地理解和应用这些状态码。 HTTP 状态…

文件一键解密软件工具(支持pdf、word、excel、ppt、rar、zip格式文件)

一键解密解锁神器支持解密pdf、doc、docx、xls、xlsx、ppt、pptx、rar、zip格式文件&#xff0c;Excel表格、Word文档、PPT演示、RAR、ZIP压缩包、PDF文档一键轻松解密&#xff01;简单/高效/安全。这款软件由密码帝官方提供&#xff0c;确保了其合法性和安全性&#xff0c;用户…

Banana Pi BPI-CM6 是一款八核 RISC-V 模块,兼容 Raspberry Pi CM 载板

Banana Pi BPI-CM6 是一款 SpacemIT K1 八核 RISC-V 系统级模块&#xff0c;遵循 Raspberry Pi CM5 的设计&#xff0c;并提供高达 16GB LPDDR4 RAM、高达 128GB eMMC 闪存、千兆以太网控制器和 WiFi 6 蓝牙 5.2 模块。 BPI-CM6 虽然与 Raspberry Pi CM5 基本兼容&#xff0c…

【项目篇之统一硬盘操作】仿照RabbitMQ模拟实现消息队列

统一硬盘操作 创建出实例封装交换机的操作封装队列的操作封装绑定的操作封装消息的操作总的完整代码&#xff1a; 我们之前已经使用了数据库去管理交换机&#xff0c;绑定&#xff0c;队列 还使用了数据文件去管理消息 此时我们就搞一个类去把上述两个部分都整合在一起&#…

快速上手SpringBoot开发指南

文章目录 1. 项目整体架构2. SpringBoot核心注解详解2.1 应用程序入口注解SpringBootApplication 2.2 控制器层注解RestControllerRequestMappingPostMappingRequestBody 2.3 服务层注解ServiceAutowired 2.4 数据访问层注解Repository 2.5 实体类注解JPA相关注解Lombok注解 3.…

Unity WebGL、js发布交互

官网参考 Unity3D开发之WebGL平台上 unity和js前端通信交互 WebFun.jslib mergeInto(LibraryManager.library, {JSLog: function (str) { var strsUTF8ToString(str); Log(str); Log(strs);}, Hello: function () {var strs"Hello, world!"; Log(strs); Log(UTF8ToS…

Spark 之 YarnCoarseGrainedExecutorBackend

YarnCoarseGrainedExecutorBackend executor ID , 在日志里也有体现。 25/05/06 12:41:58 INFO YarnCoarseGrainedExecutorBackend: Successfully registered with driver 25/05