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

Android类似微信聊天页面教程(Kotlin)四——数据本地化

 

前提条件

安装并配置好Android Studio

Android Studio Electric Eel | 2022.1.1 Patch 2
Build #AI-221.6008.13.2211.9619390, built on February 17, 2023
Runtime version: 11.0.15+0-b2043.56-9505619 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 6
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false
    ide.balloon.shadow.size=0
 
Non-Bundled Plugins:
    com.intuit.intellij.makefile (1.0.15)
    com.github.setial (4.0.2)
    com.alayouni.ansiHighlight (1.2.4)
    GsonOrXmlFormat (2.0)
    GLSL (1.19)
    com.mistamek.drawablepreview.drawable-preview (1.1.5)
    com.layernet.plugin.adbwifi (1.0.5)
    com.likfe.ideaplugin.eventbus3 (2020.0.2)

gradle-wrapper.properties

#Tue Apr 25 13:34:44 CST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
build.gradle(:Project)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {id 'com.android.application' version '7.3.1' apply falseid 'com.android.library' version '7.3.1' apply falseid 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}

setting.gradle

pluginManagement {repositories {google()mavenCentral()gradlePluginPortal()maven { url 'https://jitpack.io' }}
}
dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()gradlePluginPortal()maven { url 'https://jitpack.io' }}
}
rootProject.name = "logindemo"
include ':app'

build.gralde(:app)

plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'id 'kotlin-android'id 'kotlin-kapt'
}android {namespace 'com.example.fechat'compileSdk 33defaultConfig {applicationId "com.example.fechat"minSdk 26targetSdk 33versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_11targetCompatibility JavaVersion.VERSION_11}kotlinOptions {jvmTarget = '1.8'}
}dependencies {implementation 'androidx.core:core-ktx:1.7.0'implementation 'androidx.appcompat:appcompat:1.6.1'implementation 'com.google.android.material:material:1.8.0'implementation 'androidx.constraintlayout:constraintlayout:2.1.4'// 沉浸式状态栏 https://github.com/gyf-dev/ImmersionBarimplementation 'com.gyf.immersionbar:immersionbar:3.0.0'implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0' // fragment快速实现(可选)implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0' // kotlin扩展(可选)implementation 'com.google.code.gson:gson:2.8.9'implementation "androidx.room:room-runtime:2.4.2"implementation "androidx.room:room-ktx:2.4.2"kapt "androidx.room:room-compiler:2.4.2"implementation 'org.apache.commons:commons-csv:1.5'implementation 'com.permissionx.guolindev:permissionx:1.4.0'implementation 'com.blankj:utilcodex:1.30.0' // 无implementation 'com.github.bumptech.glide:glide:4.12.0'kapt 'com.github.bumptech.glide:compiler:4.12.0'
}

对Kotlin语言有基本了解

内容在前一篇博客中写了基础配置,如果本篇内容看不懂,可以先去上一篇。

数据本地化方案

采用room数据库保存首页用户聊天列表,为此引入room库

implementation "androidx.room:room-runtime:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"

采用csv文件来按行保存与用户聊天内容,这里csv不具有任何数据保护性,所以如果想要实现本地化并且数据加密,可以对保存在csv文件中的数据进行加密处理,读取时只需要解密即可还原,为此引入了kotlin的CSV读写库

implementation 'org.apache.commons:commons-csv:1.5'

其他优秀的开源库在这里也一起引入了,在这里感谢各位开源库作者

权限申请库

implementation 'com.permissionx.guolindev:permissionx:1.4.0'

通用工具类

implementation 'com.blankj:utilcodex:1.30.0' // 无

加载图片的glide库

implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'

本地化实现过程中新增的代码过多,所以不便这里一一贴出来,感兴趣的同学请移步开源库

FeChat: 模仿微信

首页聊天页面中的数据刷新

package com.example.fechat.fragmentimport android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.fechat.R
import com.example.fechat.activity.MessageActivity
import com.example.fechat.base.BaseAdapter
import com.example.fechat.room.user.UserDBUtils
import com.example.fechat.room.user.UserEntity
import java.util.*class ChatFragment : Fragment() {private var baseAdapter: BaseAdapter? = nullprivate lateinit var recyclerView: RecyclerViewprivate var data: List<UserEntity>? = nulloverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {val view = inflater.inflate(R.layout.fragment_chat, container, false)recyclerView = view.findViewById(R.id.recyclerView)recyclerView.layoutManager = LinearLayoutManager(context)data =ArrayList(UserDBUtils.getAll(context)).filter { it.last_message.isNotEmpty() }data?.let {Collections.sort(it) { o1, o2 ->(o2.duration - o1.duration).toInt()}}baseAdapter = BaseAdapter(data!!)recyclerView.adapter = baseAdapterbaseAdapter?.setOnItemClickListener(object : BaseAdapter.OnItemClickListener {override fun onItemClick(view: View, position: Int) {val intent = Intent(context, MessageActivity::class.java)intent.putExtra("UserInfo", data!![position].toString())startActivity(intent)}})return view}fun resume() {data =ArrayList(UserDBUtils.getAll(context)).filter { it.last_message.isNotEmpty() }data?.let {Collections.sort(it) { o1, o2 ->(o2.duration - o1.duration).toInt()}}baseAdapter?.setNewData(data!!)}
}

其中UserDBUtils是数据库接口,读取保存的聊天记录(包含用户名和最新的聊天记录)

而Collections.sort是对读出来的聊天记录(多用户)按照最新聊天记录的时间进行的排序

聊天页面数据本地化

package com.example.fechat.activityimport android.annotation.SuppressLint
import android.os.Bundle
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.blankj.utilcode.util.FileUtils
import com.example.fechat.R
import com.example.fechat.adapter.ChatAdapter
import com.example.fechat.bean.MessageBean
import com.example.fechat.room.user.UserDBUtils
import com.example.fechat.room.user.UserEntity
import com.example.fechat.utils.CSVUtils
import com.google.gson.Gson
import com.gyf.immersionbar.ImmersionBarclass MessageActivity : AppCompatActivity() {private val beans = ArrayList<MessageBean>()private var adapter: ChatAdapter? = nullprivate lateinit var itemView: RecyclerViewprivate lateinit var userEntity: UserEntityprivate var messagePath = ""private val userName = "Admin"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)ImmersionBar.with(this).statusBarDarkFont(true).statusBarColor(R.color.title).navigationBarColor(R.color.white).navigationBarDarkIcon(true).init()setContentView(R.layout.activity_message)val backTv = findViewById<TextView>(R.id.backTv)val inputText: EditText = findViewById(R.id.inputText)val sendText: TextView = findViewById(R.id.sendText)val userName: TextView = findViewById(R.id.userName)backTv.setOnClickListener {finish()}sendText.setOnClickListener {sendText(inputText.text.toString())inputText.setText("")}getBundle()initItemRecyclerView()userName.text = userEntity.userName}private fun getBundle() {val userInfo = intent.getStringExtra("UserInfo")userEntity = Gson().fromJson(userInfo, UserEntity::class.java)messagePath = CSVUtils.getPath(this, userEntity.userId)FileUtils.createOrExistsFile(messagePath)}override fun onResume() {super.onResume()beans.addAll(CSVUtils.readFromCSV(messagePath))}private fun initItemRecyclerView() {itemView = findViewById(R.id.itemView)val layoutManager = LinearLayoutManager(this)layoutManager.orientation = RecyclerView.VERTICALitemView.layoutManager = layoutManageradapter = ChatAdapter(beans, userEntity)itemView.adapter = adapter}@SuppressLint("NotifyDataSetChanged")private fun sendText(message: String) {insertMessage(message)adapter?.notifyDataSetChanged()}private fun insertMessage(message: String) {val messageBean = MessageBean(message, userName, false, System.currentTimeMillis(), true)beans.add(messageBean)CSVUtils.writeToCSV(messageBean, messagePath)val messageBeanResp =MessageBean(message, userEntity.userName, true, System.currentTimeMillis(), true)beans.add(messageBeanResp)CSVUtils.writeToCSV(messageBeanResp, messagePath)userEntity.duration = System.currentTimeMillis()userEntity.last_message = messageUserDBUtils.insertUser(this, userEntity)}
}

数据本地化包括对首页聊天记录列表的更新和单用户聊天记录保存到CSV文件中。

CSV工具类

package com.example.fechat.utilsimport android.content.Context
import com.example.fechat.bean.MessageBean
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVParser
import org.apache.commons.csv.CSVPrinter
import java.io.*object CSVUtils {fun getPath(context: Context, userId: String): String {return "${context.getExternalFilesDir(null)}/message/${userId}.csv"}fun writeToCSV(bean: MessageBean, path: String) {val bufferWrite = BufferedWriter(OutputStreamWriter(FileOutputStream(path, true)))val csvPrinter = CSVPrinter(bufferWrite, CSVFormat.DEFAULT)val data = listOf(bean.message, bean.userName, bean.isResponse, bean.time, bean.isSuccess)csvPrinter.printRecord(data)csvPrinter.flush()csvPrinter.close()}fun readFromCSV(path: String): ArrayList<MessageBean> {val bufferedReader = BufferedReader(FileReader(File(path)))val csvParser = CSVParser(bufferedReader, CSVFormat.DEFAULT)val messageBeans = ArrayList<MessageBean>()csvParser.forEach { parse ->val messageBean = MessageBean(parse[0],parse[1],parse[2].toBoolean(),parse[3].toLong(),parse[4].toBoolean())messageBeans.add(messageBean)}return messageBeans}
}

新增的权限请求

package com.example.fechat.activityimport android.Manifest
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.widget.BaseAdapter
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.example.fechat.R
import com.example.fechat.fragment.ChatFragment
import com.example.fechat.fragment.ContactsFragment
import com.example.fechat.fragment.DiscoverFragment
import com.google.android.material.tabs.TabLayout
import com.gyf.immersionbar.ImmersionBar
import com.permissionx.guolindev.PermissionXclass MainActivity : AppCompatActivity() {private lateinit var viewPager: ViewPagerprivate lateinit var tabLayout: TabLayoutprivate lateinit var titleTv: TextViewprivate val fragments = ArrayList<Fragment>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)ImmersionBar.with(this).statusBarDarkFont(true).statusBarColor(R.color.title).navigationBarColor(R.color.white).navigationBarDarkIcon(true).init()setContentView(R.layout.activity_main)initPermission()}private fun initPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {if (!Environment.isExternalStorageManager()) {val intent = Intent()intent.action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSIONval uri: Uri = Uri.fromParts("package", this.packageName, null)intent.data = uristartActivityForResult(intent, 0x99)} else {initView()}} else {PermissionX.init(this).permissions(Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE).request { allGranted, _, _ ->if (allGranted) {initView()}}}}private fun initView() {fragments.addAll(listOf(ChatFragment(),ContactsFragment(),DiscoverFragment()))titleTv = findViewById(R.id.titleTv)viewPager = findViewById(R.id.viewPager)tabLayout = findViewById(R.id.tabLayout)viewPager.adapter = ViewPagerAdapter(supportFragmentManager, fragments)tabLayout.setupWithViewPager(viewPager)tabLayout.getTabAt(0)?.text = "聊天"tabLayout.getTabAt(1)?.text = "联系人"tabLayout.getTabAt(2)?.text = "发现"tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {override fun onTabSelected(tab: TabLayout.Tab?) {titleTv.text = tab?.textif (tab?.position == 0) {(fragments[0] as ChatFragment).resume()}}override fun onTabUnselected(tab: TabLayout.Tab?) {}override fun onTabReselected(tab: TabLayout.Tab?) {}})}class ViewPagerAdapter(fragmentManager: androidx.fragment.app.FragmentManager,private val fragments: List<Fragment>) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {override fun getItem(position: Int): Fragment {return fragments[position]}override fun getCount(): Int {return fragments.size}}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 0x99) {initPermission()}}
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@drawable/icon_logo"android:roundIcon="@drawable/icon_logo"android:label="@string/app_name"android:supportsRtl="true"android:name=".base.BaseApplication"android:theme="@style/Theme.FeChat.Font"tools:targetApi="31"><activityandroid:name=".activity.MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".activity.MessageActivity" /></application></manifest>

新增字体

字体是阿里开源的,仅供大家学习使用,商用可能产生版权纠纷

themes.xml

<style name="Theme.FeChat.Font" parent="Theme.FeChat"><item name="fontFamily">@font/alimama_dongfangdakai_regular</item>
</style>

字体引用

<applicationandroid:allowBackup="true"android:icon="@drawable/icon_logo"android:roundIcon="@drawable/icon_logo"android:label="@string/app_name"android:supportsRtl="true"android:name=".base.BaseApplication"android:theme="@style/Theme.FeChat.Font"tools:targetApi="31"><activityandroid:name=".activity.MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".activity.MessageActivity" />
</application>

相关文章:

Android类似微信聊天页面教程(Kotlin)四——数据本地化

前提条件 安装并配置好Android Studio Android Studio Electric Eel | 2022.1.1 Patch 2 Build #AI-221.6008.13.2211.9619390, built on February 17, 2023 Runtime version: 11.0.150-b2043.56-9505619 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Windows 11 …...

C/C++基础知识

专栏&#xff1a;C/C 个人主页&#xff1a; C/C基础知识 前言C关键字(C98)命名空间命名空间的定义正常的命名空间的定义如何使用命名空间 命名空间可以嵌套同一个工程中允许存在多个相同名称的命名空间&#xff0c;编译器最后会合成同一个命名空间中(一个工程中的.h文件和test.…...

Java 入门 - 语法基础

hello world public class Hello {public static void main(String[] args) {System.out.println("hello world");} } 复制代码 public: 是关键字&#xff1b;表示公开的class: 是关键字&#xff1b;用来定义类Hello: 是类名&#xff1b;大小写敏感&#xff1b;命名…...

Java线程池及拒绝策略详解

前文提到线程的使用以及线程间通信方式&#xff0c;通常情况下我们通过new Thread或者new Runnable创建线程&#xff0c;这种情况下&#xff0c;需要开发者手动管理线程的创建和回收&#xff0c;线程对象没有复用&#xff0c;大量的线程对象创建与销毁会引起频繁GC&#xff0c;…...

GitLABJenkins

GitLAB & Jenkins 目录 实践&#xff1a;基于Jenkins提交流水线(测试成功)-2023.4.25 目的&#xff1a;掌握通过触发器将GitLab和Jenkins集成&#xff0c;实现提交流水线。 1、触发Jenkins构建 安装Generic Webhook Trigger插件 重启后&#xff0c;进入一个Pipeline项目设…...

互联网摸鱼日报(2023-04-26)

互联网摸鱼日报&#xff08;2023-04-26&#xff09; InfoQ 热门话题 神州数码&#xff1a;抢抓云原生发展机遇&#xff0c;共建共治共享 OpenNJet 应用引擎开源生态 《产业数字人才研究与发展报告&#xff08;2023&#xff09;》 如何写出CPU友好的代码&#xff0c;百倍提升…...

石化企业数字化防爆融合通信解决方案

项目背景 石化工业是我国国民经济和社会发展的基础性、战略性产业&#xff0c;其发展和壮大受到了党和国家的高度重视。随着石化企业厂区规模的不断扩大以及技术的快速发展&#xff0c;现有石化企业专网通信系统建设相对滞后&#xff0c;缺乏结合人员管理、安全生产、安全通信…...

NTT学习笔记(快速数论变换)

一些概念 欧拉函数 ϕ ( n ) \phi(n) ϕ(n) 欧拉函数简介 阶 若 g g g和 n n n互质&#xff0c;则令 g x % n 1 g^x\%n1 gx%n1的最小正整数 x x x称为 g g g模 n n n的阶。 原根 对于互质的两个正整数 g g g和 n n n&#xff0c;如果 g g g模 n n n的阶为 ϕ ( n ) \phi…...

Android类似微信首页的页面开发教程(Kotlin)二

前提条件 安装并配置好Android Studio Android Studio Electric Eel | 2022.1.1 Patch 2 Build #AI-221.6008.13.2211.9619390, built on February 17, 2023 Runtime version: 11.0.150-b2043.56-9505619 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Windows 11 …...

PAt A1015 Reversible Primes

1015 Reversible Primes 分数 20 作者 CHEN, Yue 单位 浙江大学 A reversible prime in any number system is a prime whose "reverse" in that number system is also a prime. For example in the decimal system 73 is a reversible prime because its rever…...

解决Lemuroid识别不到蓝牙键盘的问题

Android系统基于libretro的全能游戏模拟器&#xff0c;目前有RetroArch&#xff0c;Kodi&#xff0c;Lemuroid。 而且这三个都是开源免费的APP。 Lemuroid相对前面两个功能比较简陋。也不能自己下载核心。但代码也是最少的。 在使用Lemuroid的时候&#xff0c;发现它不能检测…...

SpringBoot 使用 Sa-Token 完成权限认证

一、设计思路 所谓权限认证&#xff0c;核心逻辑就是判断一个账号是否拥有指定权限&#xff1a; 有&#xff0c;就让你通过。没有&#xff1f;那么禁止访问&#xff01; 深入到底层数据中&#xff0c;就是每个账号都会拥有一个权限码集合&#xff0c;框架来校验这个集合中是…...

Spring核心与设计思想、创建与使用

文章目录 一、Spring是什么二、为什么要学习框架三、IoC和DI&#xff08;一&#xff09;IoC1. 认识IoC2. Spring的核心功能 &#xff08;二&#xff09;DI 四、Spring项目的创建&#xff08;一&#xff09;使用 Maven 方式创建一个 Spring 项目 五、Spring项目的使用&#xff0…...

mysql 备份 还原

1:备份 执行命令方案1: /usr/local/mysql/bin/mysqldump -uX -pX -h 127.0.0.1 --set-gtid-purgedOFF --skip-extended-insert --add-drop-table --add-locks --create-options --disable-keys --lock-tables --quick --set-charset -e --max_allowed_packet16777216 --net_b…...

每日学术速递4.26

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.AutoNeRF: Training Implicit Scene Representations with Autonomous Agents 标题&#xff1a;AutoNeRF&#xff1a;使用自主代理训练隐式场景表示 作者&#xff1a;Pierre Marz…...

RabbitMQ使用StringRedisTemplate-防止重复消费

造成重复消费的原因&#xff1a; MQ向消费者推送message&#xff0c;消费者向MQ返回ack&#xff0c;告知所推送的消息消费成功。但是由于网络波动等原因&#xff0c;可能造成消费者向MQ返回的ack丢失。MQ长时间&#xff08;一分钟&#xff09;收不到ack&#xff0c;于是会向消…...

临沂大学张继群寄语

目录 寄语 1、不能有不良睹好 2、坚毅的个性和勤奋的品质 3、会存钱...

线程学习笔记

1:Thread 线程的生命周期控制 2:Runnable 可执行的任务和程序 3:Callable 执行程序后返回结果 4:Future 收集程序返回结果 5:Executor 线程池 6:ForkJoin 默认线程池 每个线程有工作队列 工作窃取 7:RunnableFuture FutureTask 实现 Runnable 和 Future 执…...

代码随想录算法训练营第四十二天|01背包问题,你该了解这些!、01背包问题,你该了解这些! 滚动数组 、416. 分割等和子集

文章目录 01背包问题&#xff0c;你该了解这些&#xff01;01背包问题&#xff0c;你该了解这些&#xff01; 滚动数组416. 分割等和子集 01背包问题&#xff0c;你该了解这些&#xff01; 题目链接&#xff1a;代码随想录 二维数组解决0-1背包问题 解题思路&#xff1a; 1.dp…...

结构体指针、数组指针和结构体数组指针

结构体指针 首先让我们定义结构体&#xff1a; struct stu { char name[20]; long number; float score[4]; }; 再定义指向结构体类型变量的指针变量&#xff1a; struct stu *student; /*定义结构体类型指针*/ student malloc(sizeof(struct stu)); /*为指针变量分…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...