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.pswp.cn/bicheng/77951.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77951.shtml
英文地址,請注明出處:http://en.pswp.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子句&#…