Search code examples
androidkotlinandroid-fragmentszxing

Android Kotlin Get the Zxing Barcode Results in Fragment from Activity


Using Android Studio Kotlin, I'm using Zxing barcode scanner in my app. My app uses the fragment architecture. I am able to scan the barcode from my app from the fragment, but the scan result is returned to the activity. I believe intentionally since the signature requires the activity as input.

My question is, a) how can I get the scanned return value from the fragment call to execute onActivityResult in the fragment rather than in the activity? OR b) get the result received by the activity to be passed back to the fragment?

I'm using the following tutorial Barcode Scanning in Kotlin

The following java based post says to override the function, but that doesn't seem to actuall override the parent as the scanner function signature seems to refer to the activity.

Update note:

I changed the code to use a nav_graph. Without using the nav_graph, I was getting a fragment not found warning.

Log.d results showing the MainActivity function is called.

barcoderead D/MainActivity: Format: UPC_A
    Contents: 630509790043

Manifest addition

    <uses-feature android:name="android.hardware.camera.autoFocus" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

build.gradle (app) addition

    implementation 'com.google.zxing:core:3.3.3'
    implementation 'com.journeyapps:zxing-android-embedded:3.2.0'

MainActivity

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation
import com.google.android.gms.ads.MobileAds
import com.google.zxing.integration.android.IntentIntegrator
import com.lightningbraingames.mytoybox.R

class MainActivity : AppCompatActivity() {

    lateinit var btnBarcode: Button
    lateinit var textView: TextView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Navigation.findNavController(this,
            R.id.nav_host_fragment
        )

    }
}

Fragment

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.google.zxing.integration.android.IntentIntegrator

class BarcodeRead : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_barcode_read, container, false)
    }

    lateinit var btnBarcode: Button
    lateinit var textView: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        btnBarcode = view.findViewById(R.id.button)
        textView = view.findViewById(R.id.txtContent)
        btnBarcode.setOnClickListener {
            val intentIntegrator = IntentIntegrator(activity)
            intentIntegrator.setBeepEnabled(false)
            intentIntegrator.setCameraId(0)
            intentIntegrator.setPrompt("SCAN")
            intentIntegrator.setBarcodeImageEnabled(false)
            intentIntegrator.initiateScan()
        }
    }

    override fun onActivityResult(
        requestCode: Int,
        resultCode: Int,
        data: Intent?
    ) {
        val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
        if (result != null) {
            if (result.contents == null) {
                Toast.makeText(context, "cancelled", Toast.LENGTH_SHORT).show()
            } else {
                Log.d("Fragment", "Scanned from Fragment")
                Toast.makeText(context, "Scanned -> " + result.contents, Toast.LENGTH_SHORT)
                    .show()
                textView.text = String.format("Scanned Result: %s", result)
                Log.d("Fragment", "$result")
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

Layouts Main Activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/my_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"/>

</LinearLayout>

Fragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="4dp">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:padding="8dp"
        android:text="Tutorials Point"
        android:textColor="@android:color/holo_green_dark"
        android:textSize="48sp"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/txtContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/button"
        android:layout_centerInParent="true"
        android:layout_marginBottom="10dp"
        android:text=" code reader"
        android:textSize="16sp"
        android:textStyle="bold" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginTop="50dp"
        android:text="Process" />
</RelativeLayout>

Solution

  • If your problem is that your fragment does not get the results, maybe you are missing something from your Fragment based from ZXing Documentation:

    From you Activity it should

        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
        }
    

    From you fragment BarcodeRead

    //val intentIntegrator = IntentIntegrator(activity)
    val intentIntegrator = IntentIntegrator.forSupportFragment(this) // use this instead
    

    It is important to use IntentIntegrator.forSupportFragment() instead of IntentIntegrator(getActivity()) because if you use the latter, the results will be available only in the activity page.