为什么 SharedPreference 从另一个 activity 检索空值?

why SharedPreference retrieve null values from another activity?

所以我有两个活动 -

  1. MainActivity :从 SharedPreferences 中检索所有已保存的值。用户在点击位置时启动 SecondActivity ...
  2. SecondActivity : 用户将所有值存储到 SharedPreferences 并返回主 activity.

问题 - MainActivity 中读取的值为 0

代码-

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) {

        }
    }





使用下面的代码,您的共享偏好将完美运行。 为游戏状态创建模型

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

然后创建 class 以使用单例模式

共享首选项
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;
}

在您的 SecondActivity 中,您可以更新您的方法

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

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

然后最后在 MainActivity 的 onCreate() 中添加这段代码

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

    mLevel = gameStatus.getLevel();
    mScore = gameStatus.getScore();
    mCoins = gameStatus.getCoin();

storeretrieve 之间的 key 不匹配。在 put 值到 SharedPreference 期间 key 末尾有一个额外的 space。

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

这应该是

editor.putInt("data_0",level);
editor.putInt("data_1",score);
editor.putInt("data_2",coin);

如果您想以最简单的方式在整个应用程序中共享首选项,您应该使用 DefaultSharedPreferences

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

    SharedPreferences sharedPreferences = getDefaultSharedPreferences(this);