Search code examples
androidkotlinandroid-recyclerviewfragmentandroid-camera

How to capture photo from recyclerView in Android - Kotlin language


I have simple task. In recyclerView when I click on any button I would like to start camera, take photo and then capture this photo. However I'm not able to find any solution for this. What I tried in RecyclerAdapter.kt:

  inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
        var textView1: TextView = itemView.findViewById(R.id.firma_textView1)

        init {
            textView1.setOnClickListener {
                capturePhoto(context, activity)
            }
        }
    }

    fun capturePhoto(context: Context, activity: Activity) {
        if (getCameraPermission(context)) {
            val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            startActivityForResult(activity, cameraIntent, FirstFragment.CAMERA_REQUEST_CODE, null)
        } else {
            ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), FirstFragment.CAMERA_REQUEST_CODE)
        }
    }

    private fun getCameraPermission (context: Context):Boolean {
        return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
    }

With this code I could start camera, take picture, but in RecyclerAdapter there is no way how to capture taken image.

Normal way how to capture image in Fragment is this:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        var buttonCapturePhoto = view.findViewById<Button>(R.id.button)
        buttonCapturePhoto.setOnClickListener {
            capturePhoto()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == CAMERA_REQUEST_CODE) {
            print("photo captured")
        }
    }

    private fun capturePhoto() {
        if (getCameraPermission(requireContext())) {
            val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE)
        } else {
            ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
        }
    }

    private fun getCameraPermission (context: Context):Boolean {
        return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
    }

I also found this article at Android Developer page - https://developer.android.com/training/basics/intents/result

They suggest to create class MyLifecycleObserver and use it in Fragment, but I'm not able to use this code in RecycleAdapter

lateinit var observer : MyLifecycleObserver

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        observer = MyLifecycleObserver(requireActivity().activityResultRegistry)
        lifecycle.addObserver(observer)
    }

I get error at activityResultRegistry and at lifecycle

I also created for testing this git repository: https://github.com/Katzzer/recyclerViewPhotoCaptureKotlinAndroid


Solution

  • You should pass your click event to fragment/activity

    1. Create custom interface inside your adapter
    2. Pass it into adapter constructor
    
    // pass listener into constructor
    class RecyclerAdapter(
      val list:List<YourItemClass>,
      val listener: OnItemClickListener) : ... {
      
      // create a custom listener
      interface OnItemClickListener{
        fun onItemClick(view:View, position:Int)
       }
      
      inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
    
            // create function bind instead of using init block
            fun bind(item:YourItemClass){
                val textView1: TextView = itemView.findViewById(R.id.firma_textView1)
                // if you want to change image in your ImageView , you could also pass 
                // your ImageView too
                val imgView: ImageView = itemView.findViewById(R.id.imgView)
                textView1.setOnClickListener { view ->
                    // this is just an example , but you get the idea
    
                    // listen click event and pass view and position
                    listener.onItemClick(view, adapterPosition)
                    // or
                    listener.onItemClick(imgView, adapterPosition)
                }
            }
        }
    
       ...
       override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val item = list[position]
            // bind here
            holder.bind(item)
        }
      ...
    }
    
    
    1. Initialized your adapter in Fragment/Activity
    2. Listen to click event in Fragment/Activity
    ...
    adapter = RecyclerAdapter(list, object : RecyclerAdapter.OnItemClickListener{
       override fun onItemClick(view:View, position:Int){
         // Listen your click event here
         capturePhoto().also { result ->
             // do something
    
             // dont forget to call notifyItem if you want to update an item in 
             // RecyclerView
             adapter.notifyItemChanged(position)
          }
       }
    }
    recyclerView.adapter = adapter
    ...
    
    1. Create your capturePhoto function in Fragment\Activity