i want to download a pdf file from FireStorage, render the file, add every page like ImageBitMap in a List and show in a LazyColumn. The problem is that it is very slow trying to scroll, even freezing 4-5 secs when page change.
Any ideas on how to make it more efficient and faster? Is there a library for JetPack Compose that I can use to make this better?
Thanks
PDFScreen.kt
@Composable
fun PDFScreen(obraId: ObraId, autorId: AuthorId) {
val storageRef = FirebaseStorage.getInstance().reference
val pathReference = storageRef.child("obras/${autorId}/${obraId}.pdf")
val localFile = File.createTempFile("obra", "pdf")
var imageList = remember { mutableStateListOf<ImageBitmap?>(null) }
pathReference.getFile(localFile).addOnSuccessListener {
imageList.clear()
if (it.task.isSuccessful) {
val input = ParcelFileDescriptor.open(localFile, ParcelFileDescriptor.MODE_READ_ONLY)
val renderer = PdfRenderer(input)
for (i in 0 until renderer.pageCount) {
val page = renderer.openPage(i)
val bitmap =
Bitmap.createBitmap(Constants.width, Constants.height, Bitmap.Config.ARGB_8888)
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
imageList.add(bitmap.asImageBitmap())
page.close()
}
renderer.close()
}
}
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items = imageList) { imagen ->
if (imagen != null) {
Image(
modifier = Modifier
.fillMaxSize(), bitmap = imagen, contentDescription = "Prueba"
)
}
}
}
}
CodePudding user response:
You should not make any heavy calculations or db/network calls directly from the composable functions.
All composite functions are view constructors and can be reconfigured (e.g., recalled) whenever the values of a changeable state change, and for animations - up to every frame. In your code, getFile
query is executed when a new item is added to the list of changeable states making an endless cycle.
I suggest you start with the state in compose documentation, including this youtube video which explains the basic principles.
In your case, the fething code should be moved to view model: The PDFScreenViewModel
object will be created when the view appears and destroyed when the view leaves the view hierarchy:
class PDFScreenViewModel: ViewModel() {
val imageList = mutableStateListOf<ImageBitmap?>(null)
private val storageRef = FirebaseStorage.getInstance().reference
private val pathReference = storageRef.child("obras/${autorId}/${obraId}.pdf")
private val localFile = File.createTempFile("obra", "pdf")
init {
load()
}
fun load() {
pathReference.getFile(localFile).addOnSuccessListener {
imageList.clear()
if (it.task.isSuccessful) {
val input = ParcelFileDescriptor.open(localFile, ParcelFileDescriptor.MODE_READ_ONLY)
val renderer = PdfRenderer(input)
for (i in 0 until renderer.pageCount) {
val page = renderer.openPage(i)
val bitmap =
Bitmap.createBitmap(Constants.width, Constants.height, Bitmap.Config.ARGB_8888)
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
imageList.add(bitmap.asImageBitmap())
page.close()
}
renderer.close()
}
}
}
}
@Composable
fun PDFScreen(obraId: ObraId, autorId: AuthorId) {
val viewModel: PDFScreenViewModel = viewModel()
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items = viewModel.imageList) { imagen ->
if (imagen != null) {
Image(
modifier = Modifier
.fillMaxSize(), bitmap = imagen, contentDescription = "Prueba"
)
}
}
}
}