想要使用 SharePreferences 更新第二个片段中的数据,但第二个片段没有更新
Posted
技术标签:
【中文标题】想要使用 SharePreferences 更新第二个片段中的数据,但第二个片段没有更新【英文标题】:want to update data in second fragment with SharePreferences but second Fragment is not updating 【发布时间】:2021-04-10 22:24:41 【问题描述】:我正在制作一个计算器应用程序,并希望在第二个片段中更新历史记录,但无法找到在第二个片段中更新 ListView 的完美解决方案。我尝试了许多解决方案,但没有一个能正常工作。 我正在使用 ViewPager 在计算器和历史片段之间滑动。我厌倦了 bundle 类,但是如果我在第一个 Fragment(CalculatorFragment) 的 OnCreat 方法中使用带有 ViewPager 的 bundle,它会在启动应用程序后显示空白屏幕,如果我在 Equal Button 中使用 Bundle 类,它会使应用程序崩溃。在这里,我将 viewPager 的 id 作为片段的容器 传递。
我看到许多答案在使用 Framelayout 作为 Fragments 容器时完美运行,但我想保留 ViewPager 的滑动功能,我尝试了很多解决方案,但没有一个它们与 ViewPger 一起正常工作,我在我的代码中添加了 SharedPreferences,但是当我使用计算器时它没有更新(不是实时的)。 SharedPreferences 似乎有效,但在应用程序运行时它们没有更新历史记录 当我重新启动应用程序时,它会显示我在历史片段中的最后一次计算。
我通过 SharedPreferences 并在第二个片段(历史片段)的 onResume/onStart 方法中获取字符串,但它只显示我关闭应用程序时上次计算的历史记录
我正在使用自定义 ArrayList 在历史片段中存储和显示我的历史输出。
每当有人单击应用程序中的“=”按钮时,我想将数据(计算以显示历史记录)传递给 HistoryFragment。 “=”按钮调用计算器应用程序中的equal方法。
正在发生的事情的示例 if I do this calculation in my calculator it does not update
and in History it shows that last one from last when I closed application
这是我到目前为止所做的事情
这是使用 SharedPreferences 在 CalculatorFragment.java(first fragment) 中保存答案的代码
我也对使用 .appy() 还是 .commit() 感到困惑
public View onCreatView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View rootView = inflater.inflate(R.layout.fragment_calculator, container, false);
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor mEditor = mPreferences.edit();
/*
other code
*/
public void Equals()
String calc = etCalc.getText().toString();
if (calc.split("\\+").length == 2)
String[] calculation = calc.split("\\+");
String Ans = String.valueOf(Double.parseDouble(calculation[0]) +
Double.parseDouble(calculation[1]));
etCalc.setText(Ans);
tvCalc.setText(calc);
mEditor.putString("key",calc+"="+Ans);
mEditor.apply();
HistoryFragment.java
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import java.util.ArrayList;
public class HistoryFragment extends Fragment
ArrayList<HistoryList> historyLists;
SharedPreferences mPreferences;
String History = "";
View rootView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
rootView = inflater.inflate(R.layout.fragment_history, container, false);
return rootView;
public void onResume()
super.onResume();
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
History = mPreferences.getString("key", "");
if (History.split("=").length == 2)
historyLists = new ArrayList<>();
historyLists.add(new HistoryList(History.split("=")[0], History.split("=")[1]));
HistoryAdapter adapter = new HistoryAdapter(getActivity(), historyLists);
ListView listView = rootView.findViewById(R.id.history);
listView.setAdapter(adapter);
MainActivity.java
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
public class MainActivity extends AppCompatActivity
ViewPager viewPager;
pageAdapter pageAdapter;
Button btnEqual;
@RequiresApi(api = Build.VERSION_CODES.M)
@SuppressLint("SetTextI18n", "UseCompatLoadingForDrawables")
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewPager);
//Get rid of ActionBar
ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
actionBar.hide();
pageAdapter = new pageAdapter(getSupportFragmentManager(), 2);
viewPager.setAdapter(pageAdapter);
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context=".MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_
android:layout_ />
</LinearLayout>
如果您需要任何其他应用程序代码,请发表评论。
【问题讨论】:
确保调用 equal() 函数记录值或显示 toast @takieddine 你能详细解释一下在哪里调用equal方法吗,我是app dev的菜鸟,不完全明白你告诉我在哪里实现这个方法 既然你调用 editor.apply 来保存 sharedpreferences 中的数据,现在我们需要首先检查是否调用了 equal() 函数,尝试这样的 toast 消息: Toast.make(this ,"data saved",Toast.Length_Short).show() ,当您启动应用并尝试保存数据时,它应该显示一个 toast ,并告诉我是否显示 @takieddine 在将数据字符串保存在 SharedPreferences 中后,我在 equal() 方法中添加了 Toast 消息。在 editor.apply() 的代码之后显示 Toast 消息;运行。 现在在 onResume() 中的历史片段中获取历史值后,尝试记录字符串值,Toast.make(this,"History is" + History ,Toast.Length_Short).show( ) 并告诉我它是否显示保存的数据 【参考方案1】:我找到了解决这个问题的方法。我们可以使用 Shared ViewModel 通过 Fragments 传递数据,无需使用 SharedPreferences。我们可以将文本设置为 ViewModel 并在第二个片段中获取它,即使两个片段都处于恢复状态(两个片段都处于恢复状态,因为这里我们使用的是简单的 ViewPager)。
我在下面发布我的代码以供参考,我如何更新第二个片段中的数据。
将此代码添加到 MainActivity.java 文件中。 两个fragment都需要加,如果只加一个就没有ViewPager的滑动效果。
getSupportFragmentManager().beginTransaction().add(R.id.viewPager, new CalculatorFragment()).add(R.id.viewPager, new HistoryFragment()).commit();
在 CalculatorFragment.java 文件中将文本设置为 ViewModel。
public void Equals()
String calc = etCalc.getText().toString();
if (calc.split("\\+").length == 2)
String[] calculation = calc.split("\\+");
String Ans = String.valueOf(Double.parseDouble(calculation[0]) +
Double.parseDouble(calculation[1]));
etCalc.setText(Ans);
viewModel.setText(Ans);
//to send data to ViewModel
public void onActivityCreated(@Nullable Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(SharedViewModel.class);
创建一个名为 SharedViewModel.java
的类package com.shashank.calculator;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class SharedViewModel extends ViewModel
private final MutableLiveData<CharSequence> text = new MutableLiveData<>();
public void setText(CharSequence input)
text.setValue(input);
public LiveData<CharSequence> getText()
return text;
最后在第二个 HistoryFragment.java
中从 ViewModel 获取数据public class HistoryFragment extends Fragment
ArrayList<HistoryList> historyLists;
HistoryAdapter adapter;
SharedViewModel viewModel;
String History;
View rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
rootView = inflater.inflate(R.layout.fragment_history, container, false);
listView = rootView.findViewById(R.id.history);
historyLists = new ArrayList<>();
return rootView;
public void onActivityCreated(@Nullable Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
// getting data from SharedViewModel and setting it to ListView
viewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(SharedViewModel.class);
viewModel.getText().observe(getViewLifecycleOwner(), charSequence ->
History = String.valueOf(charSequence);
adapter = new HistoryAdapter(Objects.requireNonNull(getActivity()), historyLists);
historyLists.add(0,History);
listView.setAdapter(adapter);
);
【讨论】:
以上是关于想要使用 SharePreferences 更新第二个片段中的数据,但第二个片段没有更新的主要内容,如果未能解决你的问题,请参考以下文章
SharePreferences源码分析(SharedPreferencesImpl)
Android - SharePreferences数据存储的简单使用
关于android开发的sharePreferences读取问题