Android - android.database.StaleDataException при уничтожении активности - PullRequest
0 голосов
/ 28 мая 2018

Я столкнулся с этим сбоем в моем приложении на данный момент только на двух устройствах, как Samsung Galaxy (SM-G950F [api 26] и Galaxy J7 [api 23]).
Я думаю, что это SamsungЭто очень важно, потому что со всеми остальными устройствами для тестирования, которые я использую (физические, LG [api 24] и эмуляторы Genymotion), этого никогда не было.

Это полная трассировка стека:

Fatal Exception: java.lang.RuntimeException: Unable to destroy activity {us.highlanders.app/rs.highlande.highlanders_app.activities_and_fragments.activities_create_post.CreatePostActivityMod}: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4603)
   at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4621)
   at android.app.ActivityThread.-wrap5(Unknown Source)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1757)
   at android.os.Handler.dispatchMessage(Handler.java:105)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:6938)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Caused by android.database.StaleDataException: Attempted to access a cursor after it has been closed.
   at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:63)
   at android.database.BulkCursorToCursorAdaptor.getCount(BulkCursorToCursorAdaptor.java:69)
   at android.database.CursorWrapper.getCount(CursorWrapper.java:60)
   at <MY-APP-PACKAGE>.adapters.CustomGalleryAdapter.getItemCount(CustomGalleryAdapter.java:111)
   at android.support.v7.widget.RecyclerView$LayoutManager.getColumnCountForAccessibility(RecyclerView.java:10131)
   at android.support.v7.widget.RecyclerView$LayoutManager.onInitializeAccessibilityNodeInfo(RecyclerView.java:9992)
   at android.support.v7.widget.RecyclerView$LayoutManager.onInitializeAccessibilityNodeInfo(RecyclerView.java:9951)
   at android.support.v7.widget.RecyclerViewAccessibilityDelegate.onInitializeAccessibilityNodeInfo(RecyclerViewAccessibilityDelegate.java:61)
   at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl$1.onInitializeAccessibilityNodeInfo(AccessibilityDelegateCompat.java:126)
   at android.view.View.onInitializeAccessibilityNodeInfo(View.java:7951)
   at android.view.View.createAccessibilityNodeInfoInternal(View.java:7912)
   at android.view.View$AccessibilityDelegate.createAccessibilityNodeInfo(View.java:27397)
   at android.view.View.createAccessibilityNodeInfo(View.java:7895)
   at android.view.accessibility.AccessibilityRecord.setSource(AccessibilityRecord.java:146)
   at android.view.accessibility.AccessibilityRecord.setSource(AccessibilityRecord.java:119)
   at android.view.View.onInitializeAccessibilityEventInternal(View.java:7849)
   at android.view.View$AccessibilityDelegate.onInitializeAccessibilityEvent(View.java:27280)
   at android.support.v4.view.AccessibilityDelegateCompat.onInitializeAccessibilityEvent(AccessibilityDelegateCompat.java:309)
   at android.support.v7.widget.RecyclerViewAccessibilityDelegate.onInitializeAccessibilityEvent(RecyclerViewAccessibilityDelegate.java:67)
   at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl$1.onInitializeAccessibilityEvent(AccessibilityDelegateCompat.java:120)
   at android.view.View.onInitializeAccessibilityEvent(View.java:7835)
   at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:7699)
   at android.view.View$AccessibilityDelegate.sendAccessibilityEventUnchecked(View.java:27219)
   at android.support.v4.view.AccessibilityDelegateCompat.sendAccessibilityEventUnchecked(AccessibilityDelegateCompat.java:248)
   at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl$1.sendAccessibilityEventUnchecked(AccessibilityDelegateCompat.java:148)
   at android.view.View.sendAccessibilityEventUnchecked(View.java:7682)
   at android.support.v7.widget.RecyclerView.sendAccessibilityEventUnchecked(RecyclerView.java:3421)
   at android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:27434)
   at android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:27467)
   at android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:11870)
   at android.view.View.onFocusChanged(View.java:7544)
   at android.view.View.clearFocusInternal(View.java:7404)
   at android.view.View.unFocus(View.java:7437)
   at android.view.ViewGroup.unFocus(ViewGroup.java:1084)
   at android.view.ViewGroup.unFocus(ViewGroup.java:1086)
   at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5416)
   at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5403)
   at android.view.ViewGroup.removeView(ViewGroup.java:5334)
   at android.support.v4.view.ViewPager.removeView(ViewPager.java:1501)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1529)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:3235)
   at android.support.v4.app.FragmentController.dispatchDestroy(FragmentController.java:265)
   at android.support.v4.app.FragmentActivity.onDestroy(FragmentActivity.java:390)
   at android.support.v7.app.AppCompatActivity.onDestroy(AppCompatActivity.java:209)
   at <MY-APP-PACKAGE>.HLActivity.onDestroy(HLActivity.java:164)
   at <MY-APP-PACKAGE>.CreatePostActivityMod.onDestroy(CreatePostActivityMod.java:95)
   at android.app.Activity.performDestroy(Activity.java:7462)
   at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1255)
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4590)
   at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4621)
   at android.app.ActivityThread.-wrap5(Unknown Source)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1757)
   at android.os.Handler.dispatchMessage(Handler.java:105)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:6938)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Что я в основном имею здесь, это действие, состоящее из ViewPager, закрепленного в нижней части экрана, где первый фрагмент представляет собойRecyclerView с горизонтальным LayoutManager, который хочет имитировать картинную галерею Telegram / Messenger.Все обрабатывается классом CustomGalleryAdapter (расширение RecyclerView.Adapter), который использует Cursor для извлечения файлов мультимедиа с устройства и который вылетает, когда по причинам доступности во время уничтоженияАктивность, на курсор снова ссылаются.Это действие создается в ожидании его результата, поэтому, когда я закончу, я вызываю finish(), как обычно, чтобы передать результат.

Фрагмент с RecyclerView прослушивает обратные вызовы Loader:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    String[] projection = {
            MediaStore.Files.FileColumns._ID,
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MEDIA_TYPE
    };
    String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
            + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
            + " OR "
            + MediaStore.Files.FileColumns.MEDIA_TYPE + "="
            + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
    String sortOrder = String.format("%s limit 50 ", MediaStore.Files.FileColumns.DATE_ADDED +" DESC");

    if (getActivity() != null) {
        return new CursorLoader(
                getActivity(),
                MediaStore.Files.getContentUri("external"),
                projection,
                selection,
                null,
                sortOrder
        );
    }
    else return null;
}

@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
    galleryAdapter.changeCursor(data);
}

@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
    galleryAdapter.changeCursor(null);
}`  

И смотрит на исходный код платформы, который возвращает мой курсор, когда он уже закрыт:

public int getColumnCountForAccessibility(Recycler recycler, State state) {
        if (mRecyclerView == null || mRecyclerView.mAdapter == null) {
            return 1;
        }
        return canScrollHorizontally() ? mRecyclerView.mAdapter.getItemCount() : 1;
    }  

, который вызывает getItemCount() метод:

@Override
public int getItemCount() {
    return (myCursor == null) ? 0 : myCursor.getCount();
}  

Я думал, что мог бы установить для поля mAdapter значение null в onDestroyView() методе фрагмента:

@Override
public void onDestroyView() {
    super.onDestroyView();

    if (galleryRecView != null)
        galleryRecView.setAdapter(null);
    galleryAdapter = null;
}  

длярешить вопрос.Но приложение продолжало падать, когда я пытался провести тестирование в Samsung Test Lab .

Но очень странно то, что я пытался отлаживать на своих устройствах эти линии доступности даже не были пойманы точками останова ...

У кого-нибудь есть предложения?

1 Ответ

0 голосов
/ 03 августа 2018

Попробуйте следующий обходной путь:

@Override
public int getItemCount() {
    return (myCursor == null || myCursor.isClosed()) ? 0 : myCursor.getCount();
}  
...