基于Android Studio的行程记录APK开发指南(三)---界面设计及两种方法获取用户位置
前言
- 本系列教程我们来看看如何使用Android Studio去开发一个APK用于用户的实时行程记录
- 第一期:基于Android Studio的用户行程记录APK开发指南(一):项目基础配置与速通Kotlin-CSDN博客
- 第二期:基于Android Studio的行程记录APK开发指南(二):熟悉一个项目结构-CSDN博客
- 前两期我们已经熟悉了kotlin语言特性和android studio一个项目模板的项目结构,本节将设计一个简单的UI,包含一个图片和文本及其一个按钮,当用户按下按钮时候将输出用户的位置信息
01 添加位置权限
- 为了在Android应用中获取用户的位置信息,我们需要在
AndroidManifest.xml
文件中添加位置相关的权限。(上一节我们提到过AndroidManifest描述了应用程序的组件以及应用程序的权限、主题和所需的库。) - 在
<manifest>
标签内,添加如下代码:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
ACCESS_FINE_LOCATION
:允许应用程序访问精确的位置信息。ACCESS_COARSE_LOCATION
:允许应用程序访问大致的位置信息。
02 设计程序界面
2-1 打开界面
-
我们这一节来设计一个简单的界面,回顾上一节,
res/layout/activity_main.xml
描述了MainActivity的界面设计 -
我们在右上角找到split按钮如下:
-
-
如此一来我们就可以实时进行xml编写和查看效果展示了
2-2 导入图片
-
上一节说到,
res/drawable
文件夹通常存放图像资源,这里我们导入一张下载好的图片,放到drawable中,这时候图像就可以通过@drawable/pyrmont
被访问 -
我们在activity_main.xml中添加一个ImageView组件,并指定位置,这时候图片就被导入到我们的界面中了
-
这时候我们点击图片右侧圆形,拖动直至右边框,这样图片就被绑定到界面的右侧
-
这样无论是怎么样的设备,图像都会加载到屏幕的最右侧
-
同理我们把图片绑定到正中央,代码会根据拖动自动生成对应的代码
<ImageView android:layout_width="271dp" android:layout_height="278dp" android:src="@drawable/pyrmont" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.291">
</ImageView>
2-3 添加文本
- 同样我们添加一个文本
<TextView android:id="@+id/text_location" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="当前位置" android:textSize="20sp" app:layout_constraintTop_toBottomOf="@+id/imageView"></TextView>
android:id="@+id/text_location"
: 为TextView
设置了一个唯一标识符,这样我们可以在代码中引用它
android:layout_width="match_parent"
: 设置TextView
的宽度为父容器(通常是Activity的布局)的宽度。android:layout_height="wrap_content"
: 设置TextView
的高度为足够包裹其内容的最大高度。android:layout_margin="10dp"
: 在TextView
的上下左右四个方向都添加了10dp的边距。dp
(密度无关像素)是一个相对单位,用于根据屏幕密度调整元素的大小。android:text="当前位置"
: 设置TextView
中显示的文本内容为“当前位置”。android:textSize="20sp"
: 设置文本的大小为20sp(scale-independent pixels,与密度无关的像素)。sp
单位与dp
类似,但它是专门为字体大小设计的,可以根据用户的字体大小偏好自动缩放。- 这里我们同样拖动文本框的上部分到派蒙图片的正下方,代码自动生成
app:layout_constraintTop_toBottomOf="@+id/imageView"></TextView>
2-4 添加按钮
- 这里我们来学习如何自定义样式的按钮,我要创建一个灰色背景色,白色按钮的样式
- 搜先我们先来添加颜色,上一节我们提到了
res/values/colors.xml
中存放了基本的颜色
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="black">#FF000000</color><color name="white">#FFFFFFFF</color><color name="gray">#A8A8A8</color> <!-- 灰色 -->
</resources>
- 同时我们在在res文件夹下创建styles.xml,用于存档风格资源
<?xml version="1.0" encoding="utf-8"?>
<resources> <style name="CustomGrayButtonStyle"> <item name="android:textSize">30sp</item> <item name="android:textColor">@color/white</item> <!-- 白色文本 --> <item name="android:backgroundTint">@color/gray</item> <!-- 灰色背景 --> <item name="android:padding">10dp</item> <item name="android:layout_margin">10dp</item> <item name="android:layout_width">187dp</item> <item name="android:layout_height">113dp</item> </style></resources>
- 回到activity_main.xml,我们就可以直接引用这个按钮了
<Button android:id="@+id/button_getLocation" android:text="开!" style="@style/CustomGrayButtonStyle" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" />
-
同时我们绑定按钮在最下方的正中央
-
好至此我们简单的界面设计完毕,我们来完善代码
3 编写获取位置具体代码逻辑(方法1)
3-1 实例化控件
- 我们实例化刚刚设计的按钮和文本,我们需要导入库,这里导入一个
Toast
,Toast
是 Android 系统中提供的一种轻量级反馈机制,用于向用户显示简短的消息提示。它是一种非侵入式的 UI 元素,通常在屏幕底部以弹窗的形式出现,并在一段时间后自动消失,不会干扰用户的当前操作。
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
- 记得我们第一节提到的延迟实例化的时候使用lateinit
lateinit var button_location: Button
lateinit var text_location:TextView
- 获取控件
button_location = findViewById<Button>(R.id.button_getLocation)
text_location=findViewById<TextView>(R.id.text_location)
- 同时我们为按钮绑定一个函数,当用户按下按钮时,会弹出一个信息,过一会就会自动消失
button_location.setOnClickListener { Toast.makeText(this, "按钮被按下", Toast.LENGTH_SHORT).show()
}
3-2 获取位置
FusedLocationProviderClient
是 Google Play 服务提供的一个类,用于简化对设备位置信息的访问。它是一个高级的 API,旨在提供更准确和更高效的位置信息,同时减少电池消耗。FusedLocationProviderClient
结合了多种位置来源,包括 GPS、Wi-Fi 和移动网络,以提供最佳的位置信息。
lateinit var fusedLocationProviderClient:FusedLocationProviderClient
- 这里我们编写一个
getUserLocation
函数,用于获取用户设备的当前地理位置。
private fun getUserLocation() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 100) Toast.makeText(this,"未获取权限",Toast.LENGTH_LONG).show() return } val location=fusedLocationProviderClient.lastLocation location.addOnSuccessListener { if(it!=null) { val latitude = it.latitude.toString() val longitude = it.longitude.toString() text_location.text = "Latitude: $latitude\nLongitude:$longitude" } } location.addOnFailureListener {exception -> text_location.text=exception.localizedMessage Toast.makeText(this, "获取位置信息失败: ${exception.localizedMessage}", Toast.LENGTH_LONG).show() } }
- 搜先我们需要检查应用是否有访问精确位置(GPS)的权限
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTE
- 如果用户没有同意,我们需要
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 100)
请求权限,并将请求码设置为100
。同时,弹出一个 Toast 提示用户未获取权限。 - 如果应用有权限,调用
fusedLocationProviderClient.lastLocation
方法来获取设备的最后已知位置。这个方法返回一个Task<Location>
对象addOnSuccessListener
添加一个成功监听器,当位置获取成功时,这个监听器会被调用。addOnFailureListener
添加一个失败监听器,当位置获取失败时,这个监听器会被调用。
- 最后我们吧这个函数和按钮绑定
button_location.setOnClickListener{ getUserLocation()
}
3-3 运行
-
运行会进行位置提示,用户可以选择是否允许使用位置权限
-
同意权限将输出位置的经纬度信息
-
Android Studio 模拟器默认的经纬度位置通常是位于美国加利福尼亚州的谷歌总部附近,即纬度大约为 37.4219999,经度大约为 -122.084。这个位置是模拟器在启动时默认设置的,因此,如果你没有在模拟器设置中更改位置,那么应用获取到的位置信息将会是这个默认位置。
-
值得一提的是我们可以修改虚拟设备的GPS位置,找到Extended Controls
-
在Location中可以更改地理位置
-
此外细心的朋友会发现一个小问题,这里使用的定位是基于Google Play服务的,那如果用户手机不支持这个服务怎么办,后面我们会细说
4 导出APK
APK
- APK(Android Package Kit)是一种用于打包和分发Android应用程序的文件格式。它包含了应用程序的所有文件,如代码、资源、资产、证书和清单文件等。APK文件是Android操作系统中应用程序安装和更新的基本单元。
- APK文件通常具有
.apk
扩展名,并且可以被安装在支持Android的设备上。
导出APK
-
成功在模拟器运行了这个小demo,相信各位已经迫不及待想在自己手机尝试了吧
-
在build中选择生成APK
-
这里我们选择APK
-
初次使用的话需要新建存储钥匙
-
这里看着填一下就行
-
创建完后选择钥匙存储地,再次next
-
选择APK生成位置,选择release版本,点击create等待片刻
-
APK生成成功后会出现提示
-
我们来到安装位置,就拿到我们的APK文件了
5 实机运行与问题分析
遇到问题
-
拿到APK放到手机上是否满心欢喜?没事,不出意外的话该出意外了
-
我们把APK移动到手机上,点击安装,运行,然后,完辣
-
仔细的朋友已经明白了,我的手机没有google play服务,天塌了亚(不是)
-
在用户设备不支持Google Play的情况下,我们可以使用其他方式来获取用户的地理位置。一个常见的选择是使用Android的
LocationManager
API,该API是Android原生支持的一部分,不需要依赖Google Play服务。
6 获取位置再战(方法2)
6-1 LocationManager
LocationListener
是 Android 开发中的一个接口,它允许我们的应用接收关于设备位置变化的更新。当设备的位置发生改变时,系统会通过LocationListener
调用我们的应用中实现的方法,以便我们能够根据这些变化做出相应的反应。- 我们继承自
LocationListener
class MainActivity : AppCompatActivity(),LocationListener
-
LocationListener
接口包含以下三个方法:onLocationChanged(Location location)
: 当设备的位置发生变化时,这个方法会被调用。我们可以通过传递给这个方法的Location
对象来获取新的位置信息,如经度、纬度、海拔等。onStatusChanged(String provider, int status, Bundle extras)
: 当位置提供者的状态发生变化时,这个方法会被调用。状态变化可能包括位置提供者变为可用、不可用或者位置更新发生错误。provider
参数指定了位置提供者的名称,如LocationManager.GPS_PROVIDER
或LocationManager.NETWORK_PROVIDER
。onProviderEnabled(String provider)
: 当位置提供者被启用时,这个方法会被调用。这通常发生在用户在设置中启用 GPS 或网络位置服务时。onProviderDisabled(String provider)
: 当位置提供者被禁用时,这个方法会被调用。这通常发生在用户在设置中禁用 GPS 或网络位置服务时。
-
要使用
LocationListener
,我们需要在我们的应用中实现这个接口,并在适当的时候注册和注销监听器。注册监听器通常是通过调用LocationManager.requestLocationUpdates()
方法来完成的,而注销监听器则是通过调用LocationManager.removeUpdates()
方法。 -
但值得一提的是,onStatusChanged,onProviderEnabled,onProviderDisabled这几个函数在API 29以上的版本被设置为过时了
-
我们继承自LocationListener,并点击红色灯泡选择复写方法
-
选择方法
-
代码自动就会为你生成
override fun onLocationChanged(p0: Location) { TODO("Not yet implemented")
}
6-2 配置LocationMannager
LocationManager
是 Android 系统中用于管理设备位置服务的类。它允许您访问各种位置提供者,如 GPS、Wi-Fi 和移动网络,以获取设备的当前位置。LocationManager
提供了多种方法来查询和监听位置更新,以及管理位置提供者的状态。- GPS_PROVIDER: 提供最准确的位置数据,但功耗较高。
- NETWORK_PROVIDER: 使用设备的网络连接(如 Wi-Fi 和移动数据)来获取位置,速度较快但精度较低。
- PASSIVE_PROVIDER: 不主动获取位置,而是作为其他提供者的辅助,减少电量消耗。
lateinit var location_mannager:LocationManager
- 同样的我们创建一个getUserLocation的函数
private fun getUserLocation()
{ location_mannager=getSystemService(Context.LOCATION_SERVICE) as LocationManager location_mannager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000,5f,this)
}
location_mannager=getSystemService(Context.LOCATION_SERVICE) as LocationManager
- 这一行代码获取系统的
LocationManager
服务。getSystemService(Context.LOCATION_SERVICE)
返回一个Object
,我们使用as
关键字将其转换为LocationManager
类型。这样,我们就可以使用LocationManager
的方法来请求位置更新。
- 这一行代码获取系统的
- 后一行代码是请求位置更新的核心。
requestLocationUpdates
方法接受四个参数:
-LocationManager.GPS_PROVIDER
: 指定使用 GPS 作为位置提供者。您也可以使用其他提供者,如LocationManager.NETWORK_PROVIDER
。
-5000
: 这是更新间隔的时间,以毫秒为单位。在这个例子中,它设置为 5000 毫秒(5 秒)。
-5f
: 这是位置变化的最小距离,以米为单位。在这个例子中,它设置为 5 米。这意味着设备的位置至少需要移动 5 米,才会触发位置更新。
-this
: 这是指向当前活动(MainActivity
)的引用,因为活动实现了LocationListener
接口。当位置更新发生时,onLocationChanged
方法会被调用。
-
我们进行requestLocationUpdates时根据IDE提示,我们需要在获取位置之前进行权限检查
-
和上面一样,我们选择让他帮我补全(doge)
-
如下
-
我们只需要添加,当用户权限被禁止时候,申请同步
private fun getUserLocation()
{ location_mannager=getSystemService(Context.LOCATION_SERVICE) as LocationManager if (ActivityCompat.checkSelfPermission( this, ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { Toast.makeText(this,"Permission denied", Toast.LENGTH_SHORT).show() ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),100 ) return } location_mannager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000,5f,this)
}
6-3 获取位置信息更新
- 回到onLocationChanged函数,这次我们直接生成APK,尝试,让后成功!
override fun onLocationChanged(p0: Location) { text_location.text=p0.latitude.toString()+","+p0.longitude.toString()
Toast.makeText(this,""+p0.latitude.toString()+p0.longitude.toString(),Toast.LENGTH_SHORT).show()
}
6-4 实测
- 手机实测如下(具体的信息我就不公布了哈哈哈,因为他真的超级准…害怕史密达)
7 Geocoder(题外话)
- Geocoder 是一种编程接口,用于将地理坐标(如纬度和经度)转换为具体的地址信息,或者将地址信息转换为地理坐标。这种转换通常被称为地理编码(geocoding)和反向地理编码(reverse geocoding)。
- 在 Android 开发中,Geocoder 类提供了这种功能。它允许开发者在应用中实现位置搜索、地图显示、地址验证等功能。Geocoder 使用了多种数据源来提供尽可能准确的位置信息,包括街道名称、城市、州、邮政编码和国家等。
override fun onLocationChanged(p0: Location) { val geocoder = Geocoder(this, Locale.getDefault()) val addresses: List<Address>? try { addresses = geocoder.getFromLocation(p0.latitude, p0.longitude, 1) if (addresses != null && addresses.isNotEmpty()) { val address = addresses[0] val streetAddress = address.getAddressLine(0) ?: "No street address" val country = address.countryName ?: "No country found" val addressText = if (streetAddress.isNotBlank() && country.isNotBlank()) { "$streetAddress,$country" } else { "No detailed address available" } val latitudeText = "Latitude: ${p0.latitude.toString()}" val longitudeText = "Longitude: ${p0.longitude.toString()}" text_location.text = "$addressText\n$latitudeText\n$longitudeText" Toast.makeText(this, "$addressText\n$latitudeText\n$longitudeText", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { e.printStackTrace() text_location.text = "Geocoder error" Toast.makeText(this, "Geocoder error", Toast.LENGTH_SHORT).show() }
}
- 效果如下,手机版就不展示了,是可以用的
代码汇总
- 法1:
package com.example.pathrecorderapp import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.widget.Toast
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices class MainActivity : AppCompatActivity() { lateinit var button_location: Button lateinit var text_location:TextView lateinit var fusedLocationProviderClient:FusedLocationProviderClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this) button_location = findViewById<Button>(R.id.button_getLocation) text_location=findViewById<TextView>(R.id.text_location) button_location.setOnClickListener{ getUserLocation() } ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } } private fun getUserLocation() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 100) Toast.makeText(this,"未获取权限",Toast.LENGTH_LONG).show() return } val location=fusedLocationProviderClient.lastLocation location.addOnSuccessListener { if(it!=null) { val latitude = it.latitude.toString() val longitude = it.longitude.toString() text_location.text = "Latitude: $latitude\nLongitude:$longitude" } } location.addOnFailureListener {exception -> text_location.text=exception.localizedMessage Toast.makeText(this, "获取位置信息失败: ${exception.localizedMessage}", Toast.LENGTH_LONG).show() } } }
- 法2
package com.example.pathrecorderapp import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.content.Context
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.widget.Toast
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import java.io.IOException
import java.util.Locale class MainActivity : AppCompatActivity(),LocationListener { lateinit var button_location: Button lateinit var text_location:TextView lateinit var location_mannager:LocationManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) button_location = findViewById<Button>(R.id.button_getLocation) text_location=findViewById<TextView>(R.id.text_location) button_location.setOnClickListener{ getUserLocation() } ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } } private fun getUserLocation() { location_mannager=getSystemService(Context.LOCATION_SERVICE) as LocationManager if (ActivityCompat.checkSelfPermission( this, ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { Toast.makeText(this,"Permission denied", Toast.LENGTH_SHORT).show() ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),100 ) return } location_mannager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000,5f,this) } override fun onLocationChanged(p0: Location) { val geocoder = Geocoder(this, Locale.getDefault()) val addresses: List<Address>? try { addresses = geocoder.getFromLocation(p0.latitude, p0.longitude, 1) if (addresses != null && addresses.isNotEmpty()) { val address = addresses[0] val streetAddress = address.getAddressLine(0) ?: "No street address" val country = address.countryName ?: "No country found" val addressText = if (streetAddress.isNotBlank() && country.isNotBlank()) { "$streetAddress,$country" } else { "No detailed address available" } val latitudeText = "Latitude: ${p0.latitude.toString()}" val longitudeText = "Longitude: ${p0.longitude.toString()}" text_location.text = "$addressText\n$latitudeText\n$longitudeText" Toast.makeText(this, "$addressText\n$latitudeText\n$longitudeText", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { e.printStackTrace() text_location.text = "Geocoder error" Toast.makeText(this, "Geocoder error", Toast.LENGTH_SHORT).show() } } }
总结
- 本节介绍了如何使用Andriod Studio进行界面设计,并使用了两种方式进行位置获取,并介绍 了APK的导出
- 如有错误,欢迎指出,下一节我们看看如何进行自动运行和数据自动保存画图
相关文章:

基于Android Studio的行程记录APK开发指南(三)---界面设计及两种方法获取用户位置
前言 本系列教程我们来看看如何使用Android Studio去开发一个APK用于用户的实时行程记录 第一期:基于Android Studio的用户行程记录APK开发指南(一):项目基础配置与速通Kotlin-CSDN博客第二期:基于Android Studio的行程记录APK开发指南(二):…...
大厂趋势:低代码不等于低能力,赋能高效开发新纪元
大厂趋势:低代码不等于低能力,赋能高效开发新纪元 在数字化转型的浪潮中,科技巨头(大厂)作为行业的引领者,不断探索和创新,以应对日益复杂多变的市场需求和技术挑战。其中,“低代码…...

CentOS全面停服,国产化提速,央国企信创即时通讯/协同门户如何选型?
01. CentOS停服带来安全新风险, 国产操作系统迎来新的发展机遇 2024年6月30日,CentOS 7版本全面停服,于2014年发布的开源类服务器操作系统——CentOS全系列版本生命周期画上了句号。国内大量基于CentOS开发和适配的服务器及平台,…...

如何确定Kubernetes是在采用哪种方式进行部署的?
这里写目录标题 1. 查看 Kubernetes 安装方式的常见文件和工具2. 检查 Kubernetes 的节点信息3. 检查 Kubernetes API 服务器的版本信息4. 检查系统服务和容器5. 查看安装文档或管理员笔记为什么可以确定是 kubeadm 部署?下一步确认 如果存在多个master节点…...

【PostgreSQL】地理空间数据的数据类型定义、索引优化、查询优化策略
PostgreSQL 是开源关系型数据库,对于地理空间数据的处理提供了很好的支持。在处理地理空间数据时,优化索引和查询的性能至关重要,因为地理空间操作通常涉及大量的数据计算和复杂的几何形状比较。 一、地理空间数据类型 注意geometry和geogra…...
RocketMQ广播消费消息
1、 基础概念 RocketMQ 支持两种消息模式:集群消费( Clustering )和广播消费( Broadcasting )。 集群消费模式(Cluster): 在集群消费模式下,同一个消费者组(…...
C#基础(2)枚举
前言 我们其实在前面已经了解过枚举到底有什么作用,但是那毕竟是概念性的语言,理解起来很抽象,今天我们会具体来讲一讲枚举,并谈一谈它的应用。 希望你能从今天的C#基础中有所收获。 基本概念 1.枚举:是一个比较特…...

Linux之MySQL日志
前言 数据库就像一个庞大的图书馆,而日志则是记录这个图书馆内每一本书的目录。正如在图书馆中找到特定书籍一样,数据库日志帮助我们追溯数据的变更、定位问题和还原状态。 在MySQL中,日志是非常重要的一个组成部分,它记录了数据…...

Redis集群模式—主从集群、哨兵集群、分片集群
主从集群 主从模式中,包括一个主节点(Master)和一个或多个从节点(Slave)。主节点负责处理所有写操作和读操作,而从节点则复制主节点的数据,并且只能处理读操作。当主节点发生故障时,…...

并发工具类(二):CyclicBarrier
1、CyclicBarrier 介绍 从字面上看 CyclicBarrier 就是 一个循环屏障,它也是一个同步助手工具,它允许多个线程 在执行完相应的操作后彼此等待共同到达一个屏障点。 CyclicBarrier可以被循环使用,当屏障点值变为0之后,可以在接下来…...
Spring Cloud全解析:负载均衡之Ribbon简介
Ribbon简介 Ribbon是一种客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起,提供了一系列完善的配置如连接超时、重试等,Ribbon会自动的帮助基于某种规则(如简单轮询、随机连接等)去连接那些机器,也可以自定义的负载均衡…...
Kettle安装与使用指南
1. 介绍 什么是Kettle? Kettle,全称Pentaho Data Integration (PDI),是Pentaho BI套件的一部分。它提供了一个可视化的ETL工具,允许用户通过图形界面设计复杂的数据集成流程。Kettle支持多种数据源,包括关系型数据库…...

教育行业解决方案:智能PPT在教育行业的创新应用
在信息化时代,教育行业面临着巨大的变革。随着人工智能技术的不断发展,传统教学方式正在被重新定义。彩漩科技作为 AI 技术的先行者,推出了歌者 PPT &彩漩 PPT,为教师、学生和家长提供了一种全新的教育体验,实现了…...

Matlab程序练习
Part1 1.求 [100,999] 之间能被 21整除的数的个数。 程序: 主文件:main.m clear; start_num 100; end_num 999; div_num 21; res div(start_num,end_num,div_num); fprintf("[%d,%d]之间能被%d整除的数的个数为%d个\n",start_num,end_…...

cesium可不可以改变影像底图颜色,如何给地球底图影像添加一层滤镜蒙版?
废话:你的球是不是很丑?是不是没有科技感?是不是没有好看的影像? 因果: 因:客户问,底图可不可以改变颜色,想让球更漂亮一些。 答:可以改变影像饱和度,透明度…...

MyBatis-MappedStatement什么时候生成?QueryWrapper如何做到动态生成了SQL?
通过XML配置的MappedStatement 这部分MappedStatement主要是由MybatisXMLMapperBuilder进行解析,核心逻辑如下: 通过注解配置的MappedStatement 核心逻辑就在这个里面了: 继承BaseMapper的MappedStatement 我们看看这个类,里…...
Netty系列-2 NioServerSocketChannel和NioSocketChannel介绍
背景 本文介绍Netty的通道组件NioServerSocketChannel和NioSocketChannel,从源码的角度介绍其实现原理。 1.NioServerSocketChannel Netty本质是对NIO的封装和增强,因此Netty框架中必然包含了对于ServerSocketChannel的构建、配置以及向选择器注册&am…...

智能客服的四大优势,提升企业服务效率
在这个信息化快速发展的时代,客户服务的重要性越来越凸显。传统的客服方式已经无法满足企业日益增长的服务需求,于是智能客服服务应运而生。智能客服服务不仅改变了企业与客户的互动方式,还提高了服务效率和客户满意度。本文将深入探讨智能客…...
AutoGPT开源项目解读
AutoGPT开源项目解读 (qq.com) AutoGPT旨在创建一个自动化的自我改进系统,能够自主执行和学习各种任务 项目基本信息 首先阅读项目的README.md,下述代理和智能体两个名词可互换 项目简介:一个创建和运行智能体的工具,这些智能体…...

Linux离线安装fontconfig
Linux离线下载yum包,安装字体库 一、下载安装包 以CentOS Linux release 7.9.2009下载fontconfig的rpm包的为例 http://mirror.centos.org/centos/7/按提示跳转历史库 找到对应版本的centos https://vault.centos.org/7.9.2009/os/x86_64/Packages/在Packages目…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...