Не удалось найти информацию о ContentProvider при сбое приложения с кодом ContentProvider

#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 где мне был нужен клиент с длительным сроком службы в течение достаточно долгого времени, поэтому я не тестировал этот сценарий. И обратите внимание, что это не поможет на тех устройствах, где экран обзора привязан к поведению «Принудительная остановка», поскольку это должно завершить все ваши процессы.