kotlin 编写一个简单的天气预报app (七)使用material design

一、优化思路

对之前的天气预报的app进行了优化,原先的天气预报程序逻辑是这样的。
使用text和button组合了一个输入城市,并请求openweathermap对应数据,并显示的功能。

但是搜索城市的时候,可能会有错误,比如大小写,比如拼写之类的,所以打算给他升级一下。

目标:

  1. 在搜索的时候需要更够显示搜索的结果,然后在搜索的结果中显示符合的城市列表
  2. 需要有全球的城市数据,搜索结果过滤后,显示符合的城市
  3. 在符合搜索结果的内容中,可以点击需要的城市,并把城市的天气显示在主界面里。

二、准备城市的资料

获取城市的json压缩包
网址:https://bulk.openweathermap.org/sample/
下载链接:https://bulk.openweathermap.org/sample/city.list.json.gz

把下载文件加入进项目里,可以有两个位置一个是res/assert,一个是res/raw,它们的主要区别在于:

  1. res/raw
    • res/raw 目录用于存储原始文件,这些文件不会被 Android 资源编译器进行处理或修改。
    • 您可以在这个目录下放置各种类型的原始文件,例如音频文件、视频文件、文本文件等。
    • 资源文件放置在 res/raw 目录下会保持原始状态,不会被修改。
  2. res/assert
    • res/assert 目录也用于存储原始文件,但其中的文件会被 Android 资源编译器进行压缩和优化处理。
    • 通常用于存放一些较小的非常规资源文件,例如 JSON 文件、XML 文件等。
    • 资源文件放置在 res/assert 目录下会被压缩和优化,这可能会使得访问这些资源稍微快一些。
      如果希望保持资源文件的原始状态,不经过任何修改或处理,可以将它们放置在 res/raw 目录下。
      如果资源文件较小且希望进行优化处理,可以考虑放置在 res/assert 目录下。

这里我们把它放在res/raw目录下,因为它是一个gz的压缩文件。

三、解压城市的gz文件

为这个文件编写代码,让软件在启动时检查是否有解压文件,如果没有解压文件就解压到files目录下。

files 文件夹通常用于存储应用的私有文件。这些文件是应用专用的,其他应用无法访问。以下是关于 files 文件夹的一些主要特点:

  1. 私有性:files 文件夹中的文件只能被创建它们的应用访问,其他应用无法直接访问这些文件。
  2. 持久性:与 cache 目录不同,files 文件夹中的文件不会因为系统资源不足而被清除。这些文件会持久保存,直到应用被卸载或明确删除。
  3. 文件访问:可以通过 Context 对象提供的方法,如 openFileOutput() 和 openFileInput(),来访问 files 文件夹中的文件。
  4. 存储位置:files 文件夹通常位于应用的私有数据目录中。具体路径通常为 /data/data/包名/files/
  5. 用途:files 文件夹适用于存储各种类型的应用数据,如用户配置、日志文件、缓存数据等。

创建一个CityListDataManager的类,并在init时判断文件是否存在,如果不存在就把gz文件解压到files目录下:

class CityListDataManager(private val context: Context) {private val tag = "CityListDataManager"private val jsonFileName = "city.list.json"private val cityListJsonFile : File = File(context.filesDir, jsonFileName)private lateinit var cityDataList : Array<CityData>init {CoroutineScope(Dispatchers.IO).launch {		//使用线程执行,避免阻塞主线程if(!isExistCityListJsonFile()) {		//判断文件是否存在unzipGzFile(context)				//如果不存在就解压}}}private fun isExistCityListJsonFile() : Boolean {val isExisted = cityListJsonFile.exists()		Log.d(tag, "city list json file is existed:$isExisted")return isExisted}private suspend fun unzipGzFile(context: Context) {withContext(Dispatchers.IO) {try {context.resources.openRawResource(			//使用openRawResource打开raw目录下的文件com.example.myweather.R.raw.city_list_json).use { rawIn ->GZIPInputStream(rawIn).use { gzipIn ->		//使用GZIP来读取gz文件FileOutputStream(cityListJsonFile).use { fileOut ->		//使用FileOutputStream读取文件内容gzipIn.copyTo(fileOut)		//把文件解压到files目录下}}}} catch (ex: Exception) {ex.printStackTrace()}}}
}

四、读取所以城市数据

当我们解压了gz文件后,解压出来的文件是json格式的。包含了所有的城市数据。
这时候我需要选择解析json格式的工具,我搜索了相关的内容发现有两种方式,一种是JsonObject另一种是Gson。
我觉得Gson更简单,就选了这个

引入Gson库:


dependencies {implementation(libs.androidx.core.ktx)implementation(libs.androidx.appcompat)implementation(libs.material)implementation(libs.androidx.activity)implementation(libs.androidx.constraintlayout)testImplementation(libs.junit)androidTestImplementation(libs.androidx.junit)androidTestImplementation(libs.androidx.espresso.core)//networkimplementation(libs.com.squareup.retrofit2)implementation(libs.com.squareup.retrofit2.converterGson)implementation(libs.org.greenrobot.eventbus)implementation(libs.androidx.recyclerview)implementation(libs.com.google.code.gson)
}

对应的libs.versions.toml内容:

constraintlayout = "2.1.4"
retrofit = "2.9.0"
converter-gson = "2.9.0"
eventBus = "3.2.0"
recyclerview = "1.3.2"
gson = "2.10.1"[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
com-squareup-retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
com-squareup-retrofit2-converterGson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "converter-gson" }
org-greenrobot-eventbus = { group = "org.greenrobot", name = "eventbus", version.ref = "eventBus" }
androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
com-google-code-gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

为Json内容创建对应的类,两个数据类:CoordCityDataCoord 类表示地理坐标,包含经度 (lon) 和纬度 (lat)。CityData 类表示城市数据,包含城市的ID (id)、名称 (name)、州/省 (state)、国家 (country) 以及该城市的地理坐标 (coord)。这也对应json文件的数据格式

data class Coord (val lon: Double,val lat: Double
)
data class CityData(val id: Int,val name: String,val state: String?=null,val country: String,val coord: Coord
)

读取json格式函数,用于逐行读取文件内容并将其解析为 CityData 对象列表。这里使用了 Gson 库来解析 JSON 数据。具体步骤如下:

  1. 创建 Gson 实例。
  2. 打开应用的文件目录,并指定要读取的文件名。
  3. 使用 FileInputStream 打开文件,并创建 BufferedReader 来逐行读取文件内容。
  4. 使用 StringBuilder 来构建完整的文件内容。
  5. 在 while 循环中,逐行读取文件内容,并将每行添加到 StringBuilder 中。
  6. 读取完成后,将 StringBuilder 中的内容转换为字符串。
  7. 使用 Gson 的 fromJson 方法将 JSON 字符串转换为 CityData 对象数组。
  8. 将解析后的 CityData 对象数组发送到事件总线(EventBus)中。
    如果发生 IO 异常,将打印异常堆栈跟踪信息。
private fun readContentOneByOne(context: Context) = try {val gson = Gson()val file = File(context.filesDir, jsonFileName)val fis = FileInputStream(file)val reader = BufferedReader(InputStreamReader(fis))val stringBuilder = StringBuilder()var line : String?while (reader.readLine().also { line = it } != null) {stringBuilder.append(line).append("\n")}val fileContent = stringBuilder.toString()cityDataList = gson.fromJson(fileContent, Array<CityData>::class.java)Log.d(tag, "get city data list done and send event bus")EventBus.getDefault().post(CityDataListReadyEvent(cityDataList.toList()))} catch (e: IOException) {e.printStackTrace()
}

CityListDataManagerinit中调用它

    init {CoroutineScope(Dispatchers.IO).launch {if(!isExistCityListJsonFile()) {unzipGzFile(context)}readContentOneByOne(context)}}

五、创建Material Search Bar

根据最新的Material Design的Search说明文档,可以在MainActivity里套用它的模版来使用:

<androidx.coordinatorlayout.widget.CoordinatorLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><!-- NestedScrollingChild goes here (NestedScrollView, RecyclerView, etc.). --><androidx.core.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/searchbar_scrolling_view_behavior"><!-- Screen content goes here. 这里放显示的主内容 --></androidx.core.widget.NestedScrollView><com.google.android.material.appbar.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><com.google.android.material.search.SearchBarandroid:id="@+id/search_bar"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/searchbar_hint" /></com.google.android.material.appbar.AppBarLayout><com.google.android.material.search.SearchViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:hint="@string/searchbar_hint"app:layout_anchor="@id/search_bar"><!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). 这里是放搜索结果 --></com.google.android.material.search.SearchView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

遇到的问题:
我之前的项目并不是用Android Material Design设计的,只是一个简单的TextView和Button组合的搜索结果。
当我想要使用Material Design相关的控件时,发现引用相关的库后调用SerachBar和需要配置说明文档里不存在的一些属性,否则就会崩溃。
当我为SearchBar设置了属性后,SearchView加入后,仍然还是会崩溃。我搜索了各种问题都无法解决,最后我新建了一个项目,把代码重新拷贝进去后,问题消失了。
分析:可能是我之前建的工程版本较低导致的,我通过对比gradle文件发现,不会崩溃的版本sdk更高。具体我也说不上来为什么,就只能这么用了。

六、使用SearchBar和SearchView对接

当我插入上面的模版后,发现点击SearchBar并不会跳转显示SerachView。
不断尝试后发现可以这样做,让点击SearchBar后出现SearchView

		binding.searchBar.apply {setOnClickListener { binding.searchView.show() }}

而在SearchView中输入了内容,点击确认进行搜索的方式是这样的:

        binding.searchView.editText.setOnEditorActionListener { v, _, _ ->val filterText = v.editableText.toString()Toast.makeText(v.context, "the text: $filterText", Toast.LENGTH_SHORT).show()return@setOnEditorActionListener false}

这样我们一个基本的搜索框架就搭建好了,还需要把结果数据显示出来

七、用recycleview显示搜索结果

在SearchView中添加recycleview控件:

    <com.google.android.material.search.SearchViewandroid:id="@+id/search_view"android:layout_width="match_parent"android:layout_height="match_parent"android:hint="@string/editTextCityHint"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/cityDataRecyclerView"android:layout_width="match_parent"android:layout_height="match_parent"/></com.google.android.material.search.SearchView>

创建一个对应的CityDataAdapter类,这里我们需要添加一个itemClick事件,当有一项被点击时,可以触发一个消息:

package com.example.myweather.cityListUtilsimport android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.myweather.Rclass CityDataAdapter(private val originCityDataList: List<CityData>) :RecyclerView.Adapter<CityDataAdapter.ViewHolder>() {private var filterCityDataList : MutableList<CityData> = originCityDataList.toMutableList()var onItemClick: ((CityData) -> Unit)? = nullinner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {init {view.setOnClickListener {if(absoluteAdapterPosition != RecyclerView.NO_POSITION)onItemClick?.invoke(filterCityDataList[absoluteAdapterPosition])}}val cityDataId : TextView = view.findViewById<TextView>(R.id.city_data_id)val cityDataName : TextView = view.findViewById<TextView>(R.id.city_data_name)val cityDataCountry : TextView = view.findViewById<TextView>(R.id.city_data_country)val cityDataCoordinate: TextView = view.findViewById<TextView>(R.id.city_data_coordinate)}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {val view = LayoutInflater.from(parent.context).inflate(R.layout.city_data_item, parent, false)return ViewHolder(view)}override fun onBindViewHolder(holder: ViewHolder, position: Int) {val cityData = filterCityDataList[position]holder.cityDataId.text = cityData.id.toString()holder.cityDataName.text = cityData.nameholder.cityDataCountry.text = cityData.countryholder.cityDataCoordinate.text = buildString {append(String.format("%.1f", cityData.coord.lon))append(",")append(String.format("%.1f", cityData.coord.lat))}}override fun getItemCount() = filterCityDataList.size@SuppressLint("NotifyDataSetChanged")fun setFilter(filterText: String) {if(filterText.isEmpty()) {filterCityDataList.clear()filterCityDataList.addAll(originCityDataList)} else {filterCityDataList.clear()for (item in originCityDataList) {if (item.name.lowercase().contains(filterText.lowercase())) {filterCityDataList.add(item)}}}notifyDataSetChanged()}
}

在MainActivity里,添加处理解析完城市json格式的所有城市数据:
在主线程中接收城市数据列表准备就绪的事件,并调用 updateCityDataList 方法更新城市数据列表。

    @Subscribe(threadMode = ThreadMode.MAIN)fun onReceiveCityDataListReadyEvent(event: CityDataListReadyEvent) {Log.d(tag, "on received city data list ready event ${event.cityDataList.size}")updateCityDataList(event.cityDataList)}

当CityDataAdapter的某一项被点击时,调用OnItemClick事件来处理。需要在注册的时候就绑定相关的消息:

  1. 创建了一个 CityDataAdapter 的实例,并传入城市数据列表作为参数。
  2. 为 CityDataAdapter 设置了点击事件的回调函数 onItemClick,在点击城市数据项时执行以下操作:
    • 获取点击的城市名称 cityName。
    • 使用 RetrofitClient 获取该城市的天气信息和预报信息。
    • 创建一个包含点击项名称的提示消息 message。
    • 隐藏搜索视图(可能是搜索框之类的)。
    • 弹出一个短暂的 Toast 消息显示 message。
  3. 将适配器设置到城市数据的 RecyclerView 中,用于显示城市数据列表。
    private fun updateCityDataList(cityDataList: List<CityData>) {val adapter = CityDataAdapter(cityDataList)adapter.onItemClick = { cityData ->val cityName = cityData.nameRetrofitClient.getWeatherByCityName(cityName)RetrofitClient.getForecastByCityName(cityName)val message = "Click item name: $cityName"binding.searchView.hide()Toast.makeText(this, message, Toast.LENGTH_SHORT).show()}binding.cityDataRecyclerView.adapter = adapter}

最终的效果图:

在这里插入图片描述
在这里插入图片描述

最后遇到的奔溃问题

由于json文件解析需要一点时间,如果软件启动时,就去搜索,因为adapter是空的,所以软件会崩溃。
最后我在初始化的时候先创建了一个空的队列,避免崩溃:

    private fun initView() {supportFragmentManager.beginTransaction().replace(R.id.fragment_container, CityWeatherFragment()).commit()binding.forecastRecyclerView.layoutManager = LinearLayoutManager(this)binding.cityDataRecyclerView.layoutManager = LinearLayoutManager(this)binding.cityDataRecyclerView.adapter = CityDataAdapter(emptyList<CityData>())binding.searchBar.apply {setOnClickListener { binding.searchView.show() }}binding.searchView.editText.setOnEditorActionListener { v, _, _ ->val filterText = v.editableText.toString()Toast.makeText(v.context, "the text: $filterText", Toast.LENGTH_SHORT).show()val cityDataAdapter : CityDataAdapter= binding.cityDataRecyclerView.adapter as CityDataAdaptercityDataAdapter.setFilter(filterText)return@setOnEditorActionListener false}}
  1. 使用 supportFragmentManager 开始一个事务,并将一个 CityWeatherFragment 替换到 ID 为 fragment_container 的容器中。
  2. 设置 forecastRecyclerView 和 cityDataRecyclerView 的布局管理器为 LinearLayoutManager,以确保它们的布局是线性的。
  3. 为 cityDataRecyclerView 设置一个空的城市数据列表适配器 CityDataAdapter,以便后续更新城市数据。
  4. 为搜索栏 searchBar 设置点击事件监听器,点击时显示搜索视图 searchView。
  5. 为搜索视图的编辑文本框设置编辑动作监听器,当用户执行编辑动作时(比如按下回车键)执行以下操作:
    • 获取编辑框中的文本内容。
    • 弹出一个短暂的 Toast 消息,显示文本内容。
    • 从 cityDataRecyclerView 的适配器中获取 CityDataAdapter 实例,并调用其 setFilter 方法,传入文本内容作为过滤条件。

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

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

相关文章

steam打不开没反应 steam客户端启动不了一直无响应的解决方法

steam打不开没反应 steam客户端启动不了一直无响应的解决方法 steam这个平台想必各位游戏爱好者们肯定不会陌生&#xff0c;作为全球最大的游戏服务平台&#xff0c;steam不仅为玩家们提供了全面的游戏服务&#xff0c;还经常给玩家们提供各种游戏优惠&#xff0c;并且每年四…

【综述】DSP处理器芯片

文章目录 TI DSP C2000系列 TMS320F28003X 典型应用 开发工具链 参考资料 TI DSP TI C2000系列 控制领域 TI C5000系列 通信领域 TI C6000系列 图像领域 C2000系列 第三代集成了C28浮点DSP内核&#xff0c;采用了65nm工艺&#xff08;上一代180nm&#xff09; 第四代正在…

无人零售与传统便利店的竞争优势

无人零售与传统便利店的竞争优势 成本控制 • 无人零售 显著降低了人力成本&#xff0c;无需支付店员薪资和相关福利&#xff0c;且通过智能化管理减少能源消耗与维护费用&#xff0c;尤其在高租金和高人流区域效益突出。 • 传统便利店 则承担较高的人员开支&#xff0c;…

chrome 查看版本安装路径、cmd命令行启动浏览器

chrome 查看版本安装路径 浏览器输入 chrome://version/cmd命令行启动浏览器 "C:\Program Files\Google\Chrome\Application\chrome.exe" www.baidu.com

恒峰智慧科技—高扬程水泵:解决远距离输水难题的新选择!

在森林消防领域&#xff0c;水泵是一个至关重要的设备。它的主要功能是将水源输送到火灾现场&#xff0c;为消防人员提供足够的水源进行灭火。然而&#xff0c;传统的水泵往往面临着距离限制的问题&#xff0c;这对于远距离输水来说是一个巨大的挑战。幸运的是&#xff0c;高扬…

Jenkins构建触发器-Git hook自动触发构建

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 Jenkins是一个开源…

《苍穹外卖》Day10部分知识点记录

一、Spring Task 介绍 Spring Task是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 定位&#xff1a;定时任务框架 作用&#xff1a;定时自动执行某段Java代码 应用场景&#xff1a;只要是需要定时处理的场景都可以使用Spring Task …

2024腾讯游戏安全技术竞赛-机器学习赛道

决赛赛题链接https://gss.tencent.com/competition/2024/doc/2024%E8%85%BE%E8%AE%AF%E6%B8%B8%E6%88%8F%E5%AE%89%E5%85%A8%E6%8A%80%E6%9C%AF%E7%AB%9E%E8%B5%9B-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E5%86%B3%E8%B5%9B.zip 今年的题目是游戏跨语言恶意内容识别 ,题目比较…

技术速递|利用 Redis 使 AI 驱动的 .NET 应用程序更加一致和智能

作者&#xff1a;Catherine Wang 排版&#xff1a;Alan Wang Redis 是一种流行的内存数据存储&#xff0c;可用于解决构建和扩展智能应用程序的关键挑战。在本文中&#xff0c;你将了解如何使用 Redis 的 Azure 缓存来提高使用 Azure OpenAI 的应用程序的效率。 Redis 的 Azur…

西电超算使用方法-简易版

一、引言 西电超算不错&#xff0c;我很喜欢。本文仅供自己学习使用。 二、环境搭建 搭建环境需要有一些依赖库&#xff0c;但是其实西电超算说明手册并没有写的非常清楚。因此&#xff0c;这次实战演示一下&#xff0c;写一个运行sh文件脚本并提交作业。 1、选择GPU还是CP…

AI赋能分层模式,解构未来,智领风潮

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#x1f525;&#xff1a;探索设计模式的魅力&#xff1a;AI赋能分…

人脸识别概念解析

目录 1. 概述 2. 人脸检测 3. 人脸跟踪 4. 质量评价 5. 活体检测 6. 特征提取 7. 人脸验证 8. 人脸辨识 1. 概述 人脸识别在我们的生活中随处可见&#xff0c;例如在大楼门禁系统中&#xff0c;它取代了传统的门禁卡或密码&#xff0c;提高了进出的便捷性和安全性。在商…

【Linux】基础指令

文章目录 基础指令1. pwd 指令2. cd 指令3. ls 指令4. touch 指令5. mkdir 指令6. rmdir 和 rm 指令7. man 指令8. cp 指令9. mv 指令10. cat 指令11. more 和 less 指令12. head 和 tail 指令13. date 指令14. cal 指令15. find 指令16. grep 指令18. zip 和 unzip 指令19. ta…

Jenkins - macOS 上安装

文章目录 关于 JenkinsmacOS 上安装 Jenkins方式一&#xff1a;brew方式二&#xff1a;tomcat Jenkins war 关于 Jenkins 官网上下载Jenkins并将其安装到持续集成服务器 https://jenkins.io/download/ macOS 上安装 Jenkins 现在本 macOS 上测试 https://www.jenkins.io/do…

[蓝桥杯2024]-PWN:fd解析(命令符转义,标准输出重定向)

查看保护 查看ida 这里有一次栈溢出&#xff0c;并且题目给了我们system函数。 这里的知识点没有那么复杂 完整exp&#xff1a; from pwn import* pprocess(./pwn) pop_rdi0x400933 info0x601090 system0x400778payloadb"ca\\t flag 1>&2" print(len(paylo…

消息服务应用1——java项目使用websocket

在当前微服务项目中&#xff0c;由于业务模块众多&#xff0c;消息服务的使用场景变得异常活跃。而WebSocket由于其自身的可靠性强&#xff0c;实时性好&#xff0c;带宽占用更小的优势&#xff0c;在实时通讯应用场景中独占鳌头&#xff0c;加上HTML5标准的普及流行&#xff0…

分类神经网络3:DenseNet模型复现

目录 DenseNet网络架构 DenseNet部分实现代码 DenseNet网络架构 论文原址&#xff1a;https://arxiv.org/pdf/1608.06993.pdf 稠密连接神经网络&#xff08;DenseNet&#xff09;实质上是ResNet的进阶模型&#xff08;了解ResNet模型请点击&#xff09;&#xff0c;二者均是…

Java面试八股文-2024

面试指南 TMD&#xff0c;一个后端为什么要了解那么多的知识&#xff0c;真是服了。啥啥都得了解 MySQL MySQL索引可能在以下几种情况下失效&#xff1a; 不遵循最左匹配原则&#xff1a;在联合索引中&#xff0c;如果没有使用索引的最左前缀&#xff0c;即查询条件中没有包含…

Altera FPGA 配置flash读写

目录 一、读写控制器的配置 二、生成flash的配置文件 三、关于三种配置文件的大小 四、其他 一、读写控制器的配置 Altera ASMI Parallel&#xff08;下文简称ASMI)这个IP就仅仅是个Flash读写控制器&#xff0c;可以自由的设计数据来源。 关于这个IP的使用&#xff0c;可以…

MAC有没有免费NTFS tuxera激活码 tuxera破解 tuxera for mac2023序列号直装版 ntfs formac教程

Tuxera NTFS 2023破解版是一款非常好用的在线磁盘读写工具&#xff0c;该软件允许mac用户在Windows NTFS格式的硬盘上进行读写操作&#xff0c;Mac的文件系统是HFS&#xff0c;而Windows则使用NTFS格式&#xff0c;这导致在Mac系统上不能直接读写Windows格式的硬盘。然而&#…