【问题标题】:Specifying limit / offset for ContentProvider queries为 ContentProvider 查询指定限制/偏移量
【发布时间】:2012-09-28 12:57:17
【问题描述】:

我正在尝试让我的 ContentResolver 运行此查询:

select * from myTable limit 1 offset 2

ContentResolver 中唯一的 query 方法是:

resolver.query(uri, projection, selection, selectionArgs, sortOrder);

我试过了:

final Cursor c = resolver.query(
        MyTable.CONTENT_URI,
        MyTable.PROJECTION,
        " ? ?",
        new String[] {"1", "2"},
        null);

这只会引发 IllegaLArgumentException。 实现这一目标的正确方法是什么?

【问题讨论】:

标签: android android-contentprovider


【解决方案1】:

我将 LIMIT 子句放在 sordOrder 参数中,我也看到其他人做过同样的事情,但不确定它是否 100% 正确:

final Cursor c = resolver.query(
        MyTable.CONTENT_URI,
        MyTable.PROJECTION,
        null,
        null,
        " limit 1 offset 2");

【讨论】:

  • 谢谢。我实际上尝试过使用它,并且认为由于 SQLQueryBuilder 源版本过时而无法正常工作。现在可以正常工作了。
  • 欢迎您,因为您与内容提供商合作,我有一个无耻的插件!我正在开发一个开源 DSL,它可以轻松编写和维护 sqlite 支持的内容提供程序,这里的具体说明 robotoworks.com/mechanoid-plugin/database-dsl 访问父页面以获取安装说明,我会警告它非常 alpha,但它仍然可能是有趣的东西:)
  • 否则子句会被错误地附加到底层查询中,导致 SQL 语句无效
  • 这不适用于 Android 11,java.lang.IllegalArgumentException: Invalid token limit
  • 不知道为什么开发者会称之为“滥用”,// Some apps are abusing "ORDER BY" clauses to inject "LIMIT" from here
【解决方案2】:

我使用语法'limit = offset, limit'将限制子句作为查询参数:

Cursor c = context.getContentResolver().query(
        MyTable.CONTENT_URI.buildUpon().encodedQuery("limit="+offset+","+limit).build(),
        MyTable.PROJECTION,
        null,
        null,
        null);

它至少适用于 MediaStore uris。注意不要对“,”进行编码,否则将无法正常工作。

【讨论】:

  • 感谢您提供替代解决方案,但我现在已经解决了这个问题。 :D
  • 比公认的答案好得多。在排序顺序中捎带 LIMIT 是一种可怕的 hack,很容易破坏提供者的实现。
【解决方案3】:

如果您提供内容提供者,则可以使用android.net.Uri.Builder#appendQueryParameter 提供限制和偏移量作为查询参数,内容提供者可以在构建查询时使用这些参数。

public class MyProvider extends ContentProvider {
    public static final String QUERY_PARAMETER_LIMIT = "limit";
    public static final String QUERY_PARAMETER_OFFSET = "offset";

    public Cursor query(Uri uri, ...) {
        String limit = uri.getQueryParameter(QUERY_PARAMETER_LIMIT);
        String offset = uri.getQueryParameter(QUERY_PARAMETER_OFFSET);

        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();

        // set the table name,...

        // leaving handling of null conditions as an exercise to the reader.
        String limitString = offset + "," + limit;

        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder, limitString);

        //...

        return c;
    }
}

在构建查询时:

private static final Uri CONTENT_URI = MyProvider.CONTENT_URI.buildUpon()
        .appendQueryParameter(MyProvider.QUERY_PARAMETER_LIMIT,
                    String.valueOf(limit))
        .appendQueryParameter(MyProvider.QUERY_PARAMETER_OFFSET,
                    String.valueOf(offset))
        .build();

请注意,android.net.Uri.Builder#appendQueryParameter 对值进行编码以防止 sql 注入。

参考资料:

  1. http://laviefrugale.blogspot.com/2012/01/using-limit-with-android-contentprovider.html
  2. http://www.sqlite.org/lang_select.html
  3. https://stackoverflow.com/a/12476458/1523910 + @eocanha's answer

【讨论】:

  • 你来晚了几年,我也无法验证这是否有效,但感谢您的详尽回答,我希望它对某人有所帮助!
  • @Buffalo,我在我的应用程序中使用了这段代码,我在这里写的部分原因是,我可以稍后再回来,以防万一我“失去”对这段代码的访问权限。在 android 中要记住的东西太多了。
  • 我最喜欢这种方法,但是好像limit和offset是颠倒的,所以构建limitString应该写成:limitString = offset + "," + limit;
  • @nicolai,感谢您的关注,我已将答案更新为不那么含糊。
  • @AvinashR 是的,但该语法无效。我已经尝试过了,它给出了java.lang.IllegalArgumentException: invalid LIMIT clauses: LIMIT 10,因为它接受了 OFFSET, LIMIT 模式。请参阅 SQLiteQueryBuilder 源代码中的第 208 行和第 40 行 android.googlesource.com/platform/frameworks/base/+/refs/heads/… 限制字符串的正则表达式是 "\\s*\\d+\\s*(,\\s*\\d+\\s*)?" 匹配失败
【解决方案4】:

当我尝试使用以下限制字符串 [参见下面的限制字符串] 时:

 StringBuilder sbLimit = new StringBuilder().append(" ").append(i_offset).append(" , ").append(i_limit);
String limit = sbLimit .toString()

结合选择查询、排序和分组,这给了我很好的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-21
    • 2011-08-05
    • 2016-09-19
    • 2019-06-06
    • 2012-05-17
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多