每次应用程序重新启动时,onActivityCreated() 中的函数调用都会触发观察者

如何解决每次应用程序重新启动时,onActivityCreated() 中的函数调用都会触发观察者

在我的片段中,我正在观察一个函数中的实时数据,并且在该观察者中,一些 sharedPreferences 发生了变化。然后在 onActivityCreated() 内部调用该函数。 问题是每当我重新启动我的应用程序时,onActivityCreated() 都会被调用,该函数又调用该函数,该函数又会观察实时数据,从而更改我不想要的 sharedPreference 的值.

附加到我的片段的代码。

package com.example.expensemanager.ui

import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.expensemanager.R
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry
import kotlinx.android.synthetic.main.fragment_transaction_list.*
import kotlinx.android.synthetic.main.set_balance_details.view.*
import org.eazegraph.lib.models.PieModel


class TransactionListFragment : Fragment() {
    //declaring the view model
    private lateinit var viewModel: TransactionListViewModel
    var cashAmount:Float = 0F
    var bankAmount:Float = 0F
    override fun onCreate(savedInstanceState: Bundle?){
        super.onCreate(savedInstanceState)

        //setHasOptionsMenu(true)
        //(activity as AppCompatActivity?)!!.setSupportActionBar(addAppBar)
        viewModel = ViewModelProvider(this)
            .get(TransactionListViewModel::class.java)
    }

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        //recycler view for showing all the transactions
        with(transaction_list){
            layoutManager = LinearLayoutManager(activity)
            adapter = TransactionAdapter {
                findNavController().navigate(
                    TransactionListFragmentDirections.actionTransactionListFragmentToTransactionDetailFragment(
                        it
                    )
                )
            }
        }
        //code for the floating action button in the main screen
        add_transaction.setOnClickListener{
            findNavController().navigate(
                //here id is passed 0 because the transaction is being added the first time
                TransactionListFragmentDirections.actionTransactionListFragmentToTransactionDetailFragment(
                    0
                )
            )
        }

        addAppBar.setOnMenuItemClickListener { menuItem ->
            when(menuItem.itemId){
                R.id.calendar_button -> {
                    findNavController().navigate(TransactionListFragmentDirections.actionTransactionListFragmentToCalanderViewFragment())
                    true
                }
                R.id.monthly_cards -> {
                    findNavController().navigate(TransactionListFragmentDirections.actionTransactionListFragmentToMonthlyCardsFragment())
                    true
                }
                else -> false
            }
        }
        see_all_transactions.setOnClickListener {
            findNavController().navigate(TransactionListFragmentDirections.actionTransactionListFragmentToAllTransactionsFragment())
        }


        //submitting the new list of upcoming Transactions after getting it from the db
        viewModel.upcomingTransactions.observe(viewLifecycleOwner,Observer {
            (transaction_list.adapter as TransactionAdapter).submitList(it)
        })

        val sharedPreferences: SharedPreferences = this.requireActivity().getSharedPreferences("OnboardingDetails",Context.MODE_PRIVATE)

        val monthlyBudget = sharedPreferences.getFloat("monthlyBudget",0F)
        var totalBalance = monthlyBudget*12
        net_balance.text = totalBalance.toString()
        Log.d("netbalance",totalBalance.toString())
        //the net balance (yearly) is calculated wrt the transactions already done
        viewModel.sumOfTransactions.observe(viewLifecycleOwner,Observer {
            if (it != null) {
                totalBalance += it
                net_balance.text = totalBalance.toString()
            }
        })
        val budgetPreferences: SharedPreferences =
                this.requireActivity().getSharedPreferences("Balance_details",Context.MODE_PRIVATE)
        val editor: SharedPreferences.Editor = budgetPreferences.edit()

        //setting pie chart initially to 0
        setPieChart(budgetPreferences,editor)
        //observing the cash details and the bank details to update the text view and the pie chart
        observeBalance(budgetPreferences,editor)
        //GraphCardView code
        //button for setting the balance details
        set_balance_details.setOnClickListener {
            setBalanceDetails(budgetPreferences,editor)
        }
    }
    //dialog box for setting the balance details
    private fun setBalanceDetails(budgetPreferences: SharedPreferences,editor: SharedPreferences.Editor) {
        val dialog = LayoutInflater.from(requireContext()).inflate(
            R.layout.set_balance_details,null
        )
        //AlertDialogBuilder
        val mBuilder = AlertDialog.Builder(requireContext())
            .setView(dialog)
        //show dialog
        val  mAlertDialog = mBuilder.show()

        dialog.save_details.setOnClickListener {
            cashAmount = dialog.cash_amount.editText?.text.toString().toFloat()
            bankAmount = dialog.bank_amount.editText?.text.toString().toFloat()
            //saving the cashAmount and bankAmount to shared preferences for future use
            editor.putFloat("cashAmount",cashAmount).apply()
            editor.putFloat("bankAmount",bankAmount).apply()

            //setting the pie chart with new values
            setPieChart(budgetPreferences,editor)
            mAlertDialog.dismiss()
        }
        dialog.cancel_details.setOnClickListener { mAlertDialog.dismiss() }
        mAlertDialog.show()
    }

    private fun observeBalance(budgetPreferences: SharedPreferences,editor: SharedPreferences.Editor) {
        //getting the cashAmount and bankAmount and updating the views with live data

        var cashAmount = budgetPreferences.getFloat("cashAmount",0F)
        var bankAmount = budgetPreferences.getFloat("bankAmount",0F)
        viewModel.cashAmount.observe(viewLifecycleOwner,Observer {

            if (it != null) {
                cashAmount += it
                cash.text = "CASH : ${cashAmount}"
                Log.d("observeCash",cashAmount.toString())
                editor.putFloat("cashAmount",cashAmount).apply()//find solution to this
                setPieChart(budgetPreferences,editor)
            }
        })

        viewModel.bankAmount.observe(viewLifecycleOwner,Observer {
            if (it != null) {
                bankAmount+=it
                bank.text = "BANK : ${bankAmount}"
                Log.d("observeBank",bankAmount.toString())
                editor.putFloat("cashAmount",cashAmount).apply()
                setPieChart(budgetPreferences,editor)
            }
        })
        setPieChart(budgetPreferences,editor)
    }
    //https://www.geeksforgeeks.org/how-to-add-a-pie-chart-into-an-android-application/ use this for reference
    private fun setPieChart(budgetPreferences: SharedPreferences,editor: SharedPreferences.Editor) {

        val cashAmount = budgetPreferences.getFloat("cashAmount",0f)
        val bankAmount = budgetPreferences.getFloat("bankAmount",0f)
        Log.d("pieCank",cashAmount.toString())
        Log.d("pieBank",bankAmount.toString())
        cash.text = "CASH : ${cashAmount}"
        bank.text = "BANK : ${bankAmount}"

        val pieEntries = arrayListOf<PieEntry>()
        pieEntries.add(PieEntry(cashAmount))
        pieEntries.add(PieEntry(bankAmount))
        pieChart.animateXY(1000,1000)

        // setup PieChart Entries Colors
        val pieDataSet = PieDataSet(pieEntries,"This is Pie Chart Label")
        pieDataSet.setColors(
            ContextCompat.getColor(requireActivity(),R.color.blue1),ContextCompat.getColor(requireActivity(),R.color.blue2)
        )
        val pieData = PieData(pieDataSet)

        // setip text in pieChart centre
        //piechart.setHoleColor(R.color.teal_700)
        pieChart.setHoleColor(getColorWithAlpha(Color.BLACK,0.0f))
        // hide the piechart entries tags
        pieChart.legend.isEnabled = false
//        now hide the description of piechart
        pieChart.description.isEnabled = false
        pieChart.description.text = "Expanses"
        pieChart.holeRadius = 40f
        // this enabled the values on each pieEntry
        pieData.setDrawValues(true)
        pieChart.data = pieData

    }
    fun getColorWithAlpha(color: Int,ratio: Float): Int {
        var newColor = 0
        val alpha = Math.round(Color.alpha(color) * ratio)
        val r = Color.red(color)
        val g = Color.green(color)
        val b = Color.blue(color)
        newColor = Color.argb(alpha,r,g,b)
        return newColor
    }
}

当应用程序重新启动时,可以看到 viewModel.cashAmount 被触发,给出不想要的输出。 我该怎么做才能避免这种情况。

解决方法

活动可以重新创建很多,例如当您旋转屏幕时,或者如果它在后台并且系统销毁它以释放一些内存。现在,每次发生这种情况时,您的代码都不知道它获取的是当前值还是全新的值,但其中一个应该执行计算,另一个应该只是更新显示。

问题是您的计算逻辑与 UI 状态相关 - 它被告知要显示什么,并决定这是否算作新的用户操作。它无法知道这一点。你的逻辑需要像

things observe LiveData values -> update to display new values when they come in
user clicks a button -> do calculation with the value they've entered
calculation result returns -> LiveData gets updated with new value
LiveData value changes -> things update to show the new value

这样计算就会专门响应用户操作,例如通过单击按钮。 LiveData 观察者只反映当前状态,所以他们是否多次看到相同的值并不重要,他们只是重新绘制饼图或其他什么。


您可以使用 LiveData 来观察值流,但 UI 组件的问题是有时它们会在那里看到它们,有时则不会。并且 LiveData 专门用于将更新推送给活跃的观察者,而不是不活跃的观察者 - 并且始终向新观察者或变为活跃的观察者提供最新值。

因此,在这种情况下,它更像是“这是当前情况”,这更适合显示内容,如果您重复自己,则无关紧要。这就是为什么你不能在你的 UI 中做这种“一次处理所有事情”的事情 - 除非你真的响应一个 UI 事件,比如按钮点击

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res