#android #android-manifest #android-contentprovider #android-contentresolver
#Android #android-манифест #android-contentprovider #android-contentresolver
Вопрос:
У меня есть два приложения: основное приложение и потребительское приложение. Мое потребительское приложение получит доступ к локальной базе данных основного приложения с помощью ContentResolver
. Все работает нормально, когда запущены как основное, так и потребительское приложение. Однако, как только я отключаю основное приложение, потребительское приложение не может получить доступ к локальной базе данных. Сообщение об ошибке выглядит следующим образом.
E/ActivityThread: Failed to find provider info for com.mobile.&ithubuser.provider
Я проверил манифесты обоих приложений, и они верны (в противном случае приложение-потребитель не смогло бы получить доступ к основному приложению, когда они оба запущены). Тем не менее, это манифесты обоих моих приложений.
Манифест основного приложения:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
packa&e="com.mobile.&ithubuser"&&t;
<uses-permission android:name="android.permission.INTERNET" /&&t;
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /&&t;
<permission android:name="com.mobile.&ithubuser.READ_DATABASE" android:protectionLevel="normal" /&&t;
<permission android:name="com.mobile.&ithubuser.WRITE_DATABASE" android:protectionLevel="normal" /&&t;
<application
...&&t;
<provider
android:name="com.mobile.&ithubuser.provider.FavoriteUserProvider"
android:authorities="com.mobile.&ithubuser.provider"
android:enabled="true"
android:exported="true"
android:readPermission="com.mobile.&ithubuser.READ_DATABASE"
android:writePermission="com.mobile.&ithubuser.WRITE_DATABASE" /&&t;
...
Манифест потребительского приложения.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
packa&e="com.mobile.&ithubuser.consumerapp"&&t;
<uses-permission android:name="android.permission.INTERNET" /&&t;
<uses-permission android:name="com.mobile.&ithubuser.READ_DATABASE" /&&t;
<uses-permission android:name="com.mobile.&ithubuser.WRITE_DATABASE" /&&t;
<application
...&&t;
...
</application&&t;
</manifest&&t;
Я думаю, что проблема может быть вызвана моим ContentProvider
классом. Вот код для onCreate
, init
и UriMatcher
моего класса provider в моем основном приложении.
class FavoriteUserProvider : ContentProvider() {
private lateinit var favoriteUserDao: FavoriteUserDao
override fun onCreate(): Boolean {
context?.let {
val context = it
favoriteUserDao = FavoriteUserRoomDatabase.&etDatabase(context).favoriteUserDao()
}
return true
}
override fun query(
uri: Uri, projection: Array<Strin&&&t;?, selection: Strin&?,
selectionAr&s: Array<Strin&&&t;?, sortOrder: Strin&?
): Cursor? {
...
}
override fun &etType(uri: Uri): Strin&? {
...
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
...
}
override fun update(
uri: Uri, values: ContentValues?, selection: Strin&?,
selectionAr&s: Array<Strin&&&t;?
): Int {
...
}
override fun delete(uri: Uri, selection: Strin&?, selectionAr&s: Array<Strin&&&t;?): Int {
...
}
companion object {
private const val FAVORITE_USER_LIST = 1
private const val FAVORITE_USER_ITEM = 2
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
init {
uriMatcher.addURI(AUTHORITY, FavoriteUserColumns.TABLE_NAME, FAVORITE_USER_LIST)
uriMatcher.addURI(AUTHORITY, "${FavoriteUserColumns.TABLE_NAME}/*", FAVORITE_USER_ITEM)
}
}
}
В чем здесь проблема и как я могу это исправить?
Комментарии:
1. Возможно, вы захотите предоставить подробное описание того, что вы подразумеваете под «отключением основного приложения».
2. @CommonsWare Я имею в виду отключение основного приложения: открытие экрана «Последние» и нажатие кнопки «X», чтобы закрыть мое основное приложение.
3. «В чем здесь проблема» — вы вручную завершили процесс вашего приложения, возможно, переведя приложение в режим «принудительной остановки», в зависимости от модели вашего устройства. «как я могу это исправить?» — не делайте этого. 🙂 Вы могли бы попробовать переместить поставщика в его собственный процесс с помощью
android:process
атрибута на<provider&&t;
, хотя это может вызвать проблемы с реализацией. И на устройствах, где удаление приложения с экрана обзора «принудительно останавливает» приложение, вы можете просто облажаться, пока пользователь вручную не запустит это приложение из лаунчера или с этим приложением не будет использовано какое-либо другое явноеIntent
.4. @CommonsWare я вижу. Это проблематично; является ли это предполагаемым поведением, т. Е. зависимое приложение можно использовать только при запуске «зависимого» приложения? Если это так, то ContentProvider сложно реализовать. Я никогда не видел, чтобы
android:process
приложение использовалось в ContentProvider. У вас есть образец? Кроме того, что произойдет, если я не завершу свое приложение вручную, но вместо этого система Android завершит работу моего приложения из-за нехватки ресурсов?5. «зависимое приложение можно использовать только тогда, когда запущено «зависимое» приложение?» — обычно Android автоматически запускает ваш процесс, когда клиент начинает общаться с вашим провайдером. По-видимому, Android не ожидает, что пользователь вручную завершит этот процесс. «У вас есть образец?» — нет, извините. «это система Android завершила работу моего приложения из-за нехватки ресурсов?» — это учитывает клиентов поставщика.
Ответ №1:
Обычно Android управляет процессом для ContentProvider
автоматически, запуская его при необходимости и завершая, когда он больше не нужен. Если процесс неожиданно завершается, например, из-за сбоя, клиенты могут получать ошибки, ничем не отличающиеся от ошибок веб-клиентов при сбое веб-сервера.
Точное поведение при удалении приложения с экрана обзора зависит от устройства. В некоторых случаях это может просто удалить задачу (т. Е. обратный стек) и оставить процессы в покое. Во многих случаях это завершает процесс, связанный с этой задачей. И в некоторых случаях оно будет вести себя так, как если бы пользователь использовал «Принудительную остановку» на экране настроек для этого приложения. В результате, если пользователь удаляет приложение с экрана обзора, содержащее ContentProvider
активно используемое, результаты будут отличаться, но могут привести к ошибкам в этих активных клиентах.
Вы можете попытаться минимизировать этот эффект, разместив поставщика в отдельном процессе, используя android:process
атрибут в <provider&&t;
элементе. С положительной стороны, это снижает вероятность того, что удаление приложения с экрана обзора повлияет на этот конкретный процесс. С другой стороны, это означает, что остальная часть приложения, содержащего этого поставщика, также должна использовать IPC для работы с этим поставщиком, как это делают клиенты вне приложения. Лично я не писал, ContentProvider
где мне был нужен клиент с длительным сроком службы в течение достаточно долгого времени, поэтому я не тестировал этот сценарий. И обратите внимание, что это не поможет на тех устройствах, где экран обзора привязан к поведению «Принудительная остановка», поскольку это должно завершить все ваши процессы.