[Android]常见的数据传递方式
Demo:https://github.com/Gamin-fzym/DataTransferDemo
1.Intent
发送页面 A 到页面 B 的 Intent 时,可以通过 Intent 的 putExtra() 方法将数据附加到 Intent 上。
在页面 B 中,通过 Intent 的 getXXXExtra() 方法获取传递的数据。
1).在A页面发送 Intent
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.example.datatransferdemo.databinding.ActivityMainBinding
import com.example.datatransferdemo.pageb.PageB1class MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBinding// 获取返回结果,在Activity或Fragment中定义private val someActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK) {// 执行成功后的操作val intent: Intent? = result.datawhen (intent?.tag) {"PageB1" -> {var resultValue = intent?.getStringExtra("result_key")}"PageB2" -> {val bundle = intent?.extras}}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)// 1.Intentbinding.button1.setOnClickListener {val intent = Intent(this, PageB1::class.java)intent.putExtra("key", "传递字符串") // 可选:添加要传递的数据// 启动目标 Activity//startActivity(intent)// 如果希望在目标 Activity 中获取返回结果,使用ActivityResultLauncher来启动someActivityResultLauncher.launch(intent);}}}
2).在B页面接收数据
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.datatransferdemo.Rclass PageB1 : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_page_b1)// 获取传递过来的值val value = intent.getStringExtra("key")// 离开回传数据val but = findViewById<Button>(R.id.button)but.setOnClickListener {val returnIntent = Intent()returnIntent.tag = "PageB1"returnIntent.putExtra("result_key", "返回字符串")setResult(RESULT_OK, returnIntent)finish() // 结束当前Activity, 不一定要立即结束。}}
}
3).拓展Intent用来区分回传数据
使用扩展函数为 Intent 添加一个自定义的 tag属性
import android.content.Intentvar Intent.tag: String?get() = getStringExtra("tag")set(value) {putExtra("tag", value)}
2.Bundle
类似于 Intent,可以使用 Bundle 在页面间传递数据。
在发送页面 A 到页面 B 的过程中,将数据放入 Bundle 对象中。
在接收页面 B 中,从 Intent 中获取 Bundle 对象,并从 Bundle 中提取数据。
1).在A页面发送 Bundle
val bundle = Bundle()
bundle.putInt("id",123)
bundle.putBoolean("status",true)
bundle.putString("content", "传递字符串")
val intent = Intent(this, PageB2::class.java)
intent.putExtras(bundle)
// 启动目标 Activity
//startActivity(intent)
// 获取返回结果启动
someActivityResultLauncher.launch(intent);
2).在B页面接收数据
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.datatransferdemo.R
import com.example.datatransferdemo.tagclass PageB2 : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_page_b2)// 获取传递过来的值val bundle = intent.extrasval receivedID = bundle?.getInt("id") // 根据传递的数据类型使用对应的 getXXX() 方法val receivedStatus = bundle?.getBoolean("status")val receivedContent = bundle?.getString("content")// 离开回传数据val returnBundle = Bundle()returnBundle.putInt("id",123)returnBundle.putBoolean("status",true)returnBundle.putString("content", "传递字符串")val returnIntent = Intent()returnIntent.tag = "PageB2"returnIntent.putExtras(returnBundle)setResult(RESULT_OK, returnIntent)}
}
3.静态变量
在一个类中定义一个静态变量,其他页面可以直接访问该静态变量来传递数据。
适用于全局范围内需要传递数据的情况,但不适用于临时或有生命周期的数据传递。
1).定义静态变量
object StaticDataHolder {var sharedData = mapOf<String,String>()
}
2).在A页面设置数据
StaticDataHolder.sharedData = mapOf<String,String>("id" to "1234", "status" to "1", "content" to "传递字符串")
3).在B页面获取数据
val receivedData = StaticDataHolder.sharedData
4.SharedPreferences
使用 SharedPreferences 可以存储和读取键值对数据,并在不同页面间共享数据。
适用于需要长期存储和共享数据的情况。
1).在A页面设置数据
val sharedPref = getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val editor = sharedPref.edit()
editor.putString("key", data) // data 是要传递的数据
editor.apply()
2).在B页面获取数据
val sharedPref = getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val receivedData = sharedPref.getString("key", "") // 根据传递的数据类型使用对应的 getXXX() 方法
5.接口回调(Interface Callback)
定义一个接口,在页面 A 中实现该接口,并将实现类的实例传递给页面 B。
页面 B 可以调用接口的方法来传递数据给页面 A。
适用于页面间有交互和回调需求的情况。
1).定义接口
interface DataCallback {fun onDataReceived(data: String)
}
2).在页面 A 中实现接口
class PageA : AppCompatActivity(), DataCallback {// 静态的DataCallback实例companion object {var callbackInstance: DataCallback? = null}override fun onDestroy() {super.onDestroy()callbackInstance = null // 防止内存泄漏} override fun onDataReceived(data: String) {// 处理接收到的数据}// 在需要传递数据的地方将实现类的实例传递给页面 BcallbackInstance = this;val intent = Intent(this, PageB5::class.java)startActivity(intent)
}
3).在页面 B 中使用接口传递数据
// 调用DataCallback的方法if (MainActivity.callbackInstance != null) {MainActivity.callbackInstance?.onDataReceived("传递的数据")}
6.EventBus
使用 EventBus 库来进行页面间的事件传递和数据通信。
页面 A 发布一个事件,页面 B 订阅该事件并接收数据。
适用于解耦和简化页面间通信的情况。
1).添加 EventBus 到你的项目依赖中
dependencies {implementation 'org.greenrobot:eventbus:3.3.1'
}
2).创建一个事件类
这个类的作用是在组件之间传递数据
class MessageEvent(val message: String)
3).注册和注销EventBus
在您想要接收事件的组件(如Activity或Fragment)中,注册和注销EventBus。
override fun onStart() {super.onStart()EventBus.getDefault().register(this)
}override fun onStop() {super.onStop()EventBus.getDefault().unregister(this)
}
4).监听事件
在相同的组件中,添加一个方法来监听事件,这个方法需要用@Subscribe注解。
@Subscribe(threadMode = ThreadMode.MAIN)
public fun onMessageEvent(event: MessageEvent) {// 处理事件val data = event.message// ...处理数据
}
5).发布事件
在需要发送数据的地方,发布一个事件实例。
EventBus.getDefault().post(MessageEvent("Hello, EventBus!"))
6).示例
接收方
class ReceiverActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_receiver)}override fun onStart() {super.onStart()EventBus.getDefault().register(this)}override fun onStop() {super.onStop()EventBus.getDefault().unregister(this)}@Subscribe(threadMode = ThreadMode.MAIN)public fun onMessageEvent(event: MessageEvent) {// 这里处理接收到的事件Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show()}
}
发送方
class SenderActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_sender)// 假设有一个按钮用于发送事件val sendButton: Button = findViewById(R.id.sendButton)sendButton.setOnClickListener {// 当按钮被点击时,发布事件EventBus.getDefault().post(MessageEvent("Hello from SenderActivity!"))}}
}
7.Application 类
1).创建自定义Application类
创建一个新的Kotlin类,继承自Application类,并在该类中定义你想要传递的数据。
class MyApp : Application() {var globalData: String? = null// 你可以在这里定义更多的变量或方法
}
2).在AndroidManifest.xml中声明
在AndroidManifest.xml文件中的<application>标签内,使用android:name属性来指定你的自定义Application类。
<applicationandroid:name=".MyApp"...>...
</application>
3).在Activity或其他组件中使用
在任何Activity或其他组件中,你可以通过调用getApplication()方法来获取自定义Application类的实例,并访问其中定义的数据。
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val app = application as MyAppapp.globalData = "Some data"}
}
注意事项
-
使用Application传递数据时,要注意生命周期,因为当Android系统需要为其他应用释放内存时,它可能会杀死后台进程,这会导致Application对象被重建,数据可能会丢失。
-
这种方法适合传递少量的、全局需要的数据。如果数据量较大或者需要持久化存储,应该考虑使用数据库、SharedPreferences或其他存储机制。
-
为了避免内存泄漏,不要在Application类中持有Activity、View或其他上下文相关的引用。
通过这种方式,你可以在不同的组件间共享数据,但要确保对共享数据的访问是线程安全的。
8.Parcelable
Parcelable和Serializable是两种常用的数据传递方式。Parcelable是Android特有的接口,性能比Serializable好,但实现稍微复杂一些。Serializable是Java提供的接口,实现简单,但性能较差。
实现 Parcelable 接口,使对象能够在页面间进行序列化和反序列化传递。
适用于需要传递自定义对象的情况。
1).创建一个数据类,并实现Parcelable接口。
import android.os.Parcelable
import kotlinx.parcelize.Parcelize@Parcelize
data class User(val name: String, val age: Int) : Parcelable
从Kotlin 1.1.4开始,可以使用@Parcelize注解来自动实现Parcelable接口,前提是在项目的build.gradle文件中启用了kotlin-parcelize插件。
plugins {// 其它插件...id("org.jetbrains.kotlin.plugin.parcelize")
}
2).在启动新Activity时,将Parcelable对象放入Intent。
val intent = Intent(this, SecondActivity::class.java).apply {val user = User("John Doe", 30)putExtra("USER_KEY", user)
}
startActivity(intent)
3).在接收Activity中,从Intent中取出Parcelable对象。
class SecondActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_second)val user = intent.getParcelableExtra<User>("USER_KEY")user?.let {// 使用user对象}}
}
注意: 当使用Serializable时,所有序列化的对象中的子对象也必须实现Serializable接口。而Parcelable则需要每个子对象都要实现Parcelable接口。
建议在Android中优先使用Parcelable,因为它比Serializable更高效。
9.Serializable
创建一个实现 Serializable 接口的数据类。
在发送页面中创建数据对象,并将其放入 Intent 中。
在接收页面中从 Intent 中获取传递的 Serializable 对象。
1).创建一个数据类,并实现Serializable接口。
import java.io.Serializabledata class User(val name: String, val age: Int) : Serializable
2).在启动新Activity时,将Serializable对象放入Intent。
val intent = Intent(this, SecondActivity::class.java).apply {val user = User("John Doe", 30)putExtra("USER_KEY", user)
}
startActivity(intent)
3).在接收Activity中,从Intent中取出Serializable对象。
class SecondActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_second)val user = intent.getSerializableExtra("USER_KEY") as? Useruser?.let {// 使用user对象}}
}
10.数据库(Database)
使用数据库存储数据,并在不同页面间读取和写入数据。
可以使用 SQLite、Room 等数据库框架进行数据的持久化和共享。
适用于需要长期存储和大量数据共享的情况。
1).添加依赖
在项目的build.gradle文件中,添加Room数据库的依赖。
plugins {id("kotlin-kapt")
}android {...defaultConfig {...kapt {arguments {arg("room.schemaLocation", "$projectDir/schemas")}}}compileOptions {sourceCompatibility = JavaVersion.VERSION_17targetCompatibility = JavaVersion.VERSION_17}kotlinOptions {jvmTarget = "17"}...
}dependencies {implementation("androidx.room:room-runtime:2.5.0")//annotationProcessor("androidx.room:room-compiler:2.5.0")// For Kotlin use kapt instead of annotationProcessorkapt("androidx.room:room-compiler:2.5.0")// optional - Kotlin Extensions and Coroutines support for Roomimplementation("androidx.room:room-ktx:2.5.0")
}
2).定义数据模型
创建一个数据类,并使用@Entity注解标记,表示这是一个数据库表。
import androidx.room.Entity
import androidx.room.PrimaryKey@Entity
data class User(@PrimaryKey val id: Int,val name: String,val age: Int
)
3).创建DAO(数据访问对象)
定义一个接口,使用@Dao注解标记,里面包含访问数据库的方法。
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query@Dao
interface UserDao {@Insertsuspend fun insertUser(user: User): Long@Query("SELECT * FROM user WHERE id = :id")suspend fun getUserById(id: Int): User?
}
4).创建数据库实例
创建一个抽象类,继承自RoomDatabase,并使用@Database注解。
import androidx.room.Database
import androidx.room.RoomDatabase@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {abstract fun userDao(): UserDao
}
5).使用数据库
在您的Activity或Fragment中,获取数据库实例并执行数据库操作。
val db = Room.databaseBuilder(applicationContext,AppDatabase::class.java, "database-name"
).build()val userDao = db.userDao()// 插入用户
GlobalScope.launch {userDao.insertUser(User(1, "John Doe", 30))// 测试时每次修改一下ID,不然存在相同ID会报错
}// 查询用户
GlobalScope.launch {val user = userDao.getUserById(1)// 使用user对象
}
注意:
-
上述代码中使用了Kotlin协程来处理异步数据库操作。
-
Room.databaseBuilder()需要一个Context对象,通常您会在Activity或Application中调用它。
-
数据库操作(如插入和查询)不应在主线程上执行,因为它们可能会阻塞UI,所以应该在协程或其他异步机制中运行。
-
GlobalScope的使用在真实的应用程序中并不推荐,因为它的生命周期是整个应用程序,您应该使用具有更短生命周期的作用域,如lifecycleScope或viewModelScope。
11.文件(File)
将数据存储到文件中,在不同页面间通过读写文件来传递数据。
可以使用内部存储或外部存储来创建和访问文件。
适用于大量数据或需要持久化存储的情况。
1).定义一个帮助类或者函数来处理文件的读写操作
以下是一个简单的例子:
import android.content.Context
import java.io.*class FileHelper(private val context: Context) {fun writeToFile(fileName: String, data: String) {context.openFileOutput(fileName, Context.MODE_PRIVATE).use { outputStream ->outputStream.write(data.toByteArray())}}fun readFromFile(fileName: String): String {return context.openFileInput(fileName).bufferedReader().useLines { lines ->lines.fold("") { some, text ->"$some\n$text"}}}
}
2).在您的Activity或Fragment中,您可以使用这个帮助类来存储数据到文件。
class SomeActivity : AppCompatActivity() {private lateinit var fileHelper: FileHelperoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_some)fileHelper = FileHelper(this)// 保存数据到文件val dataToSave = "Some data to be shared"fileHelper.writeToFile("shared_data.txt", dataToSave)}private fun loadData() {// 从文件中读取数据val data = fileHelper.readFromFile("shared_data.txt")// 使用读取的数据// ...}
}
3).在另一个页面,您可以使用相同的FileHelper实例来读取之前写入的文件。
class AnotherActivity : AppCompatActivity() {private lateinit var fileHelper: FileHelperoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_another)fileHelper = FileHelper(this)// 读取数据val sharedData = fileHelper.readFromFile("shared_data.txt")// 使用数据// ...}
}
确保在使用文件进行数据传递时考虑到线程安全和性能问题。对于大量数据或频繁的读写操作,可能需要考虑使用其他数据传递方法,例如数据库或SharedPreferences。此外,对于敏感数据,请确保适当加密,以保护用户数据安全。
12. 网络请求(Network Request)
使用网络请求来传递数据,可以通过 HTTP 请求或其他网络协议进行数据交换。
发送方将数据通过网络发送给接收方,接收方通过解析网络响应来获取数据。
适用于远程数据交换或与服务器进行通信的情况。
1).添加网络权限到你的AndroidManifest.xml文件
<uses-permission android:name="android.permission.INTERNET" />
2).选择一个网络请求库
如Retrofit, OkHttp或Volley,这里以Retrofit为例。
3).添加所选网络库的依赖到你的build.gradle文件中
dependencies {// Retrofit & Gsonimplementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}
4).创建一个模型类来表示你的数据
data class User(val name: String, val email: String)
5).定义一个接口来描述HTTP请求
import retrofit2.Call
import retrofit2.http.GETinterface ApiService {@GET("users/info")fun getUserInfo(): Call<User>
}
6).使用Retrofit构建器实例化你的服务
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactoryobject RetrofitClient {private const val BASE_URL = "https://your.api.url/"val apiService: ApiService by lazy {Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}
}
7).发送网络请求并处理响应
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Responseclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)RetrofitClient.apiService.getUserInfo().enqueue(object : Callback<User> {override fun onResponse(call: Call<User>, response: Response<User>) {if (response.isSuccessful) {val userInfo = response.body()// 使用userInfo数据}}override fun onFailure(call: Call<User>, t: Throwable) {// 处理请求失败的情况}})}
}
13.ContentProvider
使用 ContentProvider 进行跨应用的数据共享和传递。
ContentProvider 提供了标准的接口和方法来操作数据,并可以通过 URI 进行数据的访问。
适用于需要在不同应用间共享数据的情况。
1).定义一个ContentProvider类
首先,创建一个类继承自ContentProvider并实现它的抽象方法。
class MyContentProvider : ContentProvider() {// 初始化ContentProvideroverride fun onCreate(): Boolean {// 初始化数据库等操作return true}// 查询数据override fun query(uri: Uri,projection: Array<String>?,selection: String?,selectionArgs: Array<String>?,sortOrder: String?): Cursor? {// 处理查询请求return null}// 插入数据override fun insert(uri: Uri, values: ContentValues?): Uri? {// 处理插入请求return null}// 更新数据override fun update(uri: Uri,values: ContentValues?,selection: String?,selectionArgs: Array<String>?): Int {// 处理更新请求return 0}// 删除数据override fun delete(uri: Uri,selection: String?,selectionArgs: Array<String>?): Int {// 处理删除请求return 0}// 返回MIME类型override fun getType(uri: Uri): String? {// 根据URI返回正确的MIME类型return null}
}
2).在AndroidManifest.xml中注册ContentProvider
<providerandroid:name=".MyContentProvider"android:authorities="com.example.myapp.provider"android:exported="true" />
android:authorities应该是唯一的,通常使用应用的包名作为前缀。
3).使用ContentResolver访问ContentProvider
其他应用可以使用ContentResolver来查询你的ContentProvider。
获取ContentResolver实例:
在你的应用中,你可以通过调用getContentResolver()方法来获取ContentResolver的实例。这通常在Activity或Service中进行。
val contentResolver = context.contentResolver
构建URI:
访问ContentProvider的数据时,你需要指定一个URI。这个URI指向你想要访问的数据集合或单个数据项。URI通常遵循这样的格式:content://<authority>/<path>,其中<authority>是在AndroidManifest.xml中注册ContentProvider时指定的,并且是唯一的。<path>是你希望访问的数据表或数据类型。
val uri: Uri = Uri.parse("content://com.example.myapp.provider/table_name")
查询数据:
使用ContentResolver的query()方法来请求数据。你可以指定列名、选择条件、选择参数和排序顺序。
val cursor: Cursor? = contentResolver.query(uri,projection, // String数组,代表你想要返回的列。selection, // SQL中的where子句,但不包括"WHERE"本身。selectionArgs, // 与selection中的占位符相匹配的值。sortOrder // 结果的排序方式。
)
处理返回的Cursor:
如果查询成功,query()方法将返回一个Cursor对象。通过这个Cursor,你可以遍历和读取数据。
cursor?.let {while (it.moveToNext()) {// 使用Cursor获取数据val columnValue = it.getString(it.getColumnIndex("column_name"))// 处理数据...}
}
cursor?.close() // 最后记得关闭Cursor
插入、更新和删除数据:
除了查询数据,ContentResolver还提供了insert(), update(), 和 delete()方法来进行数据的增、改、查操作。
// 插入数据
val newUri: Uri? = contentResolver.insert(uri, contentValues)// 更新数据
val rowsUpdated: Int = contentResolver.update(uri, contentValues, selection, selectionArgs)// 删除数据
val rowsDeleted: Int = contentResolver.delete(uri, selection, selectionArgs)
处理权限:
如果ContentProvider包含私有数据或者需要限制访问,你需要在AndroidManifest.xml中声明相应的权限,并在访问时请求这些权限。
安全性考虑:
当你的ContentProvider向其他应用公开数据时,需要考虑到数据安全性。确保对输入的URI进行验证,避免SQL注入等安全漏洞,并根据需要对访问进行身份验证和授权。
通过这种方式,ContentResolver和ContentProvider一起提供了一种强大的机制,允许应用之间安全、高效地共享数据。
相关文章:
[Android]常见的数据传递方式
Demo:https://github.com/Gamin-fzym/DataTransferDemo 1.Intent 发送页面 A 到页面 B 的 Intent 时,可以通过 Intent 的 putExtra() 方法将数据附加到 Intent 上。 在页面 B 中,通过 Intent 的 getXXXExtra() 方法获取传递的数据。 1).在A页面发送 …...

<蓝桥杯软件赛>零基础备赛20周--第7周--栈和二叉树
报名明年4月蓝桥杯软件赛的同学们,如果你是大一零基础,目前懵懂中,不知该怎么办,可以看看本博客系列:备赛20周合集 20周的完整安排请点击:20周计划 每周发1个博客,共20周(读者可以按…...

探究Kafka原理-7.exactly once semantics 和 性能测试
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理🔥如果感觉博主的文章还不错的话,请ὄ…...

【密码学引论】序列密码
第五章 序列密码 1、序列密码 定义: 加密过程:把明文与密钥序列进行异或运算得到密文解密过程:把密文与密钥序列进行异或运算得到明文以字/字节为单位加解密密钥:采用一个比特流发生器随机产生二进制比特流 2、序列密码和分组密…...

知识变现的未来:解析知识付费系统的核心
随着数字时代的发展,知识付费系统作为一种新兴的学习和知识分享模式,正逐渐引领着知识变现的未来。本文将深入解析知识付费系统的核心技术,揭示其在知识经济时代的重要性和潜力。 1. 知识付费系统的基本架构 知识付费系统的核心在于其灵活…...

【Linux基础】Linux常见指令总结及周边小知识
前言 Linux系统编程的学习我们将要开始了,学习它我们不得不谈谈它的版本发布是怎样的,谈它的版本发布就不得不说说unix。下面是unix发展史是我在百度百科了解的 Unix发展史 UNIX系统是一个分时系统。最早的UNIX系统于1970年问世。此前,只有…...
【Android知识笔记】性能优化专题(五)
App瘦身优化 随着业务迭代,apk体积逐渐变大。项目中积累的无用资源,未压缩的图片资源等,都为apk带来了不必要的体积增加。而APK 的大小会影响应用加载速度、使用的内存量以及消耗的电量。 瘦身优势: 最主要是转换率:下载转换率头部 App 都有 Lite 版渠道合作商要求了解 …...
Java基础之泛型
Java基础之泛型 一、泛型应用范围二、使用泛型方法三、泛型类 一、泛型应用范围 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。 使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调…...

WPF实战项目十五(客户端):RestSharp的使用
1、在WPF项目中添加Nuget包,搜索RestSharp安装 2、新建Service文件夹,新建基础通用请求类BaseRequest.cs public class BaseRequest{public Method Method { get; set; }public string Route { get; set; }public string ContenType { get; set; } &quo…...

C语言基础篇5:指针(二)
接上篇:C语言基础篇5:指针(一) 4 指针作为函数参数 4.1 指针变量作为函数的参数 指针型变量可以作为函数的参数,使用指针作为函数的参数是将函数的参数声明为一个指针,前面提到当数组作为函数的实参时,值传递数组的地址…...

「Verilog学习笔记」非整数倍数据位宽转换8to12
专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 要实现8bit数据至12bit数据的位宽转换,必须要用寄存器将先到达的数据进行缓存。8bit数据至12bit数据,相当于1.5个输入数据拼接成一个输出数据&#…...

Qt_一个由单例引发的崩溃
Qt_一个由单例引发的崩溃 文章目录 Qt_一个由单例引发的崩溃摘要关于 Q_GLOBAL_STATIC代码测试布局管理器源码分析Demo 验证关于布局管理器析构Qt 类声明周期探索更新代码获取父类分析Qt 单例宏源码 关键字: Qt、 Q_GLOBAL_STATIC、 单例、 UI、 崩溃 摘要 今…...

P8A004-系统加固-磁盘访问权限
【预备知识】 访问权限,根据在各种预定义的组中用户的身份标识及其成员身份来限制访问某些信息项或某些控制的机制。访问控制通常由系统管理员用来控制用户访问网络资源(如服务器、目录和文件)的访问,并且通常通过向用户和组授予…...

数智赋能 锦江汽车携手苏州金龙打造高质量盛会服务
作为一家老牌客运公司,成立于1956年的上海锦江汽车服务有限公司(以下简称锦江汽车),拥有1200多辆大巴和5000多辆轿车,是上海乃至长三角地区规模最大的专业旅游客运公司。面对客运市场的持续萎缩,锦江汽车坚…...

kolla-ansible 部署OpenStack云计算平台
目录 一、环境 二、安装及部署 三、测试 一、环境 官方文档:https://docs.openstack.org/kolla-ansible/yoga/user/quickstart.html rhel8.6 网络设置: 修改网卡名称 网络IP: 主机名: 网络时间协议 配置软件仓库 vim docke…...
wireshark 抓包提示
[TCP Previous segment not captured] 在TCP的传输阶段,同一台主机发出的数据段应该是连续的,即后一个包的Seq等于前一个包的SeqLen(三次握手和四次挥手是个例外)。如果wireshark发现后一个包的Seq号大于前一个包的SeqLen…...

Redis未授权访问-CNVD-2019-21763复现
Redis未授权访问-CNVD-2019-21763复现 利用项目: https://github.com/vulhub/redis-rogue-getshell 解压后先进入到 RedisModulesSDK目录里面的exp目录下,make编译一下才会产生exp.so文件,后面再利用这个exp.so文件进行远程代码执行 需要p…...
汇编:常用的输入与输出
1.字符输出 使用int 21h中断的02h号功能可以在屏幕输出一个字符,dl中存放要输出字符的ascii码。 如下代码将在屏幕输出一个字符“a”: mov ah,02hmov dl,aint 21h 2.字符输入 使用int 21h中断的01h号功能可以接受一个字符,al存放输…...

MYSQL基础之【正则表达式,事务处理】
文章目录 前言MySQL 正则表达式MySQL 事务事务控制语句事务处理方法PHP中使用事务实例 后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:Mysql 🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不…...

Mysql并发时常见的死锁及解决方法
使用数据库时,有时会出现死锁。对于实际应用来说,就是出现系统卡顿。 死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。就是所谓的锁资源请求产生了回路现象,即死循环,此时称系统处于…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...