ContentResolver.query() 方法抛出“无效令牌限制”错误

2024-01-11

内部版本号为 RQ1A.201205.003 或更高版本的 Pixel 设备上会出现以下错误。
我想知道错误的原因以及如何处理。
这是错误还是规格更改?

■code

      ContentResolver resolver = getContentResolver();
      String order = "date ASC limit 100";
      Cursor cursor = resolver.query(
          CallLog.Calls.CONTENT_URI,
          null,
          null,
          null,
          order);

■error

"Invalid token limit,LINE:142,Method:readExceptionFromParcel Exception:Invalid token limit"

■发生错误的内部版本号

https://support.google.com/pixelphone/thread/87641266
・RQ1A.201205.003
・RQ1A.201205.008
・RQ1A.201205.011

https://support.google.com/pixelphone/thread/93232095
・RQ1A.210105.002
・RQ1A.210105.003

https://support.google.com/pixelphone/thread/96244000
・RQ1A.210205.004

■如果将其替换为以下代码,则不会发生错误。

buildUpon().appendQueryParameter("limit", "100")

■附加信息 使用官方文档的方法实现时,没有出现错误,但是LIMIT子句不起作用(所有记录均已检索)。

ContentProvider-查询 https://developer.android.com/reference/android/content/ContentProvider#query(android.net.Uri,%20java.lang.String%5B%5D,%20android.os.Bundle,%20android.os.CancellationSignal)

 // Request 20 records starting at row index 30.
 Bundle queryArgs = new Bundle();
 queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 30);
 queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 20);
 
 Cursor cursor = getContentResolver().query(
       contentUri,    // Content Uri is specific to individual content providers.
       projection,    // String[] describing which columns to return.
       queryArgs,     // Query arguments.
       null);         // Cancellation signal.

从安卓11开始,LIMIT and OFFSET应该使用 Bundle 来检索

public Cursor query (Uri uri, 
                String[] projection, 
                Bundle queryArgs, 
                CancellationSignal cancellationSignal) 

我使用这样的解决方案,它对我有用:

import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull

data class MediaItem(
    val id: Long,
    val contentUri: Uri,
    val data: String?,
    val mimeType: String?,
    val duration: Long?
)

private fun fetchGalleryImages(
    context: Context,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): List<MediaItem> {
    val galleryImageUrls = mutableListOf<MediaItem>()
    val collection = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    val projection = arrayOf(
        MediaStore.Files.FileColumns._ID,
        MediaStore.Files.FileColumns.DATA,
        MediaStore.Files.FileColumns.DATE_ADDED,
        MediaStore.Files.FileColumns.MEDIA_TYPE,
        MediaStore.Files.FileColumns.MIME_TYPE,
        MediaStore.Files.FileColumns.TITLE,
        MediaStore.Video.Media.DURATION
    )
    val whereCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ? OR ${MediaStore.Files.FileColumns.MEDIA_TYPE} = ?"
    val selectionArgs = arrayOf(
        MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE.toString(),
        MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO.toString()
    )
    createCursor(
        contentResolver = context.contentResolver,
        collection = collection,
        projection = projection,
        whereCondition = whereCondition,
        selectionArgs = selectionArgs,
        orderBy = orderBy,
        orderAscending = orderAscending,
        limit = limit,
        offset = offset
    )?.use { cursor ->
        while (cursor.moveToNext()) {
            val idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID)
            if (idIndex < 0) continue
            val id = cursor.getLong(idIndex)
            galleryImageUrls.add(
                MediaItem(
                    id = id,
                    contentUri = ContentUris.withAppendedId(collection, id),
                    data = cursor.getStringOrNull(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)),
                    mimeType = cursor.getStringOrNull(cursor.getColumnIndex(MediaStore.Files.FileColumns.MIME_TYPE)),
                    duration = cursor.getLongOrNull(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))
                )
            )
        }
    }
    return galleryImageUrls
}

private fun createCursor(
    contentResolver: ContentResolver,
    collection: Uri,
    projection: Array<String>,
    whereCondition: String,
    selectionArgs: Array<String>,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): Cursor? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
        val selection = createSelectionBundle(whereCondition, selectionArgs, orderBy, orderAscending, limit, offset)
        contentResolver.query(collection, projection, selection, null)
    }
    else -> {
        val orderDirection = if (orderAscending) "ASC" else "DESC"
        var order = when (orderBy) {
            "ALPHABET" -> "${MediaStore.Audio.Media.TITLE}, ${MediaStore.Audio.Media.ARTIST} $orderDirection"
            else -> "${MediaStore.Audio.Media.DATE_ADDED} $orderDirection"
        }
        order += " LIMIT $limit OFFSET $offset"
        contentResolver.query(collection, projection, whereCondition, selectionArgs, order)
    }
}

@RequiresApi(Build.VERSION_CODES.O)
fun createSelectionBundle(
    whereCondition: String,
    selectionArgs: Array<String>,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): Bundle = Bundle().apply {
    // Limit & Offset
    putInt(ContentResolver.QUERY_ARG_LIMIT, limit)
    putInt(ContentResolver.QUERY_ARG_OFFSET, offset)
    // Sort function
    when (orderBy) {
        "ALPHABET" -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.TITLE))
        else -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.DATE_ADDED))
    }
    // Sorting direction
    val orderDirection =
        if (orderAscending) ContentResolver.QUERY_SORT_DIRECTION_ASCENDING else ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
    putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, orderDirection)
    // Selection
    putString(ContentResolver.QUERY_ARG_SQL_SELECTION, whereCondition)
    putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ContentResolver.query() 方法抛出“无效令牌限制”错误 的相关文章

随机推荐