如何将 ViewModel 添加到使用 ViewPager 和 Tablayout 的项目中?

How to add ViewModel to a project which uses ViewPager and Tablayout?

你好,我是 Android 开发的新手,所以这个问题对你来说可能很奇怪。

我有一个名为 IdentityCardInfo 的 class,它有变量。我在 InfoFragment.

中得到这个变量

从 InfoFragment 我想在 ResultsFragment 中显示这些变量,其中有 3 个带有 tablayout 的选项卡。

我想使用 ViewModel 将数据传递给 tablayouts 但我不知道如何使用我已经搜索过但卡住了。

这是 IdentityCardInfo 的代码 class:

class IdentityCardInfo {

    companion object AppConstant{
        const val serieNo ="67G74444"
        const val validDate = "01/01/2022"
        const val dateOfBirth = "10/08/1998"
        const val fullName = "Muhittin KAYA"
        const val identityNo: Long = 11111111111
        const val gender = "MALE"
        const val nationality = "TUR"
    }
}

这是 InfoFragment 的代码:

class InfoFragment : BaseFragment() {

    lateinit var navController: NavController

    companion object {
        private const val TAG = "Info Fragment"
    }

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        navController = Navigation.findNavController(view)
        button_info_idcard.setOnClickListener {
            //start OcrActivity
            val intent = Intent(activity, OcrActivity::class.java)
            startActivityForResult(intent, 101)
        }

        imagebutton_info_settings.setOnClickListener {
            navController.navigate(R.id.action_infoFragment_to_settingsFragment)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.i("Muhittin", "onActivityResult()")

        if (requestCode == 101) {
            val message = data?.getStringExtra("TEST_TEXT")
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()

            val serieNo = IdentityCardInfo.serieNo
            val validDate = IdentityCardInfo.validDate
            val dateOfBirth = IdentityCardInfo.dateOfBirth
            val fullname = IdentityCardInfo.fullName
            val gender = IdentityCardInfo.gender
            val identityNo = IdentityCardInfo.identityNo
            val nationality = IdentityCardInfo.nationality

            val bundle = bundleOf(
                "TEST_TEXT" to message,
                "SERIE_NO" to serieNo,
                "VALID_DATE" to validDate,
                "DOB" to dateOfBirth,
                "FULL_NAME" to fullname,
                "GENDER" to gender,
                "IDENTITY_NO" to identityNo,
                "NATIONALITY" to nationality
            )
            navController.navigate(
                R.id.action_infoFragment_to_detailFragment,
                bundle
            )
        }
    }
}

这是针对 ResultsFragment 的:(我没有添加 tablayout 代码和 viewpager 代码)

class ResultsFragment : Fragment() {

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

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)

        tabLayout.tabGravity = TabLayout.GRAVITY_FILL
        val tabTitles = arrayOf(
            resources.getString(R.string.result_tab1_name),
            resources.getString(R.string.result_tab2_name),
            resources.getString(R.string.result_tab3_name)
        )

        val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
        viewPager.offscreenPageLimit = 3
        val adapter = PagerAdapter(fragmentManager, tabTitles)
        viewPager.adapter = adapter
        tabLayout.setupWithViewPager(viewPager)
    }

}

@muhittin kaya 请参考以下代码解决您的问题

InfoFragment

class InfoFragment : BaseFragment() {

    lateinit var navController: NavController

    // Initialize your variable
    lateinit var infoFragmentInterface: InfoFragmentDataInterface

    // If you get initialization exception then uncomment below line and comment above line
    //private var  infoFragmentInterface: InfoFragmentDataInterface? = null


    companion object {
        private const val TAG = "Info Fragment"
    }

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        navController = Navigation.findNavController(view)
        button_info_idcard.setOnClickListener {
            //start OcrActivity
            val intent = Intent(activity, OcrActivity::class.java)
            startActivityForResult(intent, 101)
        }

        imagebutton_info_settings.setOnClickListener {
            navController.navigate(R.id.action_infoFragment_to_settingsFragment)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.i("Muhittin", "onActivityResult()")

        if (requestCode == 101) {
            val message = data?.getStringExtra("TEST_TEXT")
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()

            val serieNo = IdentityCardInfo.serieNo
            val validDate = IdentityCardInfo.validDate
            val dateOfBirth = IdentityCardInfo.dateOfBirth
            val fullname = IdentityCardInfo.fullName
            val gender = IdentityCardInfo.gender
            val identityNo = IdentityCardInfo.identityNo
            val nationality = IdentityCardInfo.nationality

            val bundle = bundleOf(
                "TEST_TEXT" to message,
                "SERIE_NO" to serieNo,
                "VALID_DATE" to validDate,
                "DOB" to dateOfBirth,
                "FULL_NAME" to fullname,
                "GENDER" to gender,
                "IDENTITY_NO" to identityNo,
                "NATIONALITY" to nationality
            )

            //Add This line for passing your data
            //You can also pass string data here
            infoFragmentInterface.getInfoFragmentData(bundle)

            navController.navigate(
                R.id.action_infoFragment_to_detailFragment,
                bundle
            )
        }
    }
}

// Create this interface to pass your data
interface InfoFragmentDataInterface {
    fun getInfoFragmentData(bundle: Any)
}

结果片段

class ResultsFragment : Fragment(), InfoFragmentDataInterface {

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

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)

        tabLayout.tabGravity = TabLayout.GRAVITY_FILL
        val tabTitles = arrayOf(
            resources.getString(R.string.result_tab1_name),
            resources.getString(R.string.result_tab2_name),
            resources.getString(R.string.result_tab3_name)
        )

        val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
        viewPager.offscreenPageLimit = 3
        val adapter = PagerAdapter(fragmentManager, tabTitles)
        viewPager.adapter = adapter
        tabLayout.setupWithViewPager(viewPager)
    }

    override fun getInfoFragmentData(bundle: Any) {
        // You'll get your Bundle data here.
    }
}

如果要使用ViewModel在同一个activity、here's the Android documentation about it的片段之间传递数据。它允许片段访问共享对象而无需相互了解,或通过 activity 进行通信(使用一堆代码来启用该通信)

你基本上会这样做:

// create a ViewModel that holds the data you want to share
class IdentityCardViewModel : ViewModel() {
    val identityInfo = MutableLiveData<IdentityCardInfo>()

    fun setInfo(info: IdentityCardInfo) {
        identityInfo.value = info
    }
}

然后每个片段将获取同一个 ViewModel 实例的副本:

// Get a reference to the IdentityCardViewModel created and held by the activity
private val model: IdentityCardViewModel by activityViewModels()

然后InfoFragment可以用model.setInfo(yourIdentityCardInfo)设置数据。 ResultsFragment可以观察此数据并在看到新值时执行某些操作:

model.identityInfo.observe(viewLifecycleOwner, Observer<IdentityCardInfo> { info ->
        // Do whatever you need with the updated info, like displaying it
    })