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

如何用nat123做网站广东vs北控直播

如何用nat123做网站,广东vs北控直播,重庆网络推广平台,中国最顶尖的平面设计公司一、优化思路 对之前的天气预报的app进行了优化#xff0c;原先的天气预报程序逻辑是这样的。 使用text和button组合了一个输入城市#xff0c;并请求openweathermap对应数据#xff0c;并显示的功能。 但是搜索城市的时候#xff0c;可能会有错误#xff0c;比如大小写…一、优化思路 对之前的天气预报的app进行了优化原先的天气预报程序逻辑是这样的。 使用text和button组合了一个输入城市并请求openweathermap对应数据并显示的功能。 但是搜索城市的时候可能会有错误比如大小写比如拼写之类的所以打算给他升级一下。 目标 在搜索的时候需要更够显示搜索的结果然后在搜索的结果中显示符合的城市列表需要有全球的城市数据搜索结果过滤后显示符合的城市在符合搜索结果的内容中可以点击需要的城市并把城市的天气显示在主界面里。 二、准备城市的资料 获取城市的json压缩包 网址https://bulk.openweathermap.org/sample/ 下载链接https://bulk.openweathermap.org/sample/city.list.json.gz 把下载文件加入进项目里可以有两个位置一个是res/assert一个是res/raw它们的主要区别在于 res/raw res/raw 目录用于存储原始文件这些文件不会被 Android 资源编译器进行处理或修改。您可以在这个目录下放置各种类型的原始文件例如音频文件、视频文件、文本文件等。资源文件放置在 res/raw 目录下会保持原始状态不会被修改。 res/assert res/assert 目录也用于存储原始文件但其中的文件会被 Android 资源编译器进行压缩和优化处理。通常用于存放一些较小的非常规资源文件例如 JSON 文件、XML 文件等。资源文件放置在 res/assert 目录下会被压缩和优化这可能会使得访问这些资源稍微快一些。 如果希望保持资源文件的原始状态不经过任何修改或处理可以将它们放置在 res/raw 目录下。 如果资源文件较小且希望进行优化处理可以考虑放置在 res/assert 目录下。 这里我们把它放在res/raw目录下因为它是一个gz的压缩文件。 三、解压城市的gz文件 为这个文件编写代码让软件在启动时检查是否有解压文件如果没有解压文件就解压到files目录下。 files 文件夹通常用于存储应用的私有文件。这些文件是应用专用的其他应用无法访问。以下是关于 files 文件夹的一些主要特点 私有性files 文件夹中的文件只能被创建它们的应用访问其他应用无法直接访问这些文件。持久性与 cache 目录不同files 文件夹中的文件不会因为系统资源不足而被清除。这些文件会持久保存直到应用被卸载或明确删除。文件访问可以通过 Context 对象提供的方法如 openFileOutput() 和 openFileInput()来访问 files 文件夹中的文件。存储位置files 文件夹通常位于应用的私有数据目录中。具体路径通常为 /data/data/包名/files/。用途files 文件夹适用于存储各种类型的应用数据如用户配置、日志文件、缓存数据等。 创建一个CityListDataManager的类并在init时判断文件是否存在如果不存在就把gz文件解压到files目录下 class CityListDataManager(private val context: Context) {private val tag CityListDataManagerprivate val jsonFileName city.list.jsonprivate val cityListJsonFile : File File(context.filesDir, jsonFileName)private lateinit var cityDataList : ArrayCityDatainit {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内容创建对应的类两个数据类Coord 和 CityData。Coord 类表示地理坐标包含经度 (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 数据。具体步骤如下 创建 Gson 实例。打开应用的文件目录并指定要读取的文件名。使用 FileInputStream 打开文件并创建 BufferedReader 来逐行读取文件内容。使用 StringBuilder 来构建完整的文件内容。在 while 循环中逐行读取文件内容并将每行添加到 StringBuilder 中。读取完成后将 StringBuilder 中的内容转换为字符串。使用 Gson 的 fromJson 方法将 JSON 字符串转换为 CityData 对象数组。将解析后的 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, ArrayCityData::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() }在CityListDataManager的init中调用它 init {CoroutineScope(Dispatchers.IO).launch {if(!isExistCityListJsonFile()) {unzipGzFile(context)}readContentOneByOne(context)}}五、创建Material Search Bar 根据最新的Material Design的Search说明文档可以在MainActivity里套用它的模版来使用 androidx.coordinatorlayout.widget.CoordinatorLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parent!-- NestedScrollingChild goes here (NestedScrollView, RecyclerView, etc.). --androidx.core.widget.NestedScrollViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentapp:layout_behaviorstring/searchbar_scrolling_view_behavior!-- Screen content goes here. 这里放显示的主内容 --/androidx.core.widget.NestedScrollViewcom.google.android.material.appbar.AppBarLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentcom.google.android.material.search.SearchBarandroid:idid/search_barandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:hintstring/searchbar_hint //com.google.android.material.appbar.AppBarLayoutcom.google.android.material.search.SearchViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:hintstring/searchbar_hintapp:layout_anchorid/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()returnsetOnEditorActionListener false}这样我们一个基本的搜索框架就搭建好了还需要把结果数据显示出来 七、用recycleview显示搜索结果 在SearchView中添加recycleview控件 com.google.android.material.search.SearchViewandroid:idid/search_viewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:hintstring/editTextCityHintandroidx.recyclerview.widget.RecyclerViewandroid:idid/cityDataRecyclerViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_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: ListCityData) :RecyclerView.AdapterCityDataAdapter.ViewHolder() {private var filterCityDataList : MutableListCityData 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.findViewByIdTextView(R.id.city_data_id)val cityDataName : TextView view.findViewByIdTextView(R.id.city_data_name)val cityDataCountry : TextView view.findViewByIdTextView(R.id.city_data_country)val cityDataCoordinate: TextView view.findViewByIdTextView(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.sizeSuppressLint(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事件来处理。需要在注册的时候就绑定相关的消息 创建了一个 CityDataAdapter 的实例并传入城市数据列表作为参数。为 CityDataAdapter 设置了点击事件的回调函数 onItemClick在点击城市数据项时执行以下操作 获取点击的城市名称 cityName。使用 RetrofitClient 获取该城市的天气信息和预报信息。创建一个包含点击项名称的提示消息 message。隐藏搜索视图可能是搜索框之类的。弹出一个短暂的 Toast 消息显示 message。 将适配器设置到城市数据的 RecyclerView 中用于显示城市数据列表。 private fun updateCityDataList(cityDataList: ListCityData) {val adapter CityDataAdapter(cityDataList)adapter.onItemClick { cityData -val cityName cityData.nameRetrofitClient.getWeatherByCityName(cityName)RetrofitClient.getForecastByCityName(cityName)val message Click item name: $cityNamebinding.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(emptyListCityData())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)returnsetOnEditorActionListener false}}使用 supportFragmentManager 开始一个事务并将一个 CityWeatherFragment 替换到 ID 为 fragment_container 的容器中。设置 forecastRecyclerView 和 cityDataRecyclerView 的布局管理器为 LinearLayoutManager以确保它们的布局是线性的。为 cityDataRecyclerView 设置一个空的城市数据列表适配器 CityDataAdapter以便后续更新城市数据。为搜索栏 searchBar 设置点击事件监听器点击时显示搜索视图 searchView。为搜索视图的编辑文本框设置编辑动作监听器当用户执行编辑动作时比如按下回车键执行以下操作 获取编辑框中的文本内容。弹出一个短暂的 Toast 消息显示文本内容。从 cityDataRecyclerView 的适配器中获取 CityDataAdapter 实例并调用其 setFilter 方法传入文本内容作为过滤条件。
http://www.zqtcl.cn/news/238266/

相关文章:

  • 网站标题写什么作用是什么网络推广学校培训
  • 看室内设计效果图网站网站建设需要条件
  • html教程网站做网站用哪个服务器
  • 济南网站建设 推搜点江阴响应式网站建设
  • 网站建设在windos的设置crm平台
  • 企业如何建设网站高端商城网站建设
  • 怎么制作app网站以下什么是网页制作软件
  • 网站定制一般价格多少石家庄做网站wsjz
  • 如何建立外卖网站网站可以做的活动推广
  • 手机号注册网站cms影视源码采集
  • 网站建设网页设计培训班连云港seo优化
  • 成都网站建设公司招聘定制衣服
  • 做访问量高的网站如何建立公司网站推广
  • 做公司的网站有哪些简述企业网站建设的流程
  • 网站免费获取验证码怎么做软件开发的工作
  • 萌宝宝投票网站怎么做正规网站建设多少费用
  • 产权交易网站建设方案耐克网站建设的历程
  • 网站建设投入及费用wordpress 收录插件
  • 东莞网站制作个性化清溪网站仿做
  • 简单展示网站模板天津建设网站哪家好
  • 建个人网站赚钱多吗福建省住房和城乡建设厅网站首页
  • 网站建设课程设计实训心得seo关键词优化方案
  • 逸阳网站建设的目标郑州建设电商网站
  • 有了网址怎么做网站上海网站推广服务
  • 惠州网站seo排名优化esc怎么做网站
  • 咨询公司网站设计网站建设技能
  • 上海湖南网站建设新学校网站建设成果
  • 网站开发有哪些竞赛建站行业新闻
  • 满足seo需求的网站大型网站常见问题
  • 做网站要求高吗珠宝网站建设