You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin开发:如何从Activity加载Fragment并传递扫描得到的条码变量

解决Fragment加载与条码数据传递的方案

我来帮你一步步搞定这个问题,针对当前Android开发的最佳实践(避开弃用API),咱们分几个清晰的步骤来实现:

1. 完善ResultsFragment的实现

先把你的空白fragment_results.kt改成能接收并展示条码数据的Fragment,这里用静态newInstance方法传递参数是官方推荐的安全方式,能避免Fragment重建时参数丢失的问题:

package com.example.barcode
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.barcode.databinding.FragmentResultsBinding

class ResultsFragment : Fragment() {
    private lateinit var binding: FragmentResultsBinding
    
    // 定义传递参数的常量键,避免硬编码出错
    companion object {
        private const val ARG_BARCODE = "scanned_barcode"
        
        // 静态工厂方法:创建Fragment并传入条码参数
        fun newInstance(barcode: String): ResultsFragment {
            val fragment = ResultsFragment()
            val args = Bundle()
            args.putString(ARG_BARCODE, barcode)
            fragment.arguments = args
            return fragment
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentResultsBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 从Bundle中取出条码数据,后续可以扩展成加载关联数据的逻辑
        val scannedBarcode = arguments?.getString(ARG_BARCODE)
        scannedBarcode?.let {
            binding.barcodeDisplay.text = "扫描到的条码:$it"
            // 这里后续可以加请求电子表格数据的逻辑
        }
    }
}

对应的fragment_results.xml可以先加个测试用的TextView:

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

    <TextView
        android:id="@+id/barcodeDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:padding="16dp"/>

</LinearLayout>

2. 修改MainActivity,实现Fragment加载与参数传递

接下来调整你的MainActivity.kt,核心是添加按钮点击事件,把扫描到的条码传给Fragment,再执行Fragment事务:

package com.example.barcode
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.budiyev.android.codescanner.AutoFocusMode
import com.budiyev.android.codescanner.CodeScanner
import com.budiyev.android.codescanner.DecodeCallback
import com.budiyev.android.codescanner.ErrorCallback
import com.budiyev.android.codescanner.ScanMode
import com.example.barcode.databinding.ActivityMainBinding

private const val CAMERA_REQUEST_CODE = 101

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var codeScanner: CodeScanner
    // 新增变量:保存扫描到的条码
    private var scannedBarcode: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setupPermissions()
        codeScanner()
        // 新增:设置按钮点击逻辑
        setupSearchButton()
    }

    private fun codeScanner() {
        codeScanner = CodeScanner(this, binding.scannerView)
        codeScanner.apply {
            camera = CodeScanner.CAMERA_BACK
            formats = CodeScanner.ALL_FORMATS
            autoFocusMode = AutoFocusMode.SAFE
            scanMode = ScanMode.SINGLE
            isAutoFocusEnabled = true
            isFlashEnabled = false

            decodeCallback = DecodeCallback {
                // 扫描回调在子线程,必须切回主线程更新UI和保存数据
                runOnUiThread {
                    scannedBarcode = it.text
                    binding.button.text = getString(R.string.searchButtonLabel, it.text)
                }
            }

            errorCallback = ErrorCallback {
                Log.e("Main", "Camera Initilization failed ${it.message}")
            }
        }

        binding.scannerView.setOnClickListener {
            codeScanner.startPreview()
            binding.button.text = getString(R.string.resetButtonLabel)
            scannedBarcode = null // 重置条码
        }
    }

    // 新增:处理按钮点击,加载Fragment并传参
    private fun setupSearchButton() {
        binding.button.setOnClickListener {
            scannedBarcode?.let { barcode ->
                // 创建Fragment实例并传入条码
                val resultsFragment = ResultsFragment.newInstance(barcode)
                // 执行Fragment事务:替换容器中的内容
                supportFragmentManager.beginTransaction()
                    .replace(R.id.fragment_container, resultsFragment)
                    .addToBackStack(null) // 可选:添加到返回栈,点击返回键回到扫描界面
                    .commit()
            } ?: run {
                Toast.makeText(this, "请先扫描条码再点击", Toast.LENGTH_SHORT).show()
            }
        }
    }

    // 以下是你原有的权限和生命周期代码,无需修改
    override fun onResume() {
        super.onResume()
        codeScanner.startPreview()
    }

    override fun onPause() {
        codeScanner.releaseResources()
        super.onPause()
    }

    private fun setupPermissions() {
        val permission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
        if (permission != PackageManager.PERMISSION_GRANTED) {
            makeRequest()
        }
    }

    private fun makeRequest(){
        ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            CAMERA_REQUEST_CODE -> {
                if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this,"You need the camera for this app", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
}

最后要在你的activity_main.xml里加一个Fragment容器(FrameLayout),用来放置ResultsFragment:

<!-- 放在扫描视图和按钮的下方,调整布局权重让容器占满剩余空间 -->
<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"/>

3. 关键细节说明

  • 为什么用newInstance?:直接给Fragment构造函数传参数会在屏幕旋转等场景下丢失数据,用Bundle传递参数是系统认可的安全方式,Fragment重建时会自动恢复参数。
  • 主线程更新UI:扫描回调是在后台线程执行的,必须用runOnUiThread包裹UI更新操作,否则会触发崩溃。
  • Fragment事务:用supportFragmentManager是因为AppCompatActivity基于FragmentCompatActivity,replace会替换容器内的现有内容,addToBackStack能让用户通过返回键回到扫描界面,提升体验。

这样改完之后,你扫描条码点击按钮就能成功加载ResultsFragment并看到传递的条码了,后续可以在Fragment里扩展加载电子表格关联数据的逻辑。

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:59:15