Search code examples
javaandroidandroid-layoutandroid-fragmentsandroid-viewpager

want to update data in second fragment with SharePreferences but second Fragment is not updating


I am making a calculator app and want to update history in second fragment but not able to find a perfect solution for updating ListView in second fragment. I tried many solutions but none of them worked properly. I'm using ViewPager to swipe between calculator and history fragments. I tired bundle class but if I use bundle in OnCreat method of first Fragment(CalculatorFragment) with ViewPager it shows me blank screen after starting an App & if I use Bundle class in Equal Button it crashes app. here I am passing id of viewPager as Container of fragments.

I seen many answer perfectly working when they are using Framelayout for the container of Fragments but I want to keep swipe functionality of ViewPager, I tried many solutions but none of them worked properly with ViewPger, I added SharedPreferences to my code but it is not updating (not live) when I am using calculator. SharedPreferences seemed to work but they are not updating History when App is Running And When I restart the app it shows me my last Calculation in History Fragment.

I passed SharedPreferences and fetch the string in onResume/onStart method's of second fragment(History fragment) but it only shows the history of last calculation when I closed my application

I am using Custom ArrayList to Store and display my History output in History Fragment.

I want to pass data(calculation to show history) to HistoryFragment whenever anyone clicks "=" button in application. "=" button calls the equal method in calculator app.

Example of what is happening 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

here's what I have done so far

it is the code of saving answer in CalculatorFragment.java(first fragment) using SharedPreferences

I am also confused about which one to use .appy() or .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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

      <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

comment if you need any other code of application.


Solution

  • I found out solution for this problem. we can pass data through fragments using Shared ViewModel, no need to use SharedPreferences. we can set text to ViewModel and fetch it in second fragment, even when both fragments are in resumed condition(both are in resumed condition because here we are using simple ViewPager).

    I am posting my code below for reference, how I updated data in second fragment.

    Add this code in MainActivity.java file. adding both fragments is necessary if you only add any one it will not have the slide effect of ViewPager.

     getSupportFragmentManager().beginTransaction().add(R.id.viewPager, new CalculatorFragment()).add(R.id.viewPager, new HistoryFragment()).commit();
    

    Setting text to ViewModel in CalculatorFragment.java file.

    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);
        }
    }
    

    Make a class named 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;
        }
    }
    

    and at last getting data from ViewModel in second HistoryFragment.java

    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);
                }
            });
        }