0

I am trying to capture images in my Android App using camera and show it in a list using RecyclerView

But because the images are quite heavy in size (6-7 MB each) and my list is can contains approx 8-9 images, I can see this in my logs:-

06-08 17:22:44.318 14283 14283 I Choreographer: Skipped 40 frames!  The application may be doing too much work on its main thread.

And it's not just about the logs. I can even see that when I am trying to capture the image with camera in the foreground, sometimes(frequency : 30%) my application is getting killed and automatically recreated. Because of this, I am losing my images that were earlier captured.

This is my code to capture the image written in my SampleFragment.kt:-

fun onBtnTakePicture() {
        val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        outputFileName = "${System.currentTimeMillis()}.jpg"
        val photo = File(context!!.filesDir, outputFileName)
        val outputFileUri = FileProvider.getUriForFile(context!!, AUTHORITY_APP_FILES,photo)
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri)
        cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
        startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE)
    }

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(resultCode == AppCompatActivity.RESULT_OK){
            if(requestCode == CAMERA_REQUEST_CODE){
                    //To add to db, we need to add this in view model
                    transactionViewModel.addImagePathInList(outputFileName)

                    //to show in the UI, we need to add it into this list
                    myCardsList.add(FeatureCarouselCardData(outputFileName))

                    featureCardsView.notifyAdapaterAboutDataSetChange()
            }
        }
    }

private lateinit var featureCardsView: FeatureCarouselView

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
..........
..........
featureCardsView = binding.featureCardsView
featureCardsView.showFeatureCarouselCards(myCardsList)
..........
..........
}

Adapter object is created in my class extending the RecyclerView : FeatureCarouselView.kt

fun showFeatureCarouselCards(featureCarouselCards: List<FeatureCarouselCardData>){
        this.featureCarouselCards = featureCarouselCards

        featureCarouselAdapter = FeatureCarouselAdapter(context, featureCarouselCards)
        adapter = featureCarouselAdapter

    }

This is the onBindViewHolder function in my FeatureCarouselAdapter.kt class

override fun onBindViewHolder(holder: FeatureCarouselViewHolder, position: Int) {
        val currentItem = featureCarouselCards[position]
        var bitmap = mContext.resources.getDrawable(R.drawable.ic_file_not_found).toBitmap()
        Log.d(LOG_TAG, "currentItem in onBindViewHolder : "+currentItem)
        try {
            Log.d(LOG_TAG, "try")
            val photo = File(mContext.filesDir, currentItem.fileName)
            val outputFileUri = FileProvider.getUriForFile(mContext, AUTHORITY_APP_FILES,photo)
            bitmap = MediaStore.Images.Media.getBitmap(mContext.contentResolver, outputFileUri)
        }catch (e: FileNotFoundException) {
            Log.d(LOG_TAG, "catch filenotfound")
            e.printStackTrace()
        } catch (e: IOException) {
            Log.d(LOG_TAG, "catch ioexception")
            e.printStackTrace()
        }
        holder.imageView.setImageBitmap(bitmap)
    }

While I know that there are some tools that can be used to load images alternatively and efficiently like Picasso or Glide. But these needs INTERNET permissions to be added in the Manifest file.

I want to keep my app offline only. So want to avoid this.

How can I achieve this?

Update

I even tried using loading images using Glide:-

Glide.with(mContext)
                .load(outputFileUri)
                .into(holder.imageView)

But still, I am facing the same problem. So, what could be the possible root cause for my issue?

Rohit Singla
  • 112
  • 2
  • 9
  • You can use `remove` node in `AndroidManifest` to not add Internet permission in the final apk. With these libraries, you can easily use a low quality images (thumbnails) and still keep the recyclerview performance. – Darshan Jun 08 '23 at 14:23
  • @Darshan thanks for your response. But I tried using Glide as well. It didn't help and my problem is same. – Rohit Singla Jun 08 '23 at 14:31
  • Can you try using `.override(size)`? Play around with the size values to handle image quality. – Darshan Jun 08 '23 at 14:34
  • @Darshan I have tried this as well. This is also not working. I can see that when Camera Activity is launched for result, in the background my app's activity is getting killed. So, I don't think that it's an image inflation issue. – Rohit Singla Jun 08 '23 at 15:25
  • `Because of this, I am losing my images that were earlier captured.` Not possible. Those are image files. And those files will not be deleted if your activity finishes. Its quite normal that your activity gets killed if it is not the top one. That you learned at lesson one Android programming. Your code should expect that. Further you will not get that message if you handle your images not in the main thread. – blackapps Jun 08 '23 at 16:45
  • @blackapps by losing images, I mean the references that I created within my code (say a list of file paths). Those are getting lost because application is getting recreated. But, I will have to do this on the main thread only right? ```holder.imageView.setImageBitmap(bitmap)``` – Rohit Singla Jun 08 '23 at 23:43

0 Answers0