- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 229
 
Refactor PdfDownloader to use coroutines and OkHttp's async API #233
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| 
     | 
||
| plugins { | ||
| id("com.android.application") version "8.10.0" apply false | ||
| id("com.android.library") version "8.10.0" apply false | ||
| id("org.jetbrains.kotlin.android") version "2.1.20" apply false | ||
| id("org.jetbrains.kotlin.plugin.compose") version "2.1.20" apply false | ||
| id("com.android.application") version "8.12.1" apply false | ||
| id("com.android.library") version "8.12.1" apply false | ||
| id("org.jetbrains.kotlin.android") version "2.2.10" apply false | ||
| id("org.jetbrains.kotlin.plugin.compose") version "2.2.10" apply false | ||
| } | 
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 
          
            
          
           | 
    @@ -15,9 +15,13 @@ import android.view.LayoutInflater | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.view.WindowManager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.widget.FrameLayout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.widget.TextView | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.fragment.app.Fragment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.DefaultLifecycleObserver | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.Lifecycle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.LifecycleCoroutineScope | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.LifecycleObserver | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.LifecycleOwner | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.lifecycleScope | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.DefaultItemAnimator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.DividerItemDecoration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
          
            
          
           | 
    @@ -141,6 +145,60 @@ class PdfRendererView @JvmOverloads constructor( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )).start() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Initializes the PDF view with a remote URL. Downloads and renders the PDF. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param url The URL of the PDF file. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param headers Optional HTTP headers. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param lifecycleOwner The LifecycleOwner to bind the download lifecycle. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param cacheStrategy Cache strategy to apply. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun initWithUrl( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers: HeaderData = HeaderData(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lifecycleOwner: LifecycleOwner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cacheStrategy: CacheStrategy = CacheStrategy.MAXIMIZE_PERFORMANCE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onCreate(owner: LifecycleOwner) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onCreate(owner) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val lifecycleScope = lifecycleOwner.lifecycleScope | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [email protected] = cacheStrategy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PdfDownloader( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lifecycleScope, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cacheStrategy, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PdfDownloadCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onStart = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusListener?.onPdfLoadStart() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onProgress = { progress, current, total -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusListener?.onPdfLoadProgress(progress, current, total) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initWithFile(it, cacheStrategy) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusListener?.onPdfLoadSuccess(it.absolutePath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e: Exception) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusListener?.onError(e) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onError = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusListener?.onError(it) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )).start() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onDestroy(owner: LifecycleOwner) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onDestroy(owner) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lifecycleOwner.lifecycle.removeObserver(this) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
         
      Comment on lines
    
      +163
     to 
      +201
    
   
  
    
 | 
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { | |
| override fun onCreate(owner: LifecycleOwner) { | |
| super.onCreate(owner) | |
| val lifecycleScope = lifecycleOwner.lifecycleScope | |
| this@PdfRendererView.cacheStrategy = cacheStrategy | |
| PdfDownloader( | |
| lifecycleScope, | |
| headers, | |
| url, | |
| cacheStrategy, | |
| PdfDownloadCallback( | |
| context, | |
| onStart = { | |
| statusListener?.onPdfLoadStart() | |
| }, | |
| onProgress = { progress, current, total -> | |
| statusListener?.onPdfLoadProgress(progress, current, total) | |
| }, | |
| onSuccess = { | |
| try { | |
| initWithFile(it, cacheStrategy) | |
| statusListener?.onPdfLoadSuccess(it.absolutePath) | |
| } catch (e: Exception) { | |
| statusListener?.onError(e) | |
| } | |
| }, | |
| onError = { | |
| statusListener?.onError(it) | |
| } | |
| )).start() | |
| } | |
| override fun onDestroy(owner: LifecycleOwner) { | |
| super.onDestroy(owner) | |
| lifecycleOwner.lifecycle.removeObserver(this) | |
| } | |
| }) | |
| } | |
| val startDownload = { | |
| val lifecycleScope = lifecycleOwner.lifecycleScope | |
| this@PdfRendererView.cacheStrategy = cacheStrategy | |
| PdfDownloader( | |
| lifecycleScope, | |
| headers, | |
| url, | |
| cacheStrategy, | |
| PdfDownloadCallback( | |
| context, | |
| onStart = { | |
| statusListener?.onPdfLoadStart() | |
| }, | |
| onProgress = { progress, current, total -> | |
| statusListener?.onPdfLoadProgress(progress, current, total) | |
| }, | |
| onSuccess = { | |
| try { | |
| initWithFile(it, cacheStrategy) | |
| statusListener?.onPdfLoadSuccess(it.absolutePath) | |
| } catch (e: Exception) { | |
| statusListener?.onError(e) | |
| } | |
| }, | |
| onError = { | |
| statusListener?.onError(it) | |
| } | |
| )).start() | |
| } | |
| if (lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) { | |
| startDownload() | |
| } else { | |
| lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { | |
| override fun onCreate(owner: LifecycleOwner) { | |
| super.onCreate(owner) | |
| startDownload() | |
| } | |
| override fun onDestroy(owner: LifecycleOwner) { | |
| super.onDestroy(owner) | |
| lifecycleOwner.lifecycle.removeObserver(this) | |
| } | |
| }) | |
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -11,6 +11,8 @@ import android.os.ParcelFileDescriptor | |
| import android.provider.MediaStore | ||
| import android.util.Log | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.coroutineScope | ||
| import kotlinx.coroutines.ensureActive | ||
| import kotlinx.coroutines.withContext | ||
| import java.io.* | ||
| 
     | 
||
| 
          
            
          
           | 
    @@ -73,23 +75,25 @@ object FileUtils { | |
| ?.forEach { it.delete() } | ||
| } | ||
| 
     | 
||
| fun writeFile(inputStream: InputStream, file: File, totalLength: Long, onProgress: (Long) -> Unit) { | ||
| FileOutputStream(file).use { outputStream -> | ||
| val data = ByteArray(8192) | ||
| var totalBytesRead = 0L | ||
| var bytesRead: Int | ||
| while (inputStream.read(data).also { bytesRead = it } != -1) { | ||
| outputStream.write(data, 0, bytesRead) | ||
| totalBytesRead += bytesRead | ||
| try { | ||
| onProgress(totalBytesRead) | ||
| } catch (e: Exception) { | ||
| Log.w(TAG, "Progress callback failed: ${e.message}", e) | ||
| suspend fun writeFile(inputStream: InputStream, file: File, totalLength: Long, onProgress: (Long) -> Unit) = | ||
| coroutineScope { | ||
| 
         
      Comment on lines
    
      +78
     to 
      +79
    
   
  
    
 | 
||
| FileOutputStream(file).use { outputStream -> | ||
| val data = ByteArray(8192) | ||
| var totalBytesRead = 0L | ||
| var bytesRead: Int | ||
| while (inputStream.read(data).also { bytesRead = it } != -1) { | ||
| ensureActive() | ||
| outputStream.write(data, 0, bytesRead) | ||
| totalBytesRead += bytesRead | ||
| try { | ||
| onProgress(totalBytesRead) | ||
| } catch (e: Exception) { | ||
| Log.w(TAG, "Progress callback failed: ${e.message}", e) | ||
| } | ||
| } | ||
| outputStream.flush() | ||
| } | ||
| outputStream.flush() | ||
| } | ||
| } | ||
| 
     | 
||
| suspend fun isValidPdf(file: File?): Boolean = withContext(Dispatchers.IO) { | ||
| if (file == null || !file.exists() || file.length() < 4) { | ||
| 
          
            
          
           | 
    ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The download is started in onCreate, but this may execute multiple times if the lifecycle owner goes through multiple create/destroy cycles. The download should be started immediately when initWithUrl is called, not deferred to onCreate. Consider starting the download directly and using lifecycle observer only for cleanup.