android contentProvider 踩坑日记

写此笔记原因

学习《第一行代码》到第8章节实现provider时踩了一些坑,因此记录下来给后来人和自己一个提示,仅此而已。

包含内容

  1. Sqlite数据库CURD内容
  2. provider界面
  3. provider项目中书籍管理
  4. provider实现逻辑
  5. 用adb shell确认provider
  6. contentResolver接收项目
  7. contentProvider权限
  8. 生成Uri方法

Sqlite数据库CURD内容

  1. Android studio 创建一个Empty的空项目
  2. 不需要等项目同步完成,直接取消同步。因为从官网下载Gradle和java库太慢。
  3. 修改Gradle和java库为国内镜像后,再点击同步。应当就能快速的实现依赖下载
    # settings.gradle.kts pluginManagement {repositories {maven { setUrl("https://maven.aliyun.com/repository/central") }maven { setUrl("https://maven.aliyun.com/repository/jcenter") }maven { setUrl("https://maven.aliyun.com/repository/google") }maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }maven { setUrl("https://maven.aliyun.com/repository/public") }maven { setUrl("https://jitpack.io") }google {content {includeGroupByRegex("com\\.android.*")includeGroupByRegex("com\\.google.*")includeGroupByRegex("androidx.*")}}mavenCentral()gradlePluginPortal()}}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {maven { setUrl("https://maven.aliyun.com/repository/central") }maven { setUrl("https://maven.aliyun.com/repository/jcenter") }maven { setUrl("https://maven.aliyun.com/repository/google") }maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }maven { setUrl("https://maven.aliyun.com/repository/public") }maven { setUrl("https://jitpack.io") }google()mavenCentral()}}rootProject.name = "BookProviderTest"include(":app")
	gradle/wrapper/gradle-wrapper.propertiesdistributionBase=GRADLE_USER_HOMEdistributionPath=wrapper/dists# 此处gradle版本可以根据android相应的java版本自行修改,移植android项目也可以修改此处版本distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-all.zipzipStoreBase=GRADLE_USER_HOMEzipStorePath=wrapper/dists
  1. 创建一个类BookDatabaseHelper
class BookDatabaseHelper(val context: Context, val name: String, version: Int) :SQLiteOpenHelper(context, name, null, version) {private val createBookCMD = "create table Book (" +" id integer primary key autoincrement, " +"author text not null," +"price real," +"pages integer," +"name text not null)"private val createCategoryCMD = "create table category (" +"id integer primary key autoincrement," +"category_name text not null," +"category_code integer)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createBookCMD)db?.execSQL(createCategoryCMD)
//        Toast.makeText(context, "创建 $name 成功", Toast.LENGTH_SHORT).show()}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {db?.execSQL("drop table if exists Book")db?.execSQL("drop table if exists category")onCreate(db)}
}
  1. app/src/main/java/com.example.databasetest中创建一个空的MainActivity,同时选中"Generate a Layout File"和"Launcher Activity",就同时创建了MainActivity和res/layout/activity_main.xml
  2. 引入viewBinding
    # build.gradle.kts文件android的大括号中加入,再次同步buildFeatures {viewBinding = true}

provider界面

# 切换到图形界面,鼠标右键点击main,选择"Convert view",将布局换成LinearLayout
# 下面内容就是书籍管理界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="书名"android:id="@+id/BookNameLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="书名"android:id="@+id/bookName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="作者"android:id="@+id/BookAuthorLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="作者"android:id="@+id/bookAuthor" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="页数"android:id="@+id/BookPagesLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:inputType="number"android:hint="页数"android:id="@+id/bookPages" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="售价"android:id="@+id/BookPriceLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="售价"android:inputType="number"android:id="@+id/bookPrice" /></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookSave"android:text="保存" /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookUpdate"android:text="更新" /></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookDelete"android:text="删除" /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookSearch"android:text="查询" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="20dp" ><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/createDatabase"android:layout_gravity="center"android:text="创建数据库" /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:id="@+id/transictionTest"android:layout_gravity="center"android:text="事务测试" /></LinearLayout>
</LinearLayout>

provider项目中书籍管理

# MainActivity
class MainActivity : AppCompatActivity() {private lateinit var binding : ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)val dbHelper = BookDatabaseHelper(this, "Books.db", 2)/* 创建数据库 */binding.createDatabase.setOnClickListener {dbHelper.writableDatabase}/* 添加新书 */binding.bookSave.setOnClickListener {val db = dbHelper.writableDatabaseval values = ContentValues().apply {put("name", binding.bookName.text.toString())put("author", binding.bookAuthor.text.toString())put("pages", binding.bookPages.text.toString().toInt())put("price", binding.bookPrice.text.toString().toFloat())}db.insert("Book", null, values);binding.bookName.setText("")binding.bookAuthor.setText("")binding.bookPages.setText("")binding.bookPrice.setText("")}/* 更新书籍信息 */binding.bookUpdate.setOnClickListener {var db = dbHelper.writableDatabaseval values = ContentValues().apply{put("name", binding.bookName.text.toString())put("author", binding.bookAuthor.text.toString())put("pages", binding.bookPages.text.toString().toInt())put("price", binding.bookPrice.text.toString().toFloat())}db.update("Book", values, "name = ?", arrayOf("Book1"))binding.bookName.setText("")binding.bookAuthor.setText("")binding.bookPages.setText("")binding.bookPrice.setText("")}/* 按书名删除书籍信息 */binding.bookDelete.setOnClickListener {var db = dbHelper.writableDatabasedb.delete("Book", "name = ?", arrayOf(binding.bookName.text.toString()))binding.bookName.setText("")binding.bookAuthor.setText("")binding.bookPages.setText("")binding.bookPrice.setText("")}binding.bookSearch.setOnClickListener {val db = dbHelper.writableDatabaseval queryBookName = binding.bookName.text.toString()
//            val cursor = db.rawQuery("select name,author,pages,price from Book where name = ?"  , arrayOf(queryBookName))val cursor = db.query("Book",arrayOf("name","author","pages","price"), "name = ?", arrayOf(queryBookName), null, null, null)if(cursor.count > 0){cursor.moveToFirst()binding.bookName.setText(cursor.getString(cursor.getColumnIndex("name") as Int))binding.bookAuthor.setText(cursor.getString(cursor.getColumnIndex("author") as Int))binding.bookPages.setText(cursor.getString(cursor.getColumnIndex("pages") as Int))binding.bookPrice.setText(cursor.getString(cursor.getColumnIndex("price") as Int))}}binding.transictionTest.setOnClickListener {val db = dbHelper.writableDatabasedb.beginTransaction()try{db.delete("Book", null, null)if(true){
//                    throw NullPointerException()}val values = ContentValues().apply {put("name", "Game Of Thrones")put("author", "George Martin")put("pages", 720)put("price", 20.85)}db.insert("Book", null, values)db.setTransactionSuccessful()   // 事务完成提交}catch (e: Exception){e.printStackTrace()}finally {db.endTransaction()}}}
}

至此就可以向Books.db中加入书籍的内容了,保存是添加新书,查询可以查出已经加入的书籍。《第一行代码》第7章还推荐了一个"Database Navigator"可以查看导出的sqlite数据库,可以试试。

provider实现逻辑

# 新建一个BookDatabaseProvider,最好使用File->New->Other->Content Provider,会自动在`AndroidManifest.xml`文件中自动加入新建的provider
class BookDatabaseProvider : ContentProvider() {/* 自定义uri编号 */private val bookDir = 0private val bookItem = 1private val categoryDir = 2private val categoryItem = 3private val authority = "com.example.databasetest.provider"private var dbHelper: BookDatabaseHelper? = nullprivate val uirMatcher by lazy {val matcher = UriMatcher(UriMatcher.NO_MATCH)matcher.addURI(authority, "book", bookDir)matcher.addURI(authority, "book/#", bookItem)matcher.addURI(authority,"category", categoryDir)matcher.addURI(authority, "category/#", categoryItem)matcher}override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = dbHelper?.let {val db = it.writableDatabaseval deleteRows = when(uirMatcher.match(uri)) {bookDir -> db.delete("Book",  selection, selectionArgs)bookItem -> {/* uri 最后一个字段 */val bookId = uri.pathSegments[1]db.delete("Book", "id = ?", arrayOf(bookId))}categoryDir -> db.delete("Category", selection, selectionArgs)categoryItem -> {val categoryId = uri.pathSegments[1]db.delete("Category", "id = ?",arrayOf(categoryId))}else -> null}deleteRows} ?: 0override fun getType(uri: Uri) = when(uirMatcher.match(uri)) {bookDir -> "vnd.android.cursor.dir/vnd.$authority.book"bookItem -> "vnd.android.cursor.item/vnd.$authority.book"categoryDir -> "vnd.android.cursor.dir/vnd.$authority.category"categoryItem -> "vnd.android.cursor.item/vnd.$authority.category"else -> null}override fun insert(uri: Uri, values: ContentValues?) = dbHelper?.let {val db = it.writableDatabaseval uriReturn = when(uirMatcher.match(uri)) {bookDir, bookItem -> {val newBookId = db.insert("Book", null, values)Uri.parse("content://$authority/book/$newBookId")}categoryDir, categoryItem -> {val newCategoryId = db.insert("Category", null, values)Uri.parse("content://$authority/category/$newCategoryId")}else -> null}uriReturn}override fun onCreate() = context?.let {dbHelper = BookDatabaseHelper(it, "Books.db", 2)true} ?: falseoverride fun query(uri: Uri, projection: Array<String>?, selection: String?,selectionArgs: Array<String>?, sortOrder: String?) = dbHelper?.let{val db = it.readableDatabaseval cursor = when(uirMatcher.match(uri)){bookDir -> db.query("Book", projection, selection, selectionArgs, null, null, sortOrder)bookItem -> {val bookId = uri.pathSegments[1]db.query("Book", projection, "id = ?", arrayOf(bookId), null, null, sortOrder)}categoryDir -> db.query("Category", projection, selection, selectionArgs, null, null, sortOrder)categoryItem -> {val categoryId = uri.pathSegments[1]db.query("Category", projection, "id = ?", arrayOf(categoryId), null, null, sortOrder)}else -> null}cursor}override fun update(uri: Uri, values: ContentValues?, selection: String?,selectionArgs: Array<String>?) = dbHelper?.let {val db = it.writableDatabaseval updateRows = when(uirMatcher.match(uri)) {bookDir -> db.update("Book", values, selection, selectionArgs)bookItem -> {val bookId = uri.pathSegments[1]db.update("Book", values, "id = ?", arrayOf(bookId))}categoryDir -> db.update("Category", values, selection, selectionArgs)categoryItem -> {val categoryId = uri.pathSegments[1]db.update("Category", values, "id = ?", arrayOf(categoryId))}else -> null}updateRows} ?: 0
}

完成后就可以连接手机或模拟器点击运行安装了,加入些书籍信息

用adb shell确认provider

$ adb shell content query --uri content://com.example.databasetest.provider/book
Row: 0 id=1, author=Author1, price=1.0, pages=1, name=Book1
Row: 1 id=2, author=Author2, price=2.0, pages=2, name=Book2
# 可以看到输出了2本刚加入的书籍信息,这里还没有加入权限说明adb shell可以直接读取书籍信息
adb shell content query --uri content://com.example.databasetest.provider/book --where "name=\'Book1\'"
# 这里如果要找特定行内容需要以\' xxx \'这样的形式,什么name:s:xxx "name='xxx'" 都会报错

contentResolver接收项目界面

同样的方法再建立一个访问provider的项目"BookProviderTest",建立一个新的Activity,和activity_main.xml布局。

# 布局和上面的书籍管理类似
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="书名"android:id="@+id/BookNameLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="书名"android:id="@+id/bookName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="作者"android:id="@+id/BookAuthorLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="作者"android:id="@+id/bookAuthor" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="页数"android:id="@+id/BookPagesLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:inputType="number"android:hint="页数"android:id="@+id/bookPages" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="售价"android:id="@+id/BookPriceLabel"></TextView><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:hint="售价"android:inputType="number"android:id="@+id/bookPrice" /></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookSave"android:text="保存" /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookUpdate"android:text="更新" /></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookDelete"android:text="删除" /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="20dp"android:layout_weight="1"android:layout_gravity="center"android:id="@+id/bookSearch"android:text="查询" /></LinearLayout>
</LinearLayout>
class MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBindingvar bookId: String? = nullval providerUri = "content://com.example.databasetest.provider"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)supportActionBar?.hide()binding.bookSave.setOnClickListener {var uri = Uri.parse("$providerUri/book")val values = contentValuesOf("name" to binding.bookName.text.toString(),"author" to binding.bookAuthor.text.toString(),"pages" to binding.bookPages.text.toString().toInt(),"price" to binding.bookPrice.text.toString().toDouble())val newUri = contentResolver.insert(uri, values)bookId = newUri?.pathSegments?.get(1)}binding.bookSearch.setOnClickListener {val uri = Uri.parse("content://com.example.databasetest.provider/book")val bookName = binding.bookName.text.toString()val cursor = contentResolver.query(uri, arrayOf("name","author","pages","price"), "name = ?", arrayOf(bookName), null)cursor?.apply{while(moveToNext()){val nameId = getColumnIndex("name")val name = getString(nameId)val authorId = getColumnIndex("author")val author = getString(authorId)val pagesId = getColumnIndex("pages")val pages = getInt(pagesId)val priceId = getColumnIndex("price")val price = getDouble(priceId)binding.bookName.setText(name)binding.bookAuthor.setText(author)binding.bookPages.setText(pages.toString())binding.bookPrice.setText(price.toString())}close()}}binding.bookUpdate.setOnClickListener {val uri = Uri.parse("$providerUri/book")val values = contentValuesOf("name" to binding.bookName.text.toString(),"author" to binding.bookAuthor.text.toString(),"pages" to binding.bookPages.text.toString().toInt(),"price" to binding.bookPrice.text.toString().toDouble())contentResolver.update(uri, values, "name = ?", arrayOf(binding.bookName.text.toString()))}binding.bookDelete.setOnClickListener {val uri = Uri.parse("$providerUri/book")contentResolver.delete(uri, "name = ?", arrayOf(binding.bookName.text.toString()))}}
}

此项目直接运行是不能获取到provider项目的书籍信息的,因为provider没有指定权限,此项目还没有权限读写provider内容。因此接下来就是要给provider项目和本项目添加权限说明

contentProvider权限

  1. 打开第一个项目的AndroidManifest.xml
# 加入权限声名<permission android:name="com.example.databasetest.READ_PERMISSION"android:protectionLevel="normal" /  ><permission android:name="com.example.databasetest.WRITE_PERMISSION"android:protectionLevel="normal" />
# provider信息改成如下内容<providerandroid:name=".BookDatabaseProvider"android:authorities="com.example.databasetest.provider"android:enabled="true"android:readPermission="com.example.databasetest.READ_PERMISSION"android:writePermission="com.example.databasetest.WRITE_PERMISSION"android:exported="true"></provider>
# 删除应用后重新安装,安装后就不能使用adb shell content获取内容了
  1. 修改第二个项目的AndroidManifest.xml
    <uses-permission android:name="com.example.databasetest.READ_PERMISSION" /><uses-permission android:name="com.example.databasetest.WRITE_PERMISSION" />

再次运行就可以在第二个项目中获取和编辑第一个项目的provider内容了

生成Uri方法

刚开始没有发现是权限问题,怎么都不能获取到内容,还以为是因为Uri不正确。因此发现Uri生成方式有几种,这里也记录一下。

val uri = Uri.parse("content://authority/path")
# 发现此方法生成的Uri,authority和path没有解析到相应字段中,但程序还是可以正常运行,获取到内容
val uri = Uri.Builder().apply{scheme("content")authority("com.example.authority")path("path")
}.build()
# 使用此方法,authority和path都能正确解析到相应字段中,后者应当是比较推荐的方法,就是有点啰嗦
# 系统自带的联系人等provider的uri也和后者生成的uri基本一样

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

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

相关文章

Eureka、LoadBalance和Nacos

Eureka、LoadBalance和Nacos 一.Eureka引入1.注册中心2.CAP理论3.常见的注册中心 二.Eureka介绍1.搭建Eureka Server 注册中心2.搭建服务注册3.服务发现 三.负载均衡LoadBalance1.问题引入2.服务端负载均衡3.客户端负载均衡4.Spring Cloud LoadBalancer1).快速上手2)负载均衡策…

【开关电源】关于GaN反激电源开关噪声

文章目录 0 前言1 设计信息1.1 设计需求1.2 原理图1.3 电源表现 2 原因分析3 横向对比TI UCG28826 &#xff08;GaN&#xff09;采购的普通QR反激变换器 4 总结 0 前言 笔者原计划设计一款省电的&#xff0c;效率尚可的&#xff0c;稳定的2路输出反激电源&#xff0c;用于系统…

DOCA介绍

本文分为两个部分&#xff1a; DOCA及BlueField介绍如何运行DOCA应用&#xff0c;这里以DNS_Filter为例子做大致介绍。 DOCA及BlueField介绍&#xff1a; 现代企业数据中心是软件定义的、完全可编程的基础设施&#xff0c;旨在服务于跨云、核心和边缘环境的高度分布式应用工作…

mybatis mapper.xml中使用枚举

重点&#xff1a;application.propertis配置类 #TypeEnumHandler 这个类的包名&#xff0c;不是全路径 mybatis.type-handlers-packagecom.fan.test.handler两个枚举类&#xff1a; public enum StatusEnum {DELETED(0),ACTIVE(1);private final int code;StatusEnum(int cod…

鸿蒙生态:鸿蒙生态校园行心得

&#xff08;个人观点&#xff0c;仅供参考&#xff09; 兄弟们&#xff0c;今天来浅浅聊一聊这次的设立在长沙的鸿蒙生态行活动。 老样子&#xff0c;我们先来了解一下这个活动&#xff1a; &#xff28;&#xff41;&#xff52;&#xff4d;&#xff4f;&#xff4e;&#x…

【速写】多LoRA并行衍生的一些思考

迁移学习上的一个老问题&#xff0c;怎么做多领域的迁移&#xff1f;以前的逻辑认为领域迁移属于是对参数做方向性的调整&#xff0c;如果两个领域方向相左&#xff0c;实际上不管怎么加权相加都是不合理的。 目前一些做法想着去观察LoRA权重矩阵中的稠密块与稀疏块&#xff0…

【Delphi 基础知识 44】接口interface的应用

目录 1. 前言2. 接口有哪些优势2.1. 实现多态性2.2 实现多重(解决单继承限制)2.3 解耦代码(依赖注入)2.4 便于测试(模拟接口)2.5 跨语言互操作性(COM支持)1. 前言 总结为一句话就是:接口只告诉你要做什么,而类会告诉你应该怎么做 下面是最简单的接口实现 typeIMyIn…

09.传输层协议 ——— TCP协议

文章目录 TCP协议 谈谈可靠性TCP协议格式 序号与确认序号窗口大小六个标志位 确认应答机制&#xff08;ACK&#xff09;超时重传机制连接管理机制 三次握手四次挥手 流量控制滑动窗口拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常情况TCP小结基于TCP的应用层协议 TCP协…

NLP高频面试题(五十一)——LSTM详解

长短期记忆网络(LSTM)相较于传统循环神经网络(RNN)的核心改进在于通过引入记忆单元(cell state)和门机制(gating mechanism)来有效缓解梯度消失与梯度爆炸问题,从而更好地捕捉长距离依赖关系 。在其网络结构中,信息通过输入门(input gate)、遗忘门(forget gate)和…

SpringCloud组件—Eureka

一.背景 1.问题提出 我们在一个父项目下写了两个子项目&#xff0c;需要两个子项目之间相互调用。我们可以发送HTTP请求来获取我们想要的资源&#xff0c;具体实现的方法有很多&#xff0c;可以用HttpURLConnection、HttpClient、Okhttp、 RestTemplate等。 举个例子&#x…

无需花钱购买域名服务器!使用 VuePress + Github 30分钟搭建属于自己的博客网站(保姆级教程)

前言 GitHub Pages 提供免费全球加速的服务器资源&#xff0c;VuePress 将 Markdown 变成艺术品级的网页&#xff0c;仅需 30 分钟&#xff0c;你便可以像提交代码一样发布文章&#xff0c;过程完全免费。 博客搭建好的效果如下&#xff1a;https://honorsong.github.io/exam…

提交到Gitee仓库

文章目录 注册配置公钥创建空白的码云仓库把本地项目上传到码云对应的空白仓库中 注册 注册并激活码云账号&#xff08; 注册页面地址&#xff1a;https://gitee.com/signup &#xff09; 可以在自己C盘/用户/用户名/.ssh 可以看到 有id_rsa.pub 以前在GitHub注册时搞过&…

如何在 Java 中从 PDF 文件中删除页面(教程)

由于 PDF 文件格式不是 Java 原生支持的&#xff0c;因此要从 PDF 中删除页面&#xff0c;你需要使用外部库。 本教程介绍如何使用 JPedal 来实现这一功能。 开始使用 • 将 JPedal 添加到你的类路径或模块路径中&#xff08;可从官网下载安装试用版 JAR 文件&#xff09; •…

机器学习第二篇 多变量线性回归

数据集&#xff1a;世界幸福指数数据集中的变量有幸福指数排名、国家/地区、幸福指数得分、人均国内生产总值、健康预期寿命、自由权、社会支持、慷慨程度、清廉指数。我们选择GDP per Capita和Freedom&#xff0c;来预测幸福指数得分。 文件一&#xff1a;linear&#xff0c;…

位运算,状态压缩dp(算法竞赛进阶指南学习笔记)

目录 移位运算一些位运算的操作最短 Hamilton 路径&#xff08;状态压缩dp模板&#xff0c;位运算&#xff09; 0x是十六进制常数的开头&#xff1b;本身是声明进制&#xff0c;后面是对应具体的数&#xff1b; 数组初始化最大值时用0x3f赋值&#xff1b; 移位运算 左移 把二…

Java高频面试之并发编程-05

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;线程有哪些调度方法&#xff1f; 在Java中&#xff0c;线程的调用方法主要包括以下几种方式&#xff0c;每种方式适用于…

进程的同步和互斥

进程同步&#xff08;synchronous&#xff09; ✅通俗理解&#xff1a; 就像在排队买饭&#xff0c;一个一个来&#xff0c;前面的人不走&#xff0c;后面的人就不能干事。 进程同步就是&#xff1a;多个进程之间需要协调&#xff0c;有先后顺序&#xff0c;一个进程要等另一…

PDF处理控件Aspose.PDF指南:使用 Python 将 EPUB 转换为 PDF

EPUB是一种流行的电子书格式&#xff0c;用于可重排内容&#xff0c;而PDF则广泛用于固定版式文档&#xff0c;非常适合共享和打印。如果您想使用 Python 将 EPUB 转换为 PDF&#xff0c;Aspose.PDF for Python 提供了一个简单可靠的解决方案。在本教程中&#xff0c;我们将向您…

day4-小白学习JAVA---开发软件_Scanner键盘录入_Random随机数_流程控制语句

开发软件_Scanner键盘录入_Random随机数_流程控制语句 一、开发软件idea&#xff08;MAC版&#xff09;1、软件安装-安装社区版2、中英文设置3、保存时格式化配置4、注释和代码对不齐5、idea快捷键 二、键盘录入--Scanner1、next和nextInt2、next和nextLine区别 三、Random随机…

MySQL基本查询与数据操作全面解析

目录 1. CRUD操作概述 2. Create操作详解 2.1 表的创建 2.2 单行数据插入 2.3 多行数据插入 2.4 插入冲突处理 3. Retrieve操作详解 3.1 基础查询 全列查询&#xff08;慎用&#xff09; 指定列查询 表达式查询 结果去重 3.2 条件查询&#xff08;WHERE子句&#…