安卓四大組件之ContentProvider

目錄

實現步驟

代碼分析

onCreate

insert?

query

ContextHolder

Cursor

作用與用法

基本步驟:

可能的面試題:為什么使用Cursor?

?為什么使用Cursor

?使用Cursor的好處

靜態內部類實現單例模式

AnndroidManifest.xml配置信息

注釋的意義

Room持久化數據庫

Room的核心組件

??Room的主要功能及優勢

TripDAO

Context避免內存泄漏:


實現步驟

1、定義URI

定義一個靜態的URI 常量指向數據的位置

public static final Uri DATA_URI = Uri.parse("D:/database");

2、創建一個類繼承自ContentProvider,實現必要的CRUD(新建,讀取,更新,刪除操作)

重寫以下方法:

  1. onCreate():初始化數據庫及其他資源
  2. query(),insert(),delete()和update():分別處理對數據的不同操作。每個方法都接收一個URI參數,該參數用于確定所請求的操作類型和目標數據。
  3. geType():返回給定的URI內容類型。通常需要根據傳入的URI返回響應的MIME類型

3. 配置AndroidManifest.xml

為了讓系統知道你的ContentProvider,需要在AndroidManifest.xml文件中注冊它。這通常是在<application>標簽內完成的:

<providerandroid:name=".TripDataProvider"android:authorities="my.application.TripDataProvider"android:exported="false">
</provider>

android:name: 指向你的ContentProvider類。
android:authorities: 應匹配你在代碼中定義的AUTHORITY。
android:exported: 如果你想讓其他應用程序也能訪問這個提供者,可以將其設置為true。

?4. 使用URI進行數據操作

通過ContentResolver對象來執行各種數據操作。

查詢所有行程:??

Cursor cursor = getContentResolver().query(TripDataProvider.TRIP_DATA_URI, null, null, null, null);

?插入新的行程記錄:

? ContentValues values = new ContentValues();// 設置values...Uri newUri = getContentResolver().insert(TripDataProvider.TRIP_DATA_URI, values);

刪除某個ID的行程記錄:

String selection = "id=?"; // 刪除條件
String[] selectionArgs = {"1"}; // 條件參數,假設刪除id為1的行程
int rowsDeleted = getContentResolver().delete(TripDataProvider.TRIP_DATA_URI, selection, selectionArgs);

更新某個行程的信息:

ContentValues updateValues = new ContentValues();// 設置updateValues...String selectionForUpdate = "id=?";String[] selectionArgsForUpdate = {"1"};int updatedRows = getContentResolver().update(TripDataProvider.TRIP_DATA_URI, updateValues, selectionForUpdate, selectionArgsForUpdate);

通過這種方式,就可以用ContentProvider實現跨應用組件的數據共享,并且方便地管理數據。

代碼分析

onCreate
    @Overridepublic boolean onCreate() {mContext = getContext();mDataBase = TripDatabase.getInstance(mContext);ContextHolder.getInstance().setContext(mContext);return true;}

1. 獲取Context 上下文

 mContext = getContext();

?此處調用了getContext()方法來獲取當前的Context。對于ContentProvider而言,getContext()返回的是該提供者運行于的應用程序的上下文環境。這個上下文是ContentProvider與應用程序其他部分進行交互的關鍵。

2. 初始化數據庫?

mDataBase = TripDatabase.getInstance(mContext); 

此處使用從getContext()獲得的Context來初始化TripDatabase實例。TripDatabase是基于Room持久化庫構建的數據庫類,詳見后文。

getInstance(mContext)是一個單例模式的方法,確保在整個應用生命周期內只存在一個數據庫實例。這樣做有助于節省資源并保持數據的一致性。

?3. 設置ContextHolder的Context

?ContextHolder.getInstance().setContext(mContext); 

調用ContextHolder的getInstance()方法獲取其單例實例,然后通過setContext(mContext)方法將之前獲取的mContext 上下文對象傳遞給ContextHolder。 這一步是為了在整個應用程序中共享這個mContext,特別是對于那些可能需要訪問應用程序上下文但無法直接獲得它的組件來說非常有用。

小結:

獲取上下文

初始化數據庫對象,根據上下文來獲取數據

更新上下文,更新上下文的全局持有器

insert?
    @Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {int uriType = S_URI_MATCHER.match(uri);if (uriType == TRIP_DATA_PROVIDER) {TripInfo info = formatContentValueToInfo(values);if (info != null) {long id = mDataBase.tripDAO().insertTrip(info);mContext.getContentResolver().notifyChange(uri, null);if (id > 0) {Uri newUri = Uri.parse(uri.toString() + "/" + id + "|" + OPERATION_TYPE_ADD);mContext.getContentResolver().notifyChange(newUri, null);return ContentUris.withAppendedId(uri, id);}}}return null;}

該方法主要用于向數據庫中插入一條新的行程(Trip)記錄,并通過Uri通知數據的變化。下面是對這段代碼的具體分析:

插入操作:該方法接收一個Uri對象和一個可選的ContentValues對象作為參數,代表要插入的數據。
URI匹配:首先使用S_URI_MATCHER.match(uri)來確定傳入的Uri類型是否與預定義的TRIP_DATA_PROVIDER相匹配。這一步是為了確保請求的URI是針對行程數據的操作。
數據轉換:如果匹配成功,則調用formatContentValueToInfo(values)將ContentValues對象轉換為自定義的TripInfo對象,用于后續的數據處理。
數據庫插入:使用mDataBase.tripDAO().insertTrip(info)將TripInfo對象插入到數據庫中,并返回新插入記錄的ID。

tripDao是一個抽象接口,后文有具體的分析

 Uri newUri = Uri.parse(uri.toString() + "/" + id + "|" + OPERATION_TYPE_ADD);mContext.getContentResolver().notifyChange(newUri, null);

通知變更:如果插入成功(即返回的ID大于0),則構建一個新的Uri對象,這個新Uri是在原Uri的基礎上附加了新記錄的ID以及一個操作類型標識(在這個例子中是OPERATION_TYPE_ADD)。然后,分別對原始Uri和新生成的Uri調notifyChange方法,以通知監聽這些Uri的觀察者數據已經發生變化。
返回結果:最后,如果插入成功,使用ContentUris.withAppendedId(uri, id)構造并返回一個新的Uri,它包含了新插入記錄的ID;如果插入失敗或info為null,則返回null。

小結:

1、URI匹配:檢查傳入URI是否對應于形成數據的操作

2、數據類型轉換 數據層和業務邏輯層分離

TripInfo info = formatContentValueToInfo(values);

3、?數據插入與通知:對原始Uri進行變更通知,還創建了一個更具體的`Uri`來反映剛剛添加的數據項,并同樣發出變更通知。

4. 返回值:如果插入成功返回的Uri包含了新記錄的ID,這使得調用者能夠直接獲取新記錄的位置。若插入失敗,則返回null;

query
@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {int uriType = S_URI_MATCHER.match(uri);Log.e(TAG, "uri path:" + uri.toString());Cursor cursor = null;if (uriType == TRIP_DATA_PROVIDER) {if (selectionArgs == null) {cursor = mDataBase.tripDAO().findTrips();} else {if (selectionArgs.length >= 1) {String id = selectionArgs[0];cursor = mDataBase.tripDAO().findTripById(Integer.parseInt(id));}}}return cursor;}@Nullable@Overridepublic String getType(@NonNull Uri uri) {return null;}

這query()方法實現,用于根據給定的URI查詢數據庫并返回結果。

方法分析 :

1. 參數解釋 Uri uri: 標識要訪問的數據集。

String[] projection: 要返回的列名數組。如果為null,則返回所有列。?

String selection: 一個過濾條件,類似于SQL中的WHERE子句。

String[] selectionArgs: 上述selection中占位符的實際值。

String sortOrder: 排序順序,類似于SQL中的ORDER BY子句。

2. 匹配URI類型

int uriType = S_URI_MATCHER.match(uri);

使用UriMatcher來確定傳入的URI對應的資源類型。

在這個例子中,通過S_URI_MATCHER.match(uri)來匹配URI,并根據其類型執行相應的操作。

3. 根據URI類型進行查詢

?如果uriType等于TRIP_DATA_PROVIDER,表示請求的是行程數據:

?如果沒有提供selectionArgs(即查詢所有行程),則調用mDataBase.tripDAO().findTrips()獲取所有行程記錄。

如果提供了selectionArgs并且至少包含一個元素,則認為是要根據ID查詢特定行程,因此調用mDataBase.tripDAO().findTripById(Integer.parseInt(id))。

5. 返回查詢結果?

將查詢結果封裝在Cursor對象中返回。

在這個例子中,query()方法返回的Cursor可以被其他組件(如Activity或Fragment)用來展示或進一步處理從數據庫檢索到的數據。這使得ContentProvider不僅能夠提供對數據的安全訪問,還能靈活地支持各種數據操作需求。

delete

update 略

ContextHolder

源碼:

public class ContextHolder {private ContextHolder() {}private static class InstanceHolder {private static final ContextHolder INSTANCE = new ContextHolder();}public static ContextHolder getInstance() {return InstanceHolder.INSTANCE;}private Context mContext;public Context getContext() {return LauncherApp.getApplication();}public void setContext(Context mContext) {if (!(mContext instanceof Application)) {throw new RuntimeException("context should be Application context to avoid context leak");}this.mContext = mContext;}
}

這段代碼定義了一個名為ContextHolder的類,用于在應用程序的不同部分之間共享和管理全局Context。

以下是對該類各個組成部分的詳細分析:

單例模式 :

私有構造函數:ContextHolder的構造函數被聲明為private,這意味著它不能從外部直接實例化。

這種設計是實現單例模式的一部分,確保整個應用程序中只有一個ContextHolder實例存在。

靜態內部類InstanceHolder:通過使用靜態內部類InstanceHolder來持有唯一的ContextHolder實例,這是一種懶漢式單例模式的變體。這種方式利用了Java的類加載機制,在第一次調用getInstance()方法時才加載`InstanceHolder`類,從而延遲了`ContextHolder`實例的創建,實現了懶加載的效果。這樣做不僅保證了線程安全,而且避免了同步帶來的性能開銷。

上下文管理

成員變量mContext:用來存儲應用程序的上下文(Context),通常是一個Application對象,以避免內存泄漏的風險。 getContext() 方法:返回當前保存的Context。

LauncherApp.getApplication()來返回一個Context。

public Context getContext() { return LauncherApp.getApplication(); 
} 

setContext(Context mContext) 方法:允許設置ContextHolder持有的Context,但僅當傳入的Context是Application類型時才允許設置。

這是為了避免由于持有Activity或Service等生命周期較短的Context而導致的內存泄漏問題。

public void setContext(Context mContext) { if (!(mContext instanceof Application)){ throw new RuntimeException("context should be Application context to avoid context         leak"); } this.mContext = mContext; 
} 

小結:ContextHolder的設計目的是為了提供全局安全訪問和共享Context的方式。

采用了單例模式和懶加載策略來確保高效且線程安全的實例管理。通過強制要求Context必須是Application類型,有效地防止了因錯誤地傳遞Activity或Service導致的內存泄漏問題

Cursor

作用與用法

Cursor是一個接口,允許你遍歷結果集中的行和列,并提取所需的數據,它代表了一個由數據庫查詢返回的結果集,。

基本步驟:

移動到指定位置:使用moveToFirst(), moveToNext(),?moveToLast(), 或者 moveToPosition(int position)等方法在結果集中移動指針。

讀取數據:一旦定位到某一行,可以使用如getString(columnIndex), getInt(columnIndex), getLong(columnIndex)等方法讀取特定列的數據。

注意,這里的columnIndex是指列在查詢結果中的索引,而不是列名。

關閉Cursor:完成數據讀取后應調用close()方法釋放Cursor占用的資源。 例如,假設我們有一個查詢結果`Cursor,可以通過以下方式遍歷結果集并讀取數據:?

if (cursor != null) { while (cursor.moveToNext()) { // 假設第一個列是'id',第二個列是'name' int id =                 cursor.getInt(cursor.getColumnIndexOrThrow("id")); String name = cursor.getString(cursor.getColumnIndexOrThrow("name")); // 處理id和name... } cursor.close(); // 關閉Cursor以釋放資源 
} 

可能的面試題:為什么使用Cursor?

Cursor是Android中用于表示數據庫查詢結果集的接口。當你執行一個查詢操作時,返回的結果通常是一個Cursor對象,它允許你遍歷查詢結果中的行和列,并提取所需的數據。以下是使用Cursor的原因及其帶來的好處:

?為什么使用Cursor

1. 高效處理大數據集:
? ?Cursor允許逐行讀取數據,而不是一次性將所有數據加載到內存中。這對于處理大量數據特別有用,因為它減少了內存占用并提高了應用的性能。

2.支持復雜查詢結果:
? ?Cursor`可以處理復雜的查詢結果,包括多表連接、聚合函數等產生的結果集。它不僅限于簡單的單表查詢。

3. 靈活的數據訪問方式:
? ?使用Cursor,你可以根據需要選擇要訪問的數據列和行,提供了極大的靈活性。例如,你可以只獲取特定的幾列數據,而不需要加載整個行的所有列。

4. 與ContentProvider無縫集成:
? ?在Android中,ContentProvider經常用來在不同的應用程序或應用組件之間共享數據。Cursor是ContentProvider返回查詢結果的標準方式,這使得不同部分之間的數據交換變得簡單且一致。

?使用Cursor的好處

1. 節省內存:
? ?如前所述,由于Cursor允許逐行讀取數據,因此相比于一次性加載所有數據到內存中,它可以大大減少內存消耗。

2. 簡化數據處理邏輯:
? ?Cursor提供了一系列便捷的方法來獲取不同類型的數據(如getInt(), getString(), getBlob()等),這使得從查詢結果中提取數據變得更加直接和容易。

3. 生命周期管理:
? ?Cursor具有自己的生命周期,可以通過調用close()方法手動關閉它,從而釋放相關資源。良好的資源管理有助于避免潛在的內存泄漏問題。

4. 支持異步操作:
? ??雖然`Cursor本身并不直接支持異步操作,但結合Loader框架(例如LoaderManager和AsyncTaskLoader)或Room數據庫提供的LiveData支持,可以實現非阻塞的數據加載,提升用戶體驗。

5. 便于UI更新:
? ?當與CursorAdapter結合使用時,Cursor可以直接作為數據源綁定到UI組件上(如ListView或RecyclerView),使得數據顯示更加簡便。

Java的類加載機制和懶漢式單例模式雖然涉及的概念不同,但它們之間存在一定的聯系,尤其是在實現單例模式時如何確保類實例的唯一性和延遲加載方面。下面將詳細解釋這兩個概念,并探討它們之間的關系。

靜態內部類實現單例模式

public class ContextHolder {private ContextHolder() {// 私有構造函數,防止外部實例化}private static class InstanceHolder {// 靜態內部類,只有在調用getInstance方法時才會被加載private static final ContextHolder INSTANCE = new ContextHolder();}public static ContextHolder getInstance() {return InstanceHolder.INSTANCE;}// 其他代碼...
}

1.、延遲加載,按需加載:懶漢式單例模式利用了Java類加載機制中的延遲加載特性。具體來說,在單例類首次被真正使用之前(例如調用getInstance()`方法),類不會被加載,因此單例對象也不會被實例化。

2、這是一種更加推薦的懶漢式單例模式實現方式,它不僅實現了延遲加載,而且借助了類加載機制的線程安全性。這種方式通過定義一個靜態內部類來持有單例對象,在第一次引用該內部類時才會觸發類加載及其實例化操作,從而保證了線程安全且高效的單例模式實現。

關鍵點解析

1. 私有構造函數:通過將構造函數設為private,防止其他類直接使用`new`關鍵字來實例化該類的對象,這是單例模式的基礎。

2. 靜態內部類InstanceHolder:僅當調用ContextHolder.getInstance()方法時,`InstanceHolder`類才會被加載。這是因為Java中靜態成員(包括靜態內部類)遵循“按需加載”的原則——即直到第一次使用時才會加載靜態內容。

3. **INSTANCE變量**:在`InstanceHolder`內部定義了一個靜態的`INSTANCE`變量,用于保存單例對象。由于靜態內部類只會被加載一次,因此保證了`INSTANCE`的唯一性。

4. 線程安全:利用Java類加載機制的特性,確保了多線程環境下創建單例對象的線程安全性,而無需額外的同步處理。

5. 懶加載:這種方式實現了懶加載,即只有當真正需要使用單例對象時(即調用了getInstance()),才會初始化該對象,而不是在類加載時就進行初始化。

載器才會嘗試自己加載。這種方法可以有效避免類的重復加載,同時增強了類的安全性。

對于靜態內部類實現單例模式來說,正是利用了Java的“按需加載”特性。靜態內部類InstanceHolder不會在`ContextHolder`類加載時就被加載,而是延遲到首次調用getInstance()方法時才加載。這不僅保證了單例對象的唯一性和線程安全性,還實現了懶加載,提高了資源利用率。

AnndroidManifest.xml配置信息

應用主要配置了權限聲明、保護廣播以及應用組件等信息。
以下是對該文件中包含的內容的分析:
?1. 權限聲明:

android.permission.ACCESS_NETWORK_STATE和 android.permission.INTERNET:允許應用程序訪問網絡狀態和打開網絡連接。?
android.permission.BLUETOOTH 和 android.permission.BLUETOOTH_ADMIN:允許應用程序配對和連接藍牙設備,并進行藍牙管理操作。?
android.permission.READ_EXTERNAL_STORAGE 和 android.permission.WRITE_EXTERNAL_STORAGE:允許應用程序讀取和寫入外部存儲。?
android.permission.FOREGROUND_SERVICE`:允許應用程序創建前臺服務,這在執行長時間運行的任務時非常有用。
android.permission.ACCESS_WIFI_STATE:允許應用程序訪問有關Wi-Fi網絡的信息。
?2. 保護廣播(Protected Broadcasts):

應用程序定義了兩個受保護的廣播,分別是application.ACTION_MAP_RECV和application.ACTION_SCENE_CARD。
這意味著只有具有特定權限的應用才能發送這些廣播動作,增強了應用的安全性。
?3. Application節點下的配置:

<uses-library android:name="myApplication.framework" />表示此應用依賴于名為myApplication.framework的庫,這可能與框架或功能有關,
Content Provider的配置,即TripDataProvider。

注釋的意義

注釋(Annotations)在編程中用于為代碼添加元數據,這些信息可以被編譯器、工具或運行時環境讀取和使用。它們本身不會改變程序的執行邏輯,但可以影響編譯過程、生成文檔、進行代碼檢查等。你提到的幾個注釋分別具有以下意義:

1. @NonNull: 這個注釋通常用來標明一個方法參數、返回值或變量不能為 null。這有助于靜態分析工具識別潛在的空指針異常,并提醒開發者確保該元素在所有情況下都不應為空。

2. @Nullable: 與 @NonNull相反,這個注釋表示一個方法參數、返回值或變量可能為 `null`。它提示開發者需要處理這種情況,以避免空指針異常或其他錯誤。

3. @Dao: 這個注釋是特定于Android開發中的Room持久化庫的一部分。@Dao注釋用于標記接口或抽象類作為數據訪問對象(DAO)。DAO提供了訪問數據庫的方法,如插入、刪除、查詢等操作。Room是一個官方提供的輕量級ORM(對象關系映射)庫,旨在幫助開發者更加方便地創建應用的持久層

Room持久化數據庫

Room持久化庫是Android Jetpack的一部分,它提供了一個抽象層來訪問應用程序的SQLite數據庫。通過Room,開發者可以更方便地進行數據庫操作,同時避免了直接使用SQLite API時的一些復雜性和潛在錯誤。

Room的核心組件

1. Entity(實體)
? 實體代表數據庫中的表。每個實體類對應一個數據庫表。例如,在您的項目中很可能被標記為@Entity注解,并且包含一些字段,這些字段將映射到表中的列。

@Entity(tableName = "trips")
public class TripInfo {@PrimaryKey(autoGenerate = true)private int id;private String name;// 其他字段...
}

?2. DAO (Data Access Object)
? ?DAO是定義用于訪問數據庫的方法接口。通過DAO,您可以輕松執行CRUD(創建、讀取、更新、刪除)操作。
? ?在TripDAO接口中,定義了多種方法來進行數據操作,比如插入、刪除、查詢等。

@Dao
public interface TripDAO {@Insert(onConflict = OnConflictStrategy.REPLACE)long insertTrip(TripInfo info);@Query("SELECT * FROM trips WHERE id = :id")Cursor findTripById(int id);// 更多方法...
}

3. Database
? ?數據庫持有者是一個繼承自RoomDatabase的抽象類。在這個例子中就是TripDatabase。
? 它使用@Database注解來指定其所關聯的實體列表以及數據庫版本號,并提供了獲取DAO實例的方法。

@Database(entities = {TripInfo.class}, version = 1)public abstract class TripDatabase extends RoomDatabase {public abstract TripDAO tripDAO();private static volatile TripDatabase INSTANCE;public static TripDatabase getInstance(Context context) {if (INSTANCE == null) {synchronized (TripDatabase.class) {if (INSTANCE == null) {INSTANCE = Room.databaseBuilder(context.getApplicationContext(),TripDatabase.class,"trip.db").allowMainThreadQueries().build();}}}return INSTANCE;}}


??Room的主要功能及優勢

1. 簡化數據庫操作:Room通過DAO接口自動生成實現,減少了大量樣板代碼。只需定義接口和方法簽名,Room會在編譯期生成具體的實現代碼。
? ?
2. 類型安全與編譯時檢查:Room在編譯時驗證SQL查詢語句的有效性,有助于減少運行時錯誤。如果查詢語句有誤,編譯器會立即提示。

3. 支持LiveData和RxJava:Room能夠返回LiveData對象,這樣當底層數據庫發生變化時,UI可以自動更新。此外,也支持RxJava類型如Flowable、Single等。

4. 事務支持:Room允許在一個事務中執行多個操作,確保要么所有操作都成功,要么全部不執行。

5. 異步查詢支持:為了避免阻塞主線程,Room默認不允許在主線程上執行數據庫查詢。不過,您可以通過.allowMainThreadQueries()選項臨時關閉這一限制(僅限于測試環境)。

6. 數據庫遷移支持:隨著應用的發展,數據庫結構可能需要更改。Room提供了易于使用的API來處理數據庫版本升級和遷移。

Room持久化庫極大地簡化了Android應用程序中數據庫的操作,提高了開發效率并減少了出錯的可能性。結合ContentProvider使用,不僅可以優化內部數據管理,還能增強數據共享能力,滿足更多應用場景的需求。

TripDAO

public interface TripDAO {@Insert(onConflict = OnConflictStrategy.REPLACE)public long insertTrip(TripInfo info);@Deletepublic int deleteTrip(TripInfo... info);@Query("DELETE FROM trips WHERE id = :id")public int deleteTrip(int  id);@Query("DELETE FROM trips WHERE uuid = :uuid")public int deleteTrip(String  uuid);@Query("SELECT * FROM trips WHERE id = :id")public Cursor findTripById(int id);@Query("SELECT * FROM trips")public Cursor findTrips();@Query("SELECT * FROM trips")public List<TripInfo> getAllTrips();@Query("SELECT * FROM trips WHERE tripReallyTime >= :startTime and tripReallyTime <= :endTime")public List<TripInfo> getAllTrips(long startTime,long endTime);@Query("SELECT * FROM trips WHERE id = :id")public TripInfo getTripById(int id);@Query("SELECT * FROM trips WHERE UUID = :uuid")public List<TripInfo> getTripById(String uuid);@Updatepublic int updateTrips(TripInfo info);}

這個TripDAO接口定義了一系列的方法,用于對名為`trips`的數據庫表進行操作。它使用了Room持久化庫提供的注解來簡化SQLite數據庫的操作。以下是對每個方法及其用途的詳細分析:

接口與注解

@Dao: 標記該接口為一個數據訪問對象(DAO),這是Room用來標識可以執行數據庫操作的類或接口的關鍵字。

方法:

1. 插入數據

? ?@Insert(onConflict = OnConflictStrategy.REPLACE)public long insertTrip(TripInfo info);


? ?插入一個新的行程記錄到trips表中。如果存在沖突(如主鍵沖突),則替換現有行。
? ?返回值是新插入行的ID(對于自增主鍵)。

2. 刪除數據
? ?根據對象刪除

 ?@Deletepublic int deleteTrip(TripInfo... info);

刪除傳入的一個或多個`TripInfo`對象對應的記錄。返回被刪除的行數。
根據ID刪除

? ?@Query("DELETE FROM trips WHERE id = :id")public int deleteTrip(int id);?

根據給定的ID刪除特定行程記錄。


根據UUID刪除

@Query("DELETE FROM trips WHERE uuid = :uuid")public int deleteTrip(String uuid);

3. 查詢數據
? ?根據ID查找單個行程

?@Query("SELECT * FROM trips WHERE id = :id")public Cursor findTripById(int id);


? ? ?返回一個Cursor,指向具有指定ID的行程記錄。適用于需要逐行讀取結果的情況。
? ?
? ?查找所有行程

? ? ?@Query("SELECT * FROM trips")public Cursor findTrips();

總結

該接口提供了一組全面的方法來管理`trips`表的數據,包括插入、刪除、查詢和更新操作。通過使用Room提供的注解,這些方法能夠以簡潔的方式實現復雜的數據庫操作,減少了手動編寫SQL語句的需求,并提供了類型安全性和編譯時檢查的支持。這使得開發者可以更加專注于業務邏輯而不是底層的數據庫細節。此外,支持返回Cursor和List<TripInfo>類型的查詢方法,為不同的應用場景提供了靈活性。

Context避免內存泄漏:

長生命周期對象持有短聲明周期對象,避免方法,只有當context是Application類型才賦值

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78438.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78438.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78438.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【HTML】【Web開發】滑動條挑戰

最近在思考如何開發一些入門級的迷你游戲&#xff0c;于是抽空寫了個HTML的滑動條小游戲。 游戲規則如下&#xff1a; 在[0, 100]區間內隨機生成一個目標值&#xff0c;顯示為&#xff1a;X% 倒計時 3 秒過后&#xff0c;出現 10 秒的挑戰倒計時和【停止】按鈕 挑戰倒計時結…

面試踩過的坑

1、 “”和equals 的區別 “”是運算符&#xff0c;如果是基本數據類型&#xff0c;則比較存儲的值&#xff1b;如果是引用數據類型&#xff0c;則比較所指向對象的地址值。equals是Object的方法&#xff0c;比較的是所指向的對象的地址值&#xff0c;一般情況下&#xff0c;重…

專業軟件開發全流程實踐指南

作為一家擁有十余年行業積淀的專業軟件開發服務提供商&#xff0c;我們見證了太多項目從無到有的全過程。今天&#xff0c;我們就用最樸實的語言&#xff0c;跟大家聊聊一個軟件產品從構思到上線的完整歷程。這些經驗不僅適用于自建技術團隊的企業&#xff0c;對正在尋找軟件外…

聊透多線程編程-線程互斥與同步-12. C# Monitor類實現線程互斥

目錄 一、什么是臨界區&#xff1f; 二、Monitor類的用途 三、Monitor的基本用法 四、Monitor的工作原理 五、使用示例1-保護共享變量 解釋&#xff1a; 六、使用示例2-線程間信號傳遞 解釋&#xff1a; 七、注意事項 八、總結 在多線程編程中&#xff0c;線程之間的…

第R4周:LSTM-火災溫度預測

文章目錄 一、前期準備工作1.導入數據2. 數據集可視化 二、構建數據集1. 數據集預處理2. 設置X, y3. 劃分數據集 三、模型訓練1. 構建模型2. 定義訓練函數3. 定義測試函數4. 正式訓練模型 四、模型評估1. Loss圖片2. 調用模型進行預測3. R2值評估 總結&#xff1a; &#x1f36…

toCharArray作用

toCharArray() 是 Java 中 String 類的一個方法&#xff0c;其作用是將字符串對象轉換為一個字符數組。下面為你詳細介紹其用法、原理和示例。 方法定義 toCharArray() 方法在 java.lang.String 類里被定義&#xff0c;方法簽名如下 public char[] toCharArray() 此方法沒有…

STM32八股【6】-----CortexM3的雙堆棧(MSP、PSP)設計

STM32的線程模式&#xff08;Thread Mode&#xff09;和內核模式&#xff08;Handler Mode&#xff09;以及其對應的權級和堆棧指針 線程模式&#xff1a; 正常代碼執行時的模式&#xff08;如 main 函數、FreeRTOS任務&#xff09; 可以是特權級&#xff08;使用MSP&#xff…

驅動支持的最高CUDA版本與實際安裝的Runtime版本

查看電腦上安裝的CUDA版本的多種方法&#xff0c;適用于不同系統和場景。 方法一&#xff1a;通過命令行工具 1. 查看CUDA Driver API版本&#xff08;顯卡驅動支持的CUDA版本&#xff09; 命令&#xff1a;nvidia-smi操作&#xff1a; 打開終端&#xff08;Windows為CMD/Pow…

Python CT圖像預處理——基于ITK-SNAP

Python CT圖像預處理——nii格式讀取、重采樣、窗寬窗位設置_python讀取nii-CSDN博客 基于原文指出以下幾個問題&#xff1a;文件路徑設置模糊&#xff1b;nilabel里面使用的get_data() 方法已經過時&#xff1b;需要導入scikit-image&#xff0c;還要導入一個matplotlib。 一…

【MQ篇】RabbitMQ之消息持久化!

目錄 一、 交換機持久化 (Exchange Persistence)二、 隊列持久化 (Queue Persistence)三、 消息持久化 (Message Persistence)四、 持久化的“黃金三角” &#x1f531;&#xff1a;三者缺一不可&#xff01;五、 來&#xff0c;完整的代碼示例&#xff08;整合持久化和確認機制…

[AI技術(二)]JSONRPC協議MCPRAGAgent

Agent概述(一) AI技術基礎(一) JSON-RPC 2.0 協議詳解 JSON-RPC 2.0 是一種基于 JSON 的輕量級遠程過程調用(RPC)協議,旨在簡化跨語言、跨平臺的遠程通信。以下從協議特性、核心結構、錯誤處理、批量請求等角度進行詳細解析: 一、協議概述 1. 設計原則 ? 簡單性:…

LeetCode238_除自身以外數組的乘積

LeetCode238_除自身以外數組的乘積 標簽&#xff1a;#數組 #前綴和Ⅰ. 題目Ⅱ. 示例0. 個人方法一&#xff1a;暴力循環嵌套0. 個人方法二&#xff1a;前綴和后綴分別求積 標簽&#xff1a;#數組 #前綴和 Ⅰ. 題目 給你一個整數數組 nums&#xff0c;返回 數組 answer &#…

算法筆記.spfa算法(bellman-ford算法的改進)

題目&#xff1a;&#xff08;來源于AcWing&#xff09; 給定一個 n 個點 m 條邊的有向圖&#xff0c;圖中可能存在重邊和自環&#xff0c; 邊權可能為負數。 請你求出 1 號點到 n 號點的最短距離&#xff0c;如果無法從 1 號點走到 n 號點&#xff0c;則輸出 impossible。 …

07 Python 字符串全解析

文章目錄 一. 字符串的定義二. 字符串的基本用法1. 訪問字符串中的字符2. 字符串切片3. 字符串拼接4. 字符串重復5.字符串比較6.字符串成員運算 三. 字符串的常用方法1. len() 函數2. upper() 和 lower() 方法3. strip() 方法4. replace() 方法5. split() 方法 四. 字符串的進階…

Java集成Zxing和OpenCV實現二維碼生成與識別工具類

Java集成Zxing和OpenCV實現二維碼生成與識別工具類 本文將介紹如何使用Java集成Zxing和OpenCV庫&#xff0c;實現二維碼的生成和識別功能。識別方法支持多種輸入形式&#xff0c;包括File對象、文件路徑和Base64編碼。 一、環境準備 添加Maven依賴 <dependencies><…

【專題刷題】二分查找(二)

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的基礎算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&#xff…

Java—ThreadLocal底層實現原理

首先&#xff0c;ThreadLocal 本身并不提供存儲數據的功能&#xff0c;當我們操作 ThreadLocal 的時候&#xff0c;實際上操作線程對象的一個名為 threadLocals 成員變量。這個成員變量的類型是 ThreadLocal 的一個內部類 ThreadLocalMap&#xff0c;它是真正用來存儲數據的容器…

Elasticsearch(ES)中的腳本(Script)

文章目錄 一. 腳本是什么&#xff1f;1. lang&#xff08;腳本語言&#xff09;2. source&#xff08;腳本代碼&#xff09;3. params&#xff08;參數&#xff09;4. id&#xff08;存儲腳本的標識符&#xff09;5. stored&#xff08;是否為存儲腳本&#xff09;6. script 的…

客戶聯絡中心能力與客戶匹配方式

在數字化時代&#xff0c;客戶聯絡中心作為企業與客戶溝通的核心樞紐&#xff0c;其服務能力與客戶需求的精準匹配至關重要。隨著客戶期望的不斷提升&#xff0c;傳統的“一刀切”服務模式已難以滿足個性化需求&#xff0c;如何通過智能化的手段實現服務能力與客戶的高效匹配&a…

深入理解網絡原理:UDP協議詳解

在計算機網絡中&#xff0c;數據的傳輸是通過各種協議實現的&#xff0c;其中用戶數據報協議&#xff08;UDP&#xff0c;User Datagram Protocol&#xff09;作為一種重要的傳輸層協議&#xff0c;廣泛應用于實時通信、視頻流、在線游戲等場景。本文將深入探討UDP協議的特性、…