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
相关产品推荐
相关产品推荐

