sqlite数据存储
Topics covered: Data storage into DB, cursor adaptor
涵盖的主题: 数据存储到DB,游标适配器
In this article, we will talk about the importance of data storage and how it can be implemented in android. You can find the working of a few apps in the below video that made use of data storage for the functioning of the app. Documentation on applications petInventory and Store inventory are in the links below.
在本文中,我们将讨论数据存储的重要性以及如何在android中实现它。 您可以在下面的视频中找到一些应用的工作原理,这些视频利用数据存储来实现其功能。 有关应用程序petInventory和Store库存的文档在下面的链接中。
Pet inventory: https://medium.com/@gullapalli.nikitha/pet-inventory-app-fcde3caf9786
库存清单: https : //medium.com/@gullapalli.nikitha/pet-inventory-app-fcde3caf9786
Store inventory:https://medium.com/@gullapalli.nikitha/store-inventory-app-9ed2f19f18f1
商店库存: https : //medium.com/@gullapalli.nikitha/store-inventory-app-9ed2f19f18f1
商店库存/宠物库存概述 (Store Inventory / Pet Inventory overview)
Let’s consider the inventory app to understand the concept. The Pet Inventory/ Store Inventory app will help us understand data storage on mobile DB. The app starts off with an empty list of pets/inventories. As we add to the inventory, DB is populated. We can add dummy data to the list, add a new record of a pet, or edit an already existing entry. We can future delete a record or delete all records if needed. When we close the app and reopen we will still be able to see the data as it is stored in the database.
让我们考虑使用库存应用程序来了解概念。 宠物库存/商店库存应用程序将帮助我们了解移动数据库上的数据存储。 该应用程序以一个空的宠物/库存清单开始。 当我们添加到清单中时,将填充数据库。 我们可以将虚拟数据添加到列表中,添加宠物的新记录,或编辑已经存在的条目。 我们将来可以删除记录,也可以根据需要删除所有记录。 当我们关闭应用程序并重新打开时,我们仍然能够看到存储在数据库中的数据。
数据库的目的是什么? (What’s the purpose of the database?)
Now that we know how the app functions. Let us consider a scenario where we are not using a DB and we add an entry to the list of pets. What do you think will happen when the screen is refreshed?
现在,我们知道了该应用程序的功能。 让我们考虑一种不使用数据库而将条目添加到宠物列表的情况。 您认为刷新屏幕后会发生什么?
The list will be empty again as we did not store the data anywhere so we do not have a way to load the data to the screen. Therefore data storage holds an important role in every app. Data storage can be a database on our mobile/cloud or a file on mobile/cloud or any form of data storage. Either way, we store the data that we can use later.
该列表将再次为空,因为我们没有将数据存储在任何地方,因此我们无法将数据加载到屏幕上。 因此,数据存储在每个应用程序中都扮演着重要的角色。 数据存储可以是我们的移动/云上的数据库,也可以是移动/云上的文件或任何形式的数据存储。 无论哪种方式,我们都存储以后可以使用的数据。
In my article, we will particularly talk about performing CRUD operations on a database on the android device.
在我的文章中,我们将特别讨论在android设备上的数据库上执行CRUD操作。
不同层次进行数据库调用 (Different layers to do a DB call)
For a DB call to be done the query needs to go through multiple layers as shown below. Let’s look at each layer and the purpose.
为了完成数据库调用,查询需要经过多个层次,如下所示。 让我们看一下每一层和目的。
![Image for post](https://miro.medium.com/max/9999/1*ao1Ak-GHysGj_V28TXLRqw.png)
Database: Android uses SQLiteDatabase.
数据库 :Android使用SQLiteDatabase。
Contract: Extends BaseColumns class. The contract class is used to keep things uniform. Each table in the database has a subclass in the contract class. These subclasses have the column names and other frequently used string as constants so that every time a CRUD operation is performed we can use the constants from the contracts class. This reduces the scope of error and increases usability and uniform ability of code.
合同:扩展BaseColumns类。 合同类用于保持事物统一。 数据库中的每个表在合同类中都有一个子类。 这些子类具有列名和其他常用字符串作为常量,因此每次执行CRUD操作时,我们都可以使用Contracts类中的常量。 这减少了错误的范围,并提高了代码的可用性和统一能力。
package com.nikitha.android.pets.Data;import android.content.ContentResolver;import android.net.Uri;import android.provider.BaseColumns;public final class PetsContract { public PetsContract() {
} public static final class PetsEntry implements BaseColumns {public final static String DATABASE_NAME ="PetsData.db";
public final static String TABLE_NAME ="Pets";
//public final static String COLUMN_PET_ID="id";
public final static String COLUMN_PET_NAME="Name";
public final static String COLUMN_PET_BREED="Breed";
public final static String COLUMN_PET_WEIGHT="Weight";
public final static String COLUMN_PET_GENDER="Gender"; public final static int gender_Pet_Unknown=0;
public final static int gender_Pet_Male=1;
public final static int gender_Pet_Female=2;
public static final String CONTENT_AUTHORITY = "com.nikitha.android.pets.Data";
/**
* To make this a usable URI, we use the parse method which takes in a URI string and returns a Uri.
*/
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);/***The MIME type of the {@link #CONTENT_URI} for a list of pets*/
public static final String CONTENT_LIST_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_NAME;/** The MIME type of the {@link #CONTENT_URI} for a single pet.*/
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_NAME;
}
}
DB Helper: Extends SQLiteOpenHelper. Db helper is the only class that has to talk to the database directly and creates a DB if not already created. It overrides methods to perform CRUD operations. In the onCreate method, we create a database if the database is not already created.
DB Helper:扩展SQLiteOpenHelper。 db helper是唯一必须直接与数据库对话并创建数据库(如果尚未创建)的类。 它覆盖执行CRUD操作的方法。 如果尚未创建数据库,则在onCreate方法中,我们将创建一个数据库。
package com.nikitha.android.pets.Data;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import androidx.annotation.Nullable;import static com.nikitha.android.pets.Data.Constants.*;import static com.nikitha.android.pets.Data.PetsContract.PetsEntry.*;public class PetsDbHelper extends SQLiteOpenHelper {
public PetsDbHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
} @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_PETS_TABLE);
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
DATABASE_VERSION =newVersion;
db.execSQL(SQL_DELETE_PETS_TABLE);
onCreate(db);
} @Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
} public void deleteAllEntries(SQLiteDatabase db){
db.execSQL(SQL_DELETE_ALL_FROM_TABLE);
}
}
Content Provider: This is the most important layer. The content provider is the part exposed to other apps. If another app wants to access the database of my present app, the content provider is through which they can access the database.
内容提供者 :这是最重要的层。 内容提供商是暴露给其他应用程序的部分。 如果另一个应用程序想要访问我当前应用程序的数据库,则内容提供商可以通过它们访问数据库。
public class PetProvider extends ContentProvider {@Overridepublic boolean onCreate() {
petsDbHelper=new PetsDbHelper(getContext());
db = petsDbHelper.getWritableDatabase();
return false;
}@Nullable
@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
match=sUriMatcher.match(uri);
switch(match) {
case PETS: //perform task;break;
case PETS_ID://perform task;break;
default:cursor=null;break;
}/** Set notification URI on the Cursor so we know what content URI the Cursor was created for.If the data at this URI changes, then we know we need to update the Cursor.**/cursor.setNotificationUri(getContext().getContentResolver(), uri);return cursor;
}/**
* Returns the MIME type of data for the content URI.
*/@Nullable
@Overridepublic String getType(@NonNull Uri uri) {
match=sUriMatcher.match(uri);
final int match = sUriMatcher.match(uri);
switch (match) {
case PETS:return CONTENT_LIST_TYPE;
case PETS_ID:return CONTENT_ITEM_TYPE;
default:throw new IllegalStateException("Unknown URI " + uri + " with match " + match);
}
}/**
* Insert new data into the provider with the given ContentValues.
*/@RequiresApi(api = Build.VERSION_CODES.Q)
@Nullable
@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
match=sUriMatcher.match(uri);
newId=db.insert(TABLE_NAME, null, values);
newUri = ContentUris.withAppendedId(uri, newId);
return newUri;
}}
Content Resolver: Content resolver analyses the URIs from all applications and decide what content provider the request is for. The need for content resolver comes into the picture because mobiles will have more than one app and each app might have a content provider of its own.
内容解析器:内容解析器分析来自所有应用程序的URI,并确定请求的内容提供者。 由于移动设备将具有多个应用程序,并且每个应用程序可能都有其自己的内容提供商,因此需要内容解析器。
Performing CRUD operations from UI(Activity/Fragment)
从UI执行CRUD操作(活动/片段)
Uri uri=Uri.parse(URI);//URI declared in contract
ContentValues value=new ContentValues();
value.put(PRODUCT_QUANTITY, (quan)); //Integer.toStringString id = (String)v.getTag();
String selection = _ID + "=?";
String[] selectionArgs = new String[]{id};
String[] columns={PRODUCT_QUANTITY};C: getContentResolver().insert(uri, values);R: getContext().getContentResolver().query(uri, columns, selection,
selectionArgs, null);
U:getContext().getContentResolver().update(uri,value,selection,selec
tionArgs);D: getContentResolver().delete(uri, null, null);
How can app1 get access to the app2 database?
app1如何获得对app2数据库的访问权限?
If an app1 needs to access the database of the app 2. It requires permission. app1 manifest file should request permission similar to the below statement.
如果app1需要访问应用程序2的数据库。它需要权限。 app1清单文件应请求类似于以下语句的权限。
app1 Manifest:
<uses-permission android:name="com.example.udacity.droidtermsexample.TERMS_READ"/>app2 Manifest
<provider
android:name=".Data.InventoryProvider"
android:authorities="com.nikitha.android.inventoryapp.Data"
android:exported="false" />
Conclusion:
结论:
Room is an object-mapping library that provides local data persistence with minimal boilerplate code. At compile time, it validates each query against your data schema, so broken SQL queries result in compile-time errors instead of runtime failures. Room abstracts away some of the underlying implementation details of working with raw SQL tables and queries. It also allows you to observe changes to the database’s data, including collections and join queries, exposing such changes using LiveData objects. It even explicitly defines execution constraints that address common threading issues, such as accessing storage on the main thread.
Room是一个对象映射库,它以最少的样板代码提供本地数据持久性。 在编译时,它将根据您的数据模式验证每个查询,因此损坏SQL查询将导致编译时错误,而不是运行时错误。 Room摘录了使用原始SQL表和查询的一些基础实现细节。 它还允许您观察数据库数据的变化,包括集合和联接查询,并使用LiveData对象公开这些变化。 它甚至明确定义了执行约束,以解决常见的线程问题,例如访问主线程上的存储。
翻译自: https://medium.com/swlh/data-storage-sqlite-content-provides-9d1ffe4da39d
sqlite数据存储