我有两个问题,为了让我的问题在这里清晰,一个简短的代码片段:
ContentResolver resolver = context.getContentResolver();
DocumentsContract.deleteDocument(resolver, documentUri);
resolver.openFileDescriptor(documentUri, "rw");
Run Code Online (Sandbox Code Playgroud)
文档说最后一行“如果 URI 下不存在文件或模式无效,则抛出 FileNotFoundException”。
但实际上我得到java.lang.IllegalArgumentException.
(问题 1)这是一个错误还是可以?
(问题2)openFileDescriptor()显然不是测试文档是否存在的好方法。什么是“官方”方法来做到这一点?
编辑(添加错误日志):
W/System.err: java.lang.IllegalArgumentException: 无法确定 9016-4EF8:myFolder/file1.wav 是否是 9016-4EF8:myFolder: java.io.FileNotFoundException: Missing file for 9016-4EF8:myFolder/file1 .wav 在 /storage/extSdCard/myFolder/file1.wav
W/System.err: 在 android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
W/System.err: 在 android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:148)
W/System.err: 在 android.content.ContentProviderProxy.openAssetFile(ContentProviderNative.java:618)
W/System.err: 在 android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:945)
W/System.err: 在 android.content.ContentResolver.openFileDescriptor(ContentResolver.java:784)
W/System.err: 在 android.content.ContentResolver.openFileDescriptor(ContentResolver.java:739)
和:
documentUri="content://com.android.externalstorage.documents/tree/9016-4EF8%3AmyFolder/document/9016-4EF8%3AmyFolder%2Ffile1.wav"
我们如何使用 删除 Android 表中的所有行ContentResolver?
我努力了:
context.getContentResolver().delete(Abcd.CONTENT_URI, null, null);
context.getContentResolver().delete(Abcd.CONTENT_URI, "1", null);
当我给出一个条件时,我知道我的 uri 是正确的:
context.getContentResolver().delete(Channel.CONTENT_URI, "name = ?", "abcd");
该代码有效。
全部删除的正确方法是什么?
现在我正在使用一个 hack:context.getContentResolver().delete(Channel.CONTENT_URI, "name != ?", "");因为名称永远不能为空。
但我想知道最好的方法。
我们都知道ContentResolver不应在 UI 线程上执行查询,但令人惊讶的是,我ContentResolver在官方文档中找不到有关类线程安全的信息。
我知道如何编写 thread-safe ContentProvider,并且我知道SQLite默认情况下它是线程安全的(它实现了内部锁定机制)。
但是,使用ContentResolver来自多个线程的单个实例是否安全(例如,两个线程调用insert()或query()在同一对象上并行)?
multithreading android thread-safety android-contentresolver
我正在获取设备中所有图像、视频和音频文件的列表。下面的代码在 android O (api 27) 之前的所有设备上都可以正常工作。但它不适用于 android Pie 设备(api 28)。Cursor 返回 nullquery
对于图像
String[] proj = {MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.TITLE,
MediaStore.Images.Media.SIZE
};
ContentResolver cr = context.getContentResolver();
Cursor imagescursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
proj, null, null, "_size DESC");
Run Code Online (Sandbox Code Playgroud)
对于视频文件
String[] proj = {MediaStore.Video.Media._ID,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.TITLE,
MediaStore.Video.Media.SIZE,
MediaStore.Video.Media.DURATION
};
ContentResolver cr = context.getContentResolver();
Cursor videocursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
proj, null, null, "_size DESC");
Run Code Online (Sandbox Code Playgroud)
对于音频文件
String[] proj = {MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.DURATION};
ContentResolver cr = context.getContentResolver();
Cursor audiocursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
proj, null, null, "_size …Run Code Online (Sandbox Code Playgroud) android mediastore android-contentresolver media-queries android-9.0-pie
我想通过 contentResolver 获取 uri 插入音乐。
val contentValues = ContentValues()
contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, music.displayName)
contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)
Run Code Online (Sandbox Code Playgroud)
如果没有设置MediaStore.Audio.Media.DATA,一定是错误的。
如果使用相同的方法插入 MediaStore.Images.Media.EXTERNAL_CONTENT_URI 或 MediaStore.Video.Media.EXTERNAL_CONTENT_URI 成功。
我只想在 Android Q 上获取写入数据的 uri。
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.lastIndexOf(int)' on a null object reference
at android.os.Parcel.createException(Parcel.java:1959)
at android.os.Parcel.readException(Parcel.java:1921)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.insert(ContentProviderNative.java:476)
at android.content.ContentResolver.insert(ContentResolver.java:1603)
Run Code Online (Sandbox Code Playgroud) 通过我的应用程序,我使用创建日历事件ContentResolver。活动已成功创建,您可以在系统日历应用程序中看到它们。当用户使用 Google 日历应用程序时会出现问题。有时,事件需要几分钟的时间才会出现。此外,当该事件最终出现在 Google 日历中并且用户将其删除时,它仍然会在系统日历中再次可见几分钟。
在我的应用程序中,我想创建在 caledndar 中打开新创建的事件的意图,但由于该同步问题,它没有被显示,因为它还不可见。另外,在创建新事件之前,我会检查它是否已经存在,并且由于同步,它似乎没有被删除,并且我没有在应该创建新事件时创建新事件。
这是我创建事件的方式:
fun addEventToCalendar(context: Context,
title: String,
description: String?,
startDateMillis: Long,
endDateInMillis: Long,
tag: String): Long? {
val timeZone = TimeZone.getDefault()
val values = ContentValues().apply {
put(CalendarContract.Events.DTSTART, startDateMillis)
put(CalendarContract.Events.DTEND, endDateInMillis)
put(CalendarContract.Events.TITLE, title)
description?.let { put(CalendarContract.Events.DESCRIPTION, description) }
put(CalendarContract.Events.EVENT_TIMEZONE, timeZone.id)
put(CalendarContract.Events.CALENDAR_ID, getCalendarId(context))
put(CalendarContract.Events.UID_2445, tag)
}
val uri = context.contentResolver.insert(CalendarContract.Events.CONTENT_URI, values)
return uri?.lastPathSegment?.toLong()
}
fun checkIfEventAlreadyExist(context: Context, tag: String): Long? {
val projection = arrayOf(CalendarContract.Events._ID, CalendarContract.Events.DTSTART, CalendarContract.Events.DTEND, CalendarContract.Events.UID_2445)
val cursor = context.contentResolver.query(
CalendarContract.Events.CONTENT_URI, …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用分页库在 RecyclerView 中显示具有搜索功能的联系人。https://github.com/anujmiddha/paged-list-demo我关注这个 GitHub 项目。以下是我的项目中的代码片段。我正在尝试使用 pagedList 适配器逐渐获取联系人。但这个 LIMIT 和 OFFSET 在某些 Android 版本(例如 Android 9.0)中无法按预期工作。有什么替代方案吗?
private val PROJECTION = arrayOf(
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
)
val cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
PROJECTION,
null,
null,
ContactsContract.Contacts.DISPLAY_NAME +
" ASC LIMIT " + limit + " OFFSET " + offset)
Run Code Online (Sandbox Code Playgroud)
另外,我尝试了另一种方法,如下所示。
val queryArgs = Bundle()
val cursor: Cursor?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, offset)
queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, limit)
cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
PROJECTION,
queryArgs,
null)
} else {
cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
PROJECTION,
null,
null,
ContactsContract.Contacts.DISPLAY_NAME + …Run Code Online (Sandbox Code Playgroud) android android-contentresolver android-contentprovider android-architecture-components android-paging-library
我已经在我的应用程序中实现了从电话簿中选择联系人的功能。为了使动作 PICK 的意图在 android 11 上工作,我将其添加到我的清单中:
<queries>
<intent>
<action android:name="android.intent.action.PICK" />
<data android:mimeType="vnd.android.cursor.dir/phone_v2" />
</intent>
</queries>
Run Code Online (Sandbox Code Playgroud)
该代码在 Android 版本 10 及更低版本上运行良好。但在 Android 版本 11 上,我从电话簿中选择的联系人不会插入到我的应用程序的文本字段中,因为 ContentResolver.query 返回空光标。it.moveToFirst() 返回 false 这是我的代码:
Constants.START_PICK_CONTACT_ACTION -> {
data?.data?.let { uri ->
activity.contentResolver.query(uri, null, null, null, null)?.use {
if (it.moveToFirst()) {
val number: String? = it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
etPhoneNumber.setText(number)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请帮我。
我正在使用 MediaStore.Files 在 InternalStorage/Documents/MyFolderName/xyz.pdf 中创建文件
使用
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, fileName);
contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, fileType);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, dstPublicDirectory + File.separator + dstSubDirectory);
// Getting content uri for the file
Uri dstFileUri = resolver.insert(MediaStore.Files.getContentUri("external"), contentValues);
Run Code Online (Sandbox Code Playgroud)
我能够创建该 xyz.pdf 文件
但是,为了删除我正在使用的文件
getActivity().getContentResolver().delete(fileUriToDelete, null, null);
Run Code Online (Sandbox Code Playgroud)
以上已从 MediaStore.Files 的数据库中删除,但无法删除文件系统中的该文件。
由于该文件仍然在以下位置可用:InternalStorage/Documents/MyFolderName 这种情况仅在 Android 10 中发生。在 Android 11 中,该文件将从文件系统以及 MediaStore.Files db 中删除
根据https://developer.android.com/guide/components/intents-common#Contacts上的官方文档
您可以使用选择意图
public void selectContact() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_CONTACT);
}
Run Code Online (Sandbox Code Playgroud)
}
有关在获取联系人URI后如何检索联系人详细信息的信息,请阅读检索联系人的详细信息。记住,当你检索联系人URI与上面的意图,你不会需要READ_CONTACTS权限读取该联系人的详细信息。
它指向https://developer.android.com/training/contacts-provider/retrieve-details以获取联系人的详细信息
当我按照上面链接中的说明进行操作时,我得到
Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/data from pid=5313, uid=10087 requires android.permission.READ_CONTACTS, or grantUriPermission()
Run Code Online (Sandbox Code Playgroud)
我试图通过获取联系方式
每一种方式都需要require android.permission.READ_CONTACTS异常。是否有一个示例可以按照文档中的说明工作?
最小,完整和可验证的示例,位于
https://github.com/aaronvargas/ContactsSSCCE
要测试是否使用READ_CONTACTS,必须在“系统应用设置”中进行更改
- 编辑
在Android问题跟踪器上通过https://issuetracker.google.com/issues/118400813创建了问题
android android-contentresolver contactscontract android-contacts android-permissions