Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

IllegalStateException после выхода из экрана проигрывания на главный экран #38

Closed
sadr0b0t opened this issue Oct 30, 2020 · 6 comments
Labels
bug Something isn't working

Comments

@sadr0b0t
Copy link
Owner

перенесу отсюда в отдельный тикет #36 (comment)

Дело было в эмуляторе. Вышел из крана проигрывания видео на главный экран и через некоторое время получил эксепшен

java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
        at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:1069)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:683)
        at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:378)
        at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
        at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:752)
        at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeUpdateDelete(FrameworkSQLiteStatement.java:46)
        at su.sadrobot.yashlang.model.VideoItemDao_Impl.countView(VideoItemDao_Impl.java:283)
        at su.sadrobot.yashlang.WatchVideoActivity$31.run(WatchVideoActivity.java:1270)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

тут явно видно, что это WatchVideoActivity, в текущей версии это вот эта строка:

private void playVideoItem(final VideoItem videoItem, final boolean resetCurrPos) {
[...]
            // теперь то, что в фоне
            videoLoadingExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    // посчитать просмотр (для ролика, загруженного из базы)
                    if (videoItem.getId() != -1) {
                        videodb.videoItemDao().countView(videoItem.getId());
                    }

                    loadVideoItem(videoItem);
                }
            });
[...]
}
videodb.videoItemDao().countView(videoItem.getId());

Перед этим начал добавлять на эмуляторе плейлист первого канала (довольно большой), всё тормозило, может быть, это тоже сыграло роль.

@sadr0b0t
Copy link
Owner Author

Еще аналогично вылетает в похожих ситуациях (выход из плеера на главный экран):

2020-11-20 23:20:01.598 18774-19041/su.sadrobot.yashlang D/SurfaceUtils: disconnecting from surface 0x7311bba010, reason disconnectFromSurface
2020-11-20 23:20:01.877 18774-18796/su.sadrobot.yashlang I/SQLiteConnectionPool: The connection pool for /data/user/0/su.sadrobot.yashlang/databases/video-db has been closed but there are still 1 connections in use.  They will be closed as they are released back to the pool.
2020-11-20 23:20:01.887 18774-18796/su.sadrobot.yashlang E/ROOM: Invalidation tracker is initialized twice :/.
    
    --------- beginning of crash
2020-11-20 23:20:01.940 18774-18796/su.sadrobot.yashlang E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0
    Process: su.sadrobot.yashlang, PID: 18774
    java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction.
        at android.database.sqlite.SQLiteSession.throwIfNoTransaction(SQLiteSession.java:915)
        at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:398)
        at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:524)
        at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.endTransaction(FrameworkSQLiteDatabase.java:90)
        at androidx.room.RoomDatabase.endTransaction(RoomDatabase.java:340)
        at androidx.room.paging.LimitOffsetDataSource.loadInitial(LimitOffsetDataSource.java:135)
        at androidx.paging.PositionalDataSource.dispatchLoadInitial(PositionalDataSource.java:286)
        at androidx.paging.TiledPagedList.<init>(TiledPagedList.java:107)
        at androidx.paging.PagedList.create(PagedList.java:229)
        at androidx.paging.PagedList$Builder.build(PagedList.java:388)
        at androidx.paging.LivePagedListBuilder$1.compute(LivePagedListBuilder.java:206)
        at androidx.paging.LivePagedListBuilder$1.compute(LivePagedListBuilder.java:171)
        at androidx.lifecycle.ComputableLiveData$2.run(ComputableLiveData.java:101)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)

здесь, правда, нет ссылки на исходник.

@sadr0b0t
Copy link
Owner Author

Воспроизводил эксепшен стопудово (на телефоне, не на эмуляторе):

Экран поиска > "ну, погоди" > "играть всё" > дождаться, пока видео загрузится > кнопка назад в заголовке > почти гарантированный вылет (эксепшен - последний вариант)

после этого коммита больше не воспроизводится:
c0e9a97

@sadr0b0t
Copy link
Owner Author

то же самое для всех экранов: 9556ed4

теперь стратегия работы с базой данных: создали подключение -> выполнили операцию -> закрыли подключение

Никаких "подключились в onCreate", отключились в onDestroy.

Аналогичным образом стоит пересмотреть код ContentLoader - во время длительных операций или операций, в процессе которых может вылететь эксепшен, лучше подключаться/отключать по несколько раз в процессе, чем в начале и конце операции, которая еще может быть оборвана посередине. Особенно касается вариантов с эксепшенами - базу данных будем закрывать каждый раз перед тем, как выполнять какую-то сетевую операцию.

@sadr0b0t
Copy link
Owner Author

проверил здесь: #36 (comment)

При закрытии активити вызывается метод onDestroy, при этом незавершившиеся фоновые потоки еще продолжают работать

Решение убрать глобальное подключение videodb, которое закрывается в onDestroy, совершенно правильное. При таком подходе ни в одном месте, где в фоновом потоке идет обращение к videodb (а оно всегда идет в фоновом потоке), нет никакой гарантии, что это подключение открыто.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Nov 21, 2020

Среди прочего - забыл исправить (убрать глобальный videodb) в ConfigurePlaylistNewItemsFragment.java
876f0da

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Dec 12, 2020

Решение убрать глобальное подключение videodb, которое закрывается в onDestroy, совершенно правильное. При таком подходе ни в одном месте, где в фоновом потоке идет обращение к videodb (а оно всегда идет в фоновом потоке), нет никакой гарантии, что это подключение открыто.

Так, да не так. В тех местах, где добавляю данные в базу или читаю из нее объекты, это ок. Но в тех местах, где из базы создаётся PagedListAdapter, закрытие по месту приводит к проблемам.

малые проблемы (перестали обновляться списки после записи в базу): #47 (comment)
большие проблемы: #33 #68

правильное решение будет использовать синглтон для базы данных - одно подключение на всё приложение, сделаю здесь: #68

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant