Android 如何通过 CursorLoader 使用 ContentProvider 的 insert() 方法将值正确插入 SQLite 数据库?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11131058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:05:25  来源:igfitidea点击:

How to properly insert values into the SQLite database using ContentProvider's insert() method through a CursorLoader?

androidandroid-contentproviderandroid-contentresolverandroid-loadermanagerandroid-cursorloader

提问by Andy

I was reading the doc, but I am still not too sure. Its says to use getContentResolver(), but then that really isn't using CursorLoader. So is there a way to do it through CursorLoader? I know how to do it with query(). Are the steps very similar? Even just a link that explains exactly this would be helpful.

我正在阅读文档,但我仍然不太确定。它说要使用getContentResolver(),但那真的不是在使用 CursorLoader。那么有没有办法做到这一点CursorLoader?我知道如何使用query(). 步骤非常相似吗?即使只是一个准确解释这一点的链接也会有所帮助。

Please note, do not link me to the Google doc as they do not have an example that ever uses the insert()method from ContentProvider using a CursorLoader.

请注意,不要将我链接到 Google 文档,因为他们没有使用insert()ContentProvider 使用CursorLoader.

Thanks in advance!!

提前致谢!!

Edit: I should probably mention the reason I am confused with this is because calling a new CursorLoaderautomatically calls ContentProvidersquery()method. But how can I do the same for insert?

编辑:我可能应该提到我对此感到困惑的原因是因为调用新的CursorLoader自动调用ContentProvidersquery()方法。但是我怎么能对插入做同样的事情呢?

回答by Alex Lockwood

Check out my blog poston the subject:

查看我关于该主题的博客文章

Content Resolvers and Content Providers

内容解析器和内容提供者



The CursorLoaderhas nothing to do with it.

CursorLoader有什么用它做。

Insertion is a totally different concept... it has absolutely nothingto do with the CursorLoader. When coupled with the LoaderManager, the CursorLoaderautomatically queries your database and updates itself when the ContentObserveris notified of a datastore change. It has nothing to do with the actual process of inserting data into your database.

插入是一个完全不同的概念...它绝对没有做的CursorLoader。与 结合使用时LoaderManager, 会CursorLoader自动查询您的数据库并在ContentObserver收到数据存储更改通知时自行更新。它与将数据插入数据库的实际过程无关。

How requests to the ContentResolverare resolved

如何ContentResolver解决对 的请求

When you insert (or query or update or delete) data into your database via the content provider, you don't communicate with the provider directly. Instead, you use the ContentResolverobject to communicate with the provider (note that the ContentResolveris a private instance variable in your application's global Context) . More specifically, the sequence of steps performed is:

当您通过内容提供者将数据插入(或查询、更新或删除)数据库时,您不会直接与提供者通信。相反,您使用该ContentResolver对象与提供者进行通信(请注意,ContentResolver是您应用程序的 global 中的私有实例变量Context)。更具体地说,执行的步骤顺序是:

  1. You call getContentResolver().insert(Uri, ContentValues);

  2. The ContentResolverobject determines the authority of the Uri.

  3. The ContentResolverrelays the request to the content provider registered with the authority (this is why you need to specify the authority in the AndroidManifest.xml).

  4. The content provider receives the request and performs the specified operation (in this case insert). How and where the data is inserted depends on how you implemented the insertmethod (ContentProvideris an abstract class that requires the user to implement insert, query, delete, update, and getType).

  1. 你打电话 getContentResolver().insert(Uri, ContentValues);

  2. ContentResolver对象确定URI的权限。

  3. ContentResolver请求中继到向授权注册的内容提供者(这就是您需要在 中指定授权的原因AndroidManifest.xml)。

  4. 内容提供者接收请求并执行指定的操作(在本例中为insert)。如何以及在哪里被插入的数据取决于你如何实现的insert方法(ContentProvider是需要用户的抽象类来实现insertquerydeleteupdate,和getType)。

Hopefully you were able to wrap your head around that at least a little. The reason why there are so many steps involved is because Android (1) allows applications to have more than one content provider, and (2) needs to ensure that apps can securely share data with other third-party apps. (It wasn't because it wanted to confuse you, I promise).

希望您能够至少稍微了解一下。之所以涉及这么多步骤,是因为 Android (1) 允许应用程序拥有多个内容提供者,以及 (2) 需要确保应用程序可以安全地与其他第三方应用程序共享数据。(这不是因为它想迷惑你,我保证)。

Inserting data via the ContentProvider

通过插入数据 ContentProvider

Now that you (hopefully) have a better idea of how the ContentResolveris able to relay these requests to the content provider, inserting the data is fairly straight forward:

现在您(希望)对如何将ContentResolver这些请求中继到内容提供者有了更好的了解,插入数据是相当简单的:

  1. First, decide which uri you want to have matched by your content provider. This depends on how you decided to match your uris with the UriMatcher. Each uri you have represents a different means of inserting data into your internal database (i.e. if your app has two tables, you will probably have two uris, one for each table).

  2. Create a new ContentValuesobject and use it to package the data you wish to send to the content provider. The ContentValuesobject maps column names to data values. In the below example, the column name is "column_1" and the value being inserted under that column is "value_1":

    ContentValues values = new ContentValues();
    values.put("column_1", "value_1");
    
  3. Once received, the content provider will (in your case) pass the valuesobject to your SQLiteDatabase(via the SQLiteDatabase.insert(String table, String nullColumnHack, ContentValues values)method). Unlike the ContentProvider, this method is implemented for you... the SQLiteDatabaseknows how to handle the valuesobject and will insert the row into the database, returning the row id of the inserted row, or -1if the insertion failed.

  1. 首先,确定您希望与您的内容提供商匹配的 uri。这取决于您如何决定将 uri 与UriMatcher. 您拥有的每个 uri 代表将数据插入内部数据库的不同方式(即,如果您的应用程序有两个表,您可能会有两个 uri,每个表一个)。

  2. 创建一个新ContentValues对象并使用它来打包您希望发送给内容提供者的数据。该ContentValues对象将列名映射到数据值。在下面的示例中,列名称是“column_1”,该列下插入的值是“value_1”:

    ContentValues values = new ContentValues();
    values.put("column_1", "value_1");
    
  3. 收到后,内容提供者将(在您的情况下)将values对象传递给您SQLiteDatabase(通过SQLiteDatabase.insert(String table, String nullColumnHack, ContentValues values)方法)。与 不同ContentProvider,此方法是为您实现的...SQLiteDatabase知道如何处理values对象并将行插入数据库,返回插入行的行 ID,或者-1如果插入失败。

... and that's how you insert data into your database.

...这就是您将数据插入数据库的方式。



TL;DR

TL; 博士

Use getContentResolver().insert(Uri, ContentValues);

getContentResolver().insert(Uri, ContentValues);

回答by davidcesarino

Convert Cursor to ContentValues for easy database insertion.

将 Cursor 转换为 ContentValues 以便于数据库插入。

Its says to use getContentResolver(), but then that really isn't using CursorLoader

它说要使用 getContentResolver(),但那真的不是使用 CursorLoader

Besides what Alex said, there's nothing preventing you from iterating through the Cursorreturned, putting them into ContentValues and then inserting that (say, to a different DB).

除了亚历克斯所说的之外,没有什么可以阻止您遍历Cursor返回的内容,将它们放入ContentValues 然后插入(例如,插入不同的数据库)。

Just an example from the top of my head (a simple Cursorof two Stringcolumns):

只是我头脑中的一个例子(简单Cursor的两String列):

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    if (cursor.moveToFirst()) {
        ArrayList<ContentValues> values = new ArrayList<ContentValues>();
        do {
            ContentValues row = new ContentValues();
            DatabaseUtils.cursorStringToContentValues(cursor, fieldFirstName, row);
            DatabaseUtils.cursorStringToContentValues(cursor, fieldLastName, row);
            values.add(row);
        } while (cursor.moveToNext());
        ContentValues[] cv = new ContentValues[values.size()];
        values.toArray(cv);
        getContentResolver().bulkInsert(CONTENT_NAMES, cv);
    }
}

There are probably more efficient ways to do that (and definitely some integrity checks), but that was my first thought...

可能有更有效的方法来做到这一点(当然还有一些完整性检查),但这是我的第一个想法......