Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ограничить количество потоков для загрузки иконок при пролистывании списков видео #17

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

Comments

@sadr0b0t
Copy link
Owner

sadr0b0t commented Oct 3, 2020

  • Использовать ThreadPool с ограниченным количеством потоков
  • Возможно, политика исполнения заданий - стек, а не очередь: выполнять в первую очередь те потоки, которые были добавлены последними (т.к. если мы быстро проматываем список вниз или в бок, первые на загрузку отправляются те иконки, которые мы уже давно пролистнули и в том месте, до которого долистали иконки не прогрузятся до тех пор, пока не будут загружены иконки с давно простнутых страниц)

Обоснование:

  • Должно существенно увеличить отзывчивость главного экрана и прочих списков видео (вообще, там почти на всех экранах списки) на медленных соединениях
  • Также отзывчивость на плейлистах с большим количеством удаленных видео (Союзмультфильм заблокировал все старые советские мультики - более 1 тыс видео).

Попытка промотать плейлист Союмультфильма с удаленными видео приводит к вылету приложения.

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

При этом обратить внимание: на раннем этапе разработки я уже реализовал загрузку иконок через ThreadPool (ровно то, что написано в тикете) и это привело к тому, что иконки появлялись в списках заметно медленнее, чем при создании неограниченного количества фоновых потоков. На тот момент я решил эту фичу удалить, в старых версиях код не сохранился. Но, возможно, ее следовало аккуратнее настроить (например, задать достаточно большое, но разумное количество фоновых потоков - по крайней мере, они не будут постоянно пересоздаваться, и/или, как написано выше, поиграть с порядком отправки ожадающих заданий на выполнение).

@sadr0b0t sadr0b0t added the bug Something isn't working label Oct 3, 2020
@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

Добавил ThreadPool в VideoItemPagedListAdapter.

Плейлист Союзмультфильм с 1000 удаленных видео при быстрой прокрутке вниз с ограничением в 100 потоков вылетает вот так:

20-10-03 22:27:53.383 30619-30875/su.sadrobot.yashlang W/System.err: java.io.FileNotFoundException: https://i.ytimg.com/vi/wBLAdBErMKY/hqdefault.jpg?sqp=-oaymwEiCMQBEG5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLC4IgpuZfm0oHVsBMucVp4s_Rva_Q
2020-10-03 22:27:53.383 30619-30875/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:251)
2020-10-03 22:27:53.384 30619-30875/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
2020-10-03 22:27:53.384 30619-30875/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(Unknown Source:0)
2020-10-03 22:27:53.384 30619-30875/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.controller.VideoThumbManager.loadBitmap(VideoThumbManager.java:68)
2020-10-03 22:27:53.388 30619-30875/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.controller.VideoThumbManager.loadVideoThumb(VideoThumbManager.java:117)
2020-10-03 22:27:53.388 30619-30875/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$3.run(VideoItemPagedListAdapter.java:200)
2020-10-03 22:27:53.388 30619-30875/su.sadrobot.yashlang W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
2020-10-03 22:27:53.388 30619-30875/su.sadrobot.yashlang W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
2020-10-03 22:27:53.388 30619-30875/su.sadrobot.yashlang W/System.err:     at java.lang.Thread.run(Thread.java:764)
2020-10-03 22:27:53.396 30619-31027/su.sadrobot.yashlang E/SQLiteLog: (14) cannot open file at line 35652 of [4bb21d8205]
2020-10-03 22:27:53.396 30619-31027/su.sadrobot.yashlang E/SQLiteLog: (14) os_unix.c:35652: (24) open(/data/user/0/su.sadrobot.yashlang/databases/video-db-wal) - 
2020-10-03 22:27:53.397 30619-31027/su.sadrobot.yashlang E/SQLiteLog: (14) unable to open database file
2020-10-03 22:27:53.399 30619-30619/su.sadrobot.yashlang W/zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files
2020-10-03 22:27:53.400 30619-30737/su.sadrobot.yashlang E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2020-10-03 22:27:53.409 30619-31028/su.sadrobot.yashlang E/CursorWindow: Could not allocate CursorWindow '/data/user/0/su.sadrobot.yashlang/databases/video-db' of size 2097152 due to error -24.
    
    --------- beginning of crash
2020-10-03 22:27:53.418 30619-31027/su.sadrobot.yashlang E/AndroidRuntime: FATAL EXCEPTION: Thread-212
    Process: su.sadrobot.yashlang, PID: 30619
    android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:291)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.tryAcquireNonPrimaryConnectionLocked(SQLiteConnectionPool.java:899)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:609)
        at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
        at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
        at android.database.sqlite.SQLiteSession.executeForLong(SQLiteSession.java:650)
        at android.database.sqlite.SQLiteStatement.simpleQueryForLong(SQLiteStatement.java:107)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:842)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:830)
        at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:866)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:272)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:194)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:452)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:275)
        at su.sadrobot.yashlang.model.PlaylistInfoDao_Impl.getById(PlaylistInfoDao_Impl.java:177)
        at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$2.run(VideoItemPagedListAdapter.java:166)
        at java.lang.Thread.run(Thread.java:764)
2020-10-03 22:27:53.419 30619-30619/su.sadrobot.yashlang W/zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files
2020-10-03 22:27:53.420 30619-31029/su.sadrobot.yashlang E/SQLiteLog: (14) cannot open file at line 35652 of [4bb21d8205]
2020-10-03 22:27:53.420 30619-31029/su.sadrobot.yashlang E/SQLiteLog: (14) os_unix.c:35652: (24) open(/data/user/0/su.sadrobot.yashlang/databases/video-db-wal) - 
2020-10-03 22:27:53.420 30619-31029/su.sadrobot.yashlang E/SQLiteLog: (14) unable to open database file
2020-10-03 22:27:53.426 30619-31028/su.sadrobot.yashlang E/AndroidRuntime: FATAL EXCEPTION: Thread-213
    Process: su.sadrobot.yashlang, PID: 30619
    android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. 
        at android.database.CursorWindow.<init>(CursorWindow.java:108)
        at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:140)
        at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:134)
        at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:219)
        at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:264)
        at androidx.room.RoomOpenHelper.hasRoomMasterTable(RoomOpenHelper.java:159)
        at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:127)
        at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:119)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:142)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:310)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:194)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:452)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:275)
        at su.sadrobot.yashlang.model.PlaylistInfoDao_Impl.getById(PlaylistInfoDao_Impl.java:177)
        at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$2.run(VideoItemPagedListAdapter.java:166)
        at java.lang.Thread.run(Thread.java:764)
2020-10-03 22:27:53.434 30619-31031/su.sadrobot.yashlang E/SQLiteLog: (14) cannot open file at line 35652 of [4bb21d8205]
2020-10-03 22:27:53.434 30619-31031/su.sadrobot.yashlang E/SQLiteLog: (14) os_unix.c:35652: (24) open(/data/user/0/su.sadrobot.yashlang/databases/video-db-wal) - 
2020-10-03 22:27:53.434 30619-31031/su.sadrobot.yashlang E/SQLiteLog: (14) unable to open database file
2020-10-03 22:27:53.435 30619-31030/su.sadrobot.yashlang E/SQLiteLog: (14) cannot open file at line 35652 of [4bb21d8205]
2020-10-03 22:27:53.435 30619-31030/su.sadrobot.yashlang E/SQLiteLog: (14) os_unix.c:35652: (24) open(/data/user/0/su.sadrobot.yashlang/databases/video-db-wal) - 
2020-10-03 22:27:53.435 30619-31030/su.sadrobot.yashlang E/SQLiteLog: (14) unable to open database file
2020-10-03 22:27:53.435 30619-31031/su.sadrobot.yashlang E/SQLiteDatabase: Failed to open database '/data/user/0/su.sadrobot.yashlang/databases/video-db'.
    android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:291)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
        at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:733)
        at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:309)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:254)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:194)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:452)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:275)
        at su.sadrobot.yashlang.model.PlaylistInfoDao_Impl.getById(PlaylistInfoDao_Impl.java:177)
        at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$2.run(VideoItemPagedListAdapter.java:166)
        at java.lang.Thread.run(Thread.java:764)
2020-10-03 22:27:53.438 30619-30619/su.sadrobot.yashlang W/zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files
2020-10-03 22:27:53.446 30619-30764/su.sadrobot.yashlang E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2020-10-03 22:27:53.449 30619-31029/su.sadrobot.yashlang E/AndroidRuntime: FATAL EXCEPTION: Thread-214
    Process: su.sadrobot.yashlang, PID: 30619
    android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:291)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.tryAcquireNonPrimaryConnectionLocked(SQLiteConnectionPool.java:899)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:609)
        at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
        at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
        at android.database.sqlite.SQLiteSession.executeForLong(SQLiteSession.java:650)
        at android.database.sqlite.SQLiteStatement.simpleQueryForLong(SQLiteStatement.java:107)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:842)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:830)
        at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:866)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:272)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:194)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:452)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:275)
        at su.sadrobot.yashlang.model.PlaylistInfoDao_Impl.getById(PlaylistInfoDao_Impl.java:177)
        at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$2.run(VideoItemPagedListAdapter.java:166)
        at java.lang.Thread.run(Thread.java:764)
2020-10-03 22:27:53.454 30619-30737/su.sadrobot.yashlang W/System.err: javax.net.ssl.SSLException: Unable to create application data
2020-10-03 22:27:53.465 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.org.conscrypt.NativeCrypto.SSL_new(Native Method)
2020-10-03 22:27:53.465 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:298)
2020-10-03 22:27:53.465 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:192)
2020-10-03 22:27:53.467 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
2020-10-03 22:27:53.468 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
2020-10-03 22:27:53.468 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
2020-10-03 22:27:53.468 30619-30737/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)

С ограничением в 1 поток не вылетает вообще. С огранинием в 10 потоков вылетает довольно быстро (но не так быстро, как со 100), с ограничением в 5 потоков почти не вылетает, но если долго мотать вниз, то всё равно вылетает.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

Убрал (временно) обращение в сеть для загрузки изображения, плейлист с ограничением в 100 потоков не вылетает, хотя заметны тормоза при скоростной прокрутке вниз (один раз все-таки вылетел).

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

Добавил запуск потоков через Executors.newFixedThreadPool, выставил ограничение 10 потоков: на главной странице заметного замедления загрузки иконок (как в случае с 1-м потоком) нет: 6d67146

Плейлист с удаленными на сервере роликами (Союзмультфильм) прокручивается дальше если не сильно торопиться, хотя все равно вылетает.

Пусть будет пока так.

Еще поправил освобождение ресурсов при загрузке картинок: 4b54211

субъективно плейлист Союзмультфильм стал тормозить поменьше, но это не точно.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

Возможно, кстати, дело в одновременном обращении к базе данных (вылет сопровождается SQLiteException), они там тоже в фоновых потоках, их тоже можно поместить в ThreadPool'ы.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

Оборачивание обращений к базе данных в ThreadPool не помогло, всё равно вылетает вот так, даже с ограничением на 1 поток:

2020-10-04 01:52:50.677 12795-12879/su.sadrobot.yashlang E/SQLiteLog: (14) cannot open file at line 35652 of [4bb21d8205]
2020-10-04 01:52:50.678 12795-12879/su.sadrobot.yashlang E/SQLiteLog: (14) os_unix.c:35652: (24) open(/data/user/0/su.sadrobot.yashlang/databases/video-db-wal) - 
2020-10-04 01:52:50.678 12795-12879/su.sadrobot.yashlang E/SQLiteLog: (14) unable to open database file
2020-10-04 01:52:50.680 12795-12879/su.sadrobot.yashlang E/AndroidRuntime: FATAL EXCEPTION: pool-4-thread-1
    Process: su.sadrobot.yashlang, PID: 12795
    android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:291)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.tryAcquireNonPrimaryConnectionLocked(SQLiteConnectionPool.java:899)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:609)
        at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
        at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
        at android.database.sqlite.SQLiteSession.executeForLong(SQLiteSession.java:650)
        at android.database.sqlite.SQLiteStatement.simpleQueryForLong(SQLiteStatement.java:107)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:842)
        at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:830)
        at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:866)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:272)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:194)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:452)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:275)
        at su.sadrobot.yashlang.model.PlaylistInfoDao_Impl.getById(PlaylistInfoDao_Impl.java:177)
        at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$2.run(VideoItemPagedListAdapter.java:167)
        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)
2020-10-04 01:52:50.714 12795-12927/su.sadrobot.yashlang W/zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files
2020-10-04 01:52:50.720 12795-12923/su.sadrobot.yashlang E/CursorWindow: Could not allocate CursorWindow '/data/user/0/su.sadrobot.yashlang/databases/video-db' of size 2097152 due to error -24.
2020-10-04 01:52:50.721 12795-12923/su.sadrobot.yashlang W/zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 3, 2020

  1. Вылетает плейлист Союзмультфильм, но не список рекомендаций на главной странице. На экране с плейлистом есть обращение к базе данных (запрос плейлиста для каждого ролика), а на главном экране - нет. По-хорошему, здесь нужно подключение к базе кэшировать, а не открывать/закрывать соединение при каждом запросе.

Но странно:

  1. Почему-то при быстрой прокрутке вниз не вылетают другие плейлисты, в которых тоже идет обращение в базе данных, но при этом ролики на сервере не удалены, поэтому картинки удачно загружаются одна за одной.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 4, 2020

Решение проблемы: 23a309e

Если на сервере нет файла с иконкой (connection.getInputStream() выбрасывает FileNotFound и input получается null), то нужно не только закрывать подключение connection.disconnect(), но и закрывать поток connection.getErrorStream().close(), даже если мы к нему не обращались вообще.

Если это не делать, то:

  1. Без него будет регулярно сыпаться ворнинг при прокрутке роликов в разных списках:
    2020-10-03 22:14:23.911 27270-27314/su.sadrobot.yashlang W/OkHttpClient: A connection to https://i.ytimg.com/ was leaked. Did you forget to close a response body?

  2. Хуже того, приложение может вылететь при быстрой прокрутке списка с большим количеством роликов, для которых удалены аналоги на сервере (иконка недоступна на сервере), если в этом же списке происходит обращение к б/д - вылетает ошибка:

SQLiteCantOpenDatabaseException: unable to open database file

Эксепшен (пойманный) при отсутствующей иконке на сервере выглядит вот так:

2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err: java.io.FileNotFoundException: https://i.ytimg.com/vi/C1PlT_7fA78/hqdefault.jpg?sqp=-oaymwElCMQBEG5IWvKriqkDGAgBFQAAAAAYASUAAMhCPQCAokN4AYABAQ==&rs=AOn4CLCQyfxuWF82p7KTW1hfdAKh4VpL1w
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:251)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(Unknown Source:0)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.controller.VideoThumbManager.loadBitmap(VideoThumbManager.java:72)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.controller.VideoThumbManager.loadVideoThumb(VideoThumbManager.java:137)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at su.sadrobot.yashlang.view.VideoItemPagedListAdapter$3.run(VideoItemPagedListAdapter.java:201)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
2020-10-04 15:32:31.660 8088-8200/su.sadrobot.yashlang W/System.err:     at java.lang.Thread.run(Thread.java:764)

Две проблемы одним исправлением. Вероятно, открытые стримы connection.getErrorStream() резервируют какие-то ресурсы (например, что-то вроде дескрипторов открытых файлов) так, что их перестаёт хватать на доступ к файлу базы данных. В списке с большим количеством отсутствующих иконок при быстрой прокрутке ресурс быстро исчерпывается и вылетает непойманная ошибка при очередном обращении к базе данных.

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

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented Oct 4, 2020

Возможно, кстати, дело в одновременном обращении к базе данных (вылет сопровождается SQLiteException), они там тоже в фоновых потоках, их тоже можно поместить в ThreadPool'ы.

здесь (хотя это и не было причино описанных выше проблем): 7bdc1b8

Возможно, политика исполнения заданий - стек, а не очередь: выполнять в первую очередь те потоки, которые были добавлены последними (т.к. если мы быстро проматываем список вниз или в бок, первые на загрузку отправляются те иконки, которые мы уже давно пролистнули и в том месте, до которого долистали иконки не прогрузятся до тех пор, пока не будут загружены иконки с давно простнутых страниц)

вот это реализовано: 71a4cf2

Эффект заметен сразу при быстрой прокрутке любого длинного списка - иконки появляются сразу, а не появляются через время (после того, как прогрузятся иконки из уже прокрученных областей списка).

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

No branches or pull requests

1 participant