0

So I have two Activities -

  1. MainActivity : Retrieves all the saved values from SharedPreferences. User launch SecondActivity on click where ...
  2. SecondActivity : User stores all the values into SharedPreferences and go back to the main activity.

Problem - Values read in the MainActivity are 0

Code -

MainActivity.java:

    public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration mAppBarConfiguration; 
    private DataViewModel dataViewModel;
    private StateData StateData;

    private int currinterface = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        /*-- Hide System Interface---*/
        hideSystemUI();
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view); 
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home)
                .setDrawerLayout(drawer)
                .build();

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);

        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_home); // custom home icon

        StateData = new StateData(); 
        dataViewModel = new ViewModelProvider(this).get(dataViewModel.class);
        stateObservers(); 
    } 

    private void stateObservers(){
        dataViewModel.getLevel().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer val) {
                currinterLevel = val;
                StateData.setLevel(val);
                SharedPrefManager.getInstance(MainActivity.this).setState(StateData);
            }
        });  

        dataViewModel.getSpeed().observe(this, new Observer<Float>() {
            @Override
            public void onChanged(Float val) {
                switch (currinterLevel){
                    case 0:
                        StateData.setSpeedLevelOne(val);
                        break;
                    case 1:
                        StateData.setSpeedLevelTwo(val);
                        break;
                    case 2:
                        StateData.setSpeedLevelThree(val);
                        break;
                }
                SharedPrefManager.getInstance(MainActivity.this).setState(StateData);
            }
        }); 
    }

    @Override
    protected void onPause() {
        super.onPause();
        /*Save all the setting when app closes*/
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) { 
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_one: 
                break;
            case R.id.menu_two: 
                break;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    } 
}

DataViewModel.java

    public class DataViewModel extends ViewModel { 
        private MutableLiveData<Float> speed;  
        private MutableLiveData<Integer> level; 

        public DataViewModel(){ 
            this.level = new MutableLiveData<>();
            this.speed = new MutableLiveData<>(); 
        }

        // Level
        public void setLevel(int val){
            level.setValue(val);
        }
        public LiveData<Integer> getLevel(){
            return level;
        }


        // scan
        public void setSpeed(Float val){
            speed.setValue(val);
        }
        public LiveData<Float> getSpeed(){
            return speed;
        } 

    }



public class StateData {
    private float speedOne;
    private float speedTwo;
    private float speedThree;

    private int lastLevel;

    public StateData() {
    }

    public float getSpeedLevelOne() {
        return speedOne;
    }
    public void setSpeedLevelOne(float speedOne) {
        this.speedOne = speedOne;
    }

    public float getSpeedLevelTwo() {
        return speedTwo;
    }
    public void setSpeedLevelTwo(float speedTwo) {
        this.speedTwo = speedTwo;
    }

    public float getSpeedLevelThree() {
        return speedThree;
    }
    public void setSpeedLevelThree(float speedThree) {
        this.speedThree = speedThree;
    }


    public int getLastLevel() {
        return lastLevel;
    }
    public void setLastLevel(int lastLevel) {
        this.lastLevel = lastLevel;
    }
}
HomeFragment.java

    import static androidx.fragment.app.FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;

    public class HomeFragment extends Fragment implements RadioGroup.OnCheckedChangeListener, SeekBar.OnSeekBarChangeListener {
        private static String TAG = "FRAGMENT_PARENT";

        private DataViewModel dataViewModel;
        private StateData stateData;

        private int currentLevel=0;

        private LinearLayout mSelector;
        private LinearLayout mController;
        private ViewPager viewPager;

        private SeekBar mSpeed;

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setHasOptionsMenu(true);
        }

        public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            dataViewModel = new ViewModelProvider((ViewModelStoreOwner) getContext()).get(DataViewModel.class);
            stateData = SharedPrefManager.getInstance(getActivity()).getState();
            return inflater.inflate(R.layout.fragment_home, container, false);
        }

        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);

            mSpeed = view.findViewById(R.id.Speed);
            mSpeed.setOnSeekBarChangeListener(this);

            viewPager = view.findViewById(R.id.interfacePager);
            InterfacePagerAdapter myPagerAdapter = new InterfacePagerAdapter(getChildFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
            viewPager.setAdapter(myPagerAdapter);
            viewPager.addOnPageChangeListener(pageChangeListener);

        }

        private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                currentLevel = position;
                dataViewModel.setLevel(position); // SET THE LEVEL DATA IN MAIN ACTIVITY VIA VIEW MODEL
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        };

        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            initFun();
        }


        @Override
        public void onResume() {
            super.onResume();
        }

        @Override
        public void onPause() {
            super.onPause();
        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            float progressPercentageFloat = (float)progress / 10.0f;
            switch (seekBar.getId()){
                case R.id.Speed:
                    dataViewModel.setSpeed(progressPercentageFloat); // SET SPEED DATA IN THE SELECTED LEVEL IN MAIN ACTIVITY VIA VIEW MODEL
                    break;
                default:
                    break;
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }

        private void initFun(){
            viewPager.setCurrentItem(stateData.getLastLevel());
            pageChangeListener.onPageSelected(stateData.getLastLevel());
            mSpeed.setProgress((int)(stateData.getSpeedLevelOne()*10));
            mSpeed.setProgress((int)(stateData.getSpeedLevelTwo()*10));
            mSpeed.setProgress((int)(stateData.getSpeedLevelThree()*10));
        }

        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {

        }
    }





B L Λ C K
  • 600
  • 1
  • 8
  • 24

3 Answers3

1

With the codes below your shared preferences will work perfectly. Create a model for game status

public class GameStatus {
    private int level;
    private int status;
    private int coin;

    public GameStatus() {
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public int getCoin() {
        return coin;
    }

    public void setCoin(int coin) {
        this.coin = coin;
    }
}

and then create class for shared preferences with singleton pattern

public class SharedPrefManager {
private static SharedPrefManager mInstance;
private static Context mCtx;

private static final String SHARED_PREF_NAME = "UNVERSALDEMO";
private static final String KEY_LEVEL = "keyLevel";
private static final String KEY_SCORE = "keyScore";
private static final String KEY_COIN = "keyCoin";

public SharedPrefManager(Context context){
    mCtx = context;
}

public static synchronized SharedPrefManager getInstance(Context context){
    if (mInstance == null){
        mInstance = new SharedPrefManager(context);
    }
    return mInstance;
}

public boolean saveGameStatus(GameStatus gameStatus){
    SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putInt(KEY_LEVEL, gameStatus.getLevel());
    editor.putInt(KEY_SCORE, gameStatus.getScore());
    editor.putInt(KEY_COIN, gameStatus.getCoin());
    editor.apply();
    return true;
}

public GameStatus getGameStatus(){
    SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
    GameStatus gs = new GameStatus();
    gs.setLevel(sharedPreferences.getInt(KEY_LEVEL, 0));
    gs.setScore(sharedPreferences.getInt(KEY_SCORE, 0));
    gs.setCoin(sharedPreferences.getInt(KEY_COIN, 0));
    return gs;
}

In your SecondActivity you can update your method

private void saveGame(){
    GameStatus gameStatus = new GameStatus();
    gameStatus.setLevel(level);
    gameStatus.setScore(score);
    gameStatus.setCoin(coin);

    SharedPrefManager.getInstance(this).saveGameStatus(gameStatus);
}

Then finally in MainActivity add this codes in onCreate()

GameStatus gameStatus = SharedPrefManager.getInstance(this).getGameStatus();

    mLevel = gameStatus.getLevel();
    mScore = gameStatus.getScore();
    mCoins = gameStatus.getCoin();
S.Grain
  • 182
  • 12
  • thank you for providing the code. This is a good example but I have already accepted the answer. Thank you so much again S. Grain :) – B L Λ C K Jan 08 '20 at 19:23
  • I encounter a problem when I was trying to create sharedpreferences your way, by making a class, in another project. The problem was when I was trying to get the values inside a Fragment, I was getting the "old values" from sharedPreferences. ---> I was changing the values inside a Fragment and broadcasting them via ViewModel to MainActivity and there I was setting the value to sharedPreference. But when I restart the app, I get last values stored in sharedPrefernces. Why? Do you have any idea how to fix this? – B L Λ C K Feb 28 '20 at 16:20
  • It would be easier to find where the problem is and find a solution if you share your codes. ΛBHINΛV – S.Grain Mar 01 '20 at 21:46
  • S.Gain some other guy had the same problem...Also, I have used exact methd as you have suggested... codewise it is same ... https://stackoverflow.com/questions/14128080/sharedpreferences-reads-old-values – B L Λ C K Mar 03 '20 at 12:54
  • It's confusing a bit. Can you share the codes where you encounter problem? @ΛBHINΛV – S.Grain Mar 05 '20 at 09:34
  • @S. Grain I have updated the code. Please check. The problem here is----> HomeFragment has three swipable Levels based on viewPagers. Each page has canavs based game. The speed in every level can be set with a slider presented on home screen. I am trying to store these speed based on the level. These values should be set whenever user swipe to other level and change in the speed should be saved in the preference whenever user makes any changes in the speed. My problem is everything is fine besides values read on each level are old til the app get restarted. – B L Λ C K Mar 05 '20 at 16:49
  • https://ufile.io/h00f1pd4 Here is full app. Can you suggest any solution? I am extreamly frustrated now. – B L Λ C K Mar 10 '20 at 03:03
  • Hey... do you have sometime to look into my code? I am stuck. I did make it work but poorly written hack by calling SharedPreference multiple times. Please if you can look into the code. – B L Λ C K Mar 17 '20 at 14:27
  • Hey @ΛBHINΛV I am too busy nowadays so I see your comments now. I am looking your codes right now and depending the problem I will be back in 5 minutes – S.Grain Mar 18 '20 at 14:59
  • Thank you so much. I understand you are busy with your work. No Rush. I just wanted you to look into it. Take care of yourself :) :) – B L Λ C K Mar 18 '20 at 15:36
  • Try to add your stateObservers() method and your DataViewModel object in your HomeFragment. Seems your fragment doesn't get the updates after being created. – S.Grain Mar 18 '20 at 16:52
  • I moved stateObservers() into my HomeFragment and it worked but do you have any guess why it wasn't working in MainActivity? Is it logically incorrect? Am I doing something wrong? – B L Λ C K Mar 18 '20 at 17:51
  • I hope everything is just like what you want :) Fragments and their container Activities don't just communicate each other. If you have changed the speed inside your activity your observers would show the instant result. But you change the value in fragment class and neither fragment doesn't have any code nor the container activity to pass the data. You would maintain it with local broadcasts or there are few more options to do it. @ΛBHINΛV – S.Grain Mar 18 '20 at 18:03
1

There is a mismatch in your key between store and retrieve. There is an extra space at the end of key during put value to SharedPreference.

editor.putInt("data_0 ",level);  // remove extra space at the end of data_0
editor.putInt("data_1 ",score);  // remove extra space at the end of data_1
editor.putInt("data_2 ",coin);  // remove extra space at the end of data_2

This should be

editor.putInt("data_0",level);
editor.putInt("data_1",score);
editor.putInt("data_2",coin);
Md. Asaduzzaman
  • 14,963
  • 2
  • 34
  • 46
  • Hey, sorry to bother you again but can you please help me to fix my new code. I have taken S.Grain route to write my SharedPreferences and it isn't working as expected. I am attaching a sample code for you https://uploadfiles.io/h00f1pd4 . Please look into it. Thank you. – B L Λ C K Mar 17 '20 at 14:31
0

If you want the easiest way to share preferences throughout your app, you should use the DefaultSharedPreferences.

https://developer.android.com/reference/android/preference/PreferenceManager.html#getDefaultSharedPreferences(android.content.Context)

    SharedPreferences sharedPreferences = getDefaultSharedPreferences(this);
Cory Roy
  • 5,379
  • 2
  • 28
  • 47