Как работать с Context, ContentProvider и content:// (Java/Kotlin)
Короткий ответ: используйте Context для доступа к окружению и системным сервисам, ContentProvider + URI content:// — для унифицированного и безопасного обмена данными, а Intent.data/scheme — для открытия и шаринга этих URI; всегда отдавайте предпочтение applicationContext и FileProvider при обмене файлами.
Оглавление {{TOC_AUTOMATIC}}
Context: роли, виды и правильное использование
Context — это «окружение» приложения: ресурсы, файловая система, ContentResolver и системные сервисы. Главная практическая рекомендация — передавать applicationContext в долгоживущие объекты (репозитории, синглтоны) и Activity‑context только для краткоживущих UI‑операций.
Когда использовать какой Context:
- applicationContext — для репозиториев, DB, стартов сервисов без UI.
- Activity/Fragment context — для Inflater, создания UI, startActivity().
- BroadcastReceiver (onReceive) — контекст ограничен временем выполнения onReceive.
Примеры: Kotlin — репозиторий получает applicationContext:
class MyRepository(private val context: Context) {
fun getAppVersion(): String =
context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "unknown"
}
Частая ошибка — хранить ссылку на Activity или View в синглтоне → утечки памяти. Для долгоживущих объектов используйте applicationContext.
ContentProvider и content://: структура, реализация и использование
ContentProvider — абстракция для обмена и инкапсуляции данных: он нормирует доступ через ContentResolver и URI с схемой content://. URI обычно имеют вид: content://authority/path/.../[id]
Примеры:
- content://com.android.contacts/contacts
- content://com.example.notes.provider/notes/42
Основные методы ContentResolver:
- query(uri, projection, selection, selectionArgs, sort)
- insert(uri, values)
- update(uri, values, selection, args)
- delete(uri, selection, args)
- openInputStream(uri) / openOutputStream(uri)
Минимальная структура провайдера (существенные моменты):
- наследовать ContentProvider и переопределить onCreate, query, insert, update, delete, getType;
- зарегистрировать provider в AndroidManifest, указать authorities и exported/permissions;
- при изменениях вызывать context?.contentResolver?.notifyChange(uri, null).
Ключевой момент безопасности: не экспортируйте провайдер с чувствительными данными без проверки прав и ограничений по URI и операциям.
Intent, data и scheme: как передавать и открывать контент
Intent может содержать URI в поле data и MIME type в type. Это позволяет другим компонентам/приложениям запросить открытие/обработку ресурса:
Kotlin — открыть контакт по URI:
fun openContact(context: Context, contactUri: Uri) {
val intent = Intent(Intent.ACTION_VIEW, contactUri)
context.startActivity(intent)
}
scheme — часть URI до двоеточия: content, file, https, tel. В intent‑filter можно указать android:scheme, android:host и android:pathPrefix, чтобы Activity принимала определённые URI.
Для обмена файлами между приложениями:
- Используйте FileProvider, который выдаёт content:// URI, а не file://;
- Передавайте флаг Intent.FLAG_GRANT_READ_URI_PERMISSION.
Java — открыть PDF через FileProvider:
Uri uri = FileProvider.getUriForFile(context, "com.example.app.fileprovider", pdfFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/pdf");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
Для обмена файлами между приложениями всегда используйте FileProvider и URI с content:// — это безопасно и соответствует политике доступа к файлам в современных версиях Android.
Практические сценарии: коротко и применимо
- Получение изображения из галереи:
- Запускаете ActivityResultContracts.GetContent() → получаете content:// URI.
- Через contentResolver.openInputStream(uri) декодируете Bitmap.
- Поделиться файлом:
- Получаете URI из FileProvider.getUriForFile(...).
- Формируете Intent.ACTION_SEND, кладёте EXTRA_STREAM и ставите FLAG_GRANT_READ_URI_PERMISSION.
- Публичный доступ к данным:
- Реализуете ContentProvider с чёткой URI‑схемой и правами.
- Добавляете Activity с intent‑filter VIEW, чтобы другие приложения могли открыть конкретный ресурс.
Рекомендации по архитектуре и лучшие практики
- Инкапсулируйте обращение к ContentResolver в репозитории/data‑source; тестируйте через заглушки (mock ContentResolver).
- Не захардкодьте строки URI — создайте утилиту, строящую URI централизованно.
- Выполняйте операции с провайдером в IO‑потоке (корутины, Executors).
- При экспорте данных продумайте permissions, проверку вызывающего (например, привязка к UID), и минимизируйте набор операций, доступных внешним клиентам.
Частые ошибки
- Удержание Activity‑context в длительных объектах → утечки памяти.
- Использование file:// вместо content:// (FileProvider) → ошибки доступа в новых Android.
- Не указывать FLAG_GRANT_READ_URI_PERMISSION при передаче URI другому приложению.
- Экспортировать ContentProvider с чувствительными данными без ограничений или permissions.
Никогда не экспортируйте ContentProvider с чувствительными данными без чётких permissions и валидации вызывающего приложения. Иначе данные смогут прочитать/изменить любые сторонние приложения.
FAQ
Q: Нужно ли всегда реализовывать ContentProvider для внутренних данных? A: Нет. Если данные используются только внутри приложения — провайдера можно не создавать. ContentProvider нужен для унификации доступа и обмена данными с внешними приложениями или для использования абстракций (например, Room + ContentProvider в модульной архитектуре).
Q: Как безопасно дать доступ к файлу другому приложению?
A: Через FileProvider и выдачу content:// URI с флагом FLAG_GRANT_READ_URI_PERMISSION; в манифесте описываете
Q: Где хранить URI и authority? A: В одном месте — константы/утилиты внутри модуля данных; не захардкодьте строки по всему приложению.
Теперь у вас готовая практическая картина: Context — доступ к окружению, ContentProvider и content:// — унифицированная точка доступа к данным, Intent.data/scheme — механизм открытия и шаринга. Соблюдайте ограничения по контексту, используйте FileProvider и продуманную систему прав — и ваши данные будут доступны и безопасны.