簡體   English   中英

ContentResolver.query() 方法拋出“無效的令牌限制”錯誤

[英]ContentResolver.query() method throws "Invalid token limit" error

內部版本號為 RQ1A.201205.003 或更高版本的 Pixel 設備會出現以下錯誤。
我想知道錯誤的原因以及如何處理它。
這是錯誤還是規格更改?

■代碼

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

■錯誤

"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 - 查詢

 // 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.

從 Android 11 開始, LIMITOFFSET應使用 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)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM