diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt index 255bfdda6..62c625042 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt @@ -54,9 +54,10 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) { suspend fun put(url: String, source: Source): File = withContext(Dispatchers.IO) { val file = File(cacheDir.get().parentFile, url.longHashCode().toString()) try { - file.sink(append = false).buffer().use { + val bytes = file.sink(append = false).buffer().use { it.writeAllCancellable(source) } + check(bytes != 0L) { "No data has been written" } lruCache.get().put(url, file) } finally { file.delete() diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt index a4ba27794..67127d854 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.reader.domain +import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri @@ -8,6 +9,7 @@ import androidx.collection.LongSparseArray import androidx.collection.set import dagger.hilt.android.ActivityRetainedLifecycle import dagger.hilt.android.lifecycle.RetainedLifecycle +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ActivityRetainedScoped import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers @@ -30,8 +32,10 @@ import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.await import org.koitharu.kotatsu.reader.ui.pager.ReaderPage +import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.RetainedLifecycleCoroutineScope import org.koitharu.kotatsu.utils.ext.printStackTraceDebug +import org.koitharu.kotatsu.utils.ext.ramAvailable import org.koitharu.kotatsu.utils.ext.withProgress import org.koitharu.kotatsu.utils.progress.ProgressDeferred import java.io.File @@ -44,9 +48,11 @@ import kotlin.coroutines.CoroutineContext private const val PROGRESS_UNDEFINED = -1f private const val PREFETCH_LIMIT_DEFAULT = 10 +private const val PREFETCH_MIN_RAM_MB = 80L @ActivityRetainedScoped class PageLoader @Inject constructor( + @ApplicationContext private val context: Context, lifecycle: ActivityRetainedLifecycle, private val okHttp: OkHttpClient, private val cache: PagesCache, @@ -75,7 +81,7 @@ class PageLoader @Inject constructor( } fun isPrefetchApplicable(): Boolean { - return repository is RemoteMangaRepository && settings.isPagesPreloadEnabled() + return repository is RemoteMangaRepository && settings.isPagesPreloadEnabled() && !isLowRam() } @AnyThread @@ -116,6 +122,9 @@ class PageLoader @Inject constructor( suspend fun convertInPlace(file: File) { convertLock.withLock { + if (context.ramAvailable < file.length() * 2) { + return@withLock + } runInterruptible(Dispatchers.Default) { val image = BitmapFactory.decodeFile(file.absolutePath) try { @@ -212,6 +221,10 @@ class PageLoader @Inject constructor( } } + private fun isLowRam(): Boolean { + return context.ramAvailable <= FileSize.MEGABYTES.convert(PREFETCH_MIN_RAM_MB, FileSize.BYTES) + } + private class InternalErrorHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt index 7a1872739..71d439811 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.utils.ext import android.app.Activity import android.app.ActivityManager +import android.app.ActivityManager.MemoryInfo import android.app.ActivityOptions import android.content.Context import android.content.Context.ACTIVITY_SERVICE @@ -138,6 +139,13 @@ fun isLowRamDevice(context: Context): Boolean { return context.activityManager?.isLowRamDevice ?: false } +val Context.ramAvailable: Long + get() { + val result = MemoryInfo() + activityManager?.getMemoryInfo(result) + return result.availMem + } + fun scaleUpActivityOptionsOf(view: View): ActivityOptions = ActivityOptions.makeScaleUpAnimation( view, 0,