1

I want to make a step counter on Android with TYPE_STEP_COUNTER.As you know, TYPE_STEP_COUNTER will reset when you re-boot the device.So I should conserve the steps.I decide to use SharedPreference to conserve it. The project structure as follows: enter image description here

In the MainActivity.java,

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text_step = (TextView) findViewById(R.id.main_text_step);
        delayHandler = new Handler(this);
        Toolbar toolbar=(Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        SharedPreferences.Editor editor=getSharedPreferences("DateStep",MODE_PRIVATE).edit();
    }

But ,when I put data in StepService.java,it failed. //StepService.java

editor.putInt("step",StepDetector.CURRENT_STEP); editor.putString("date",current_Date);

It says can't resolve symbol editor. can you give me some advive what should I do to conserve data in StepService.java?

When I declared in service.java,it shows as follows: enter image description here

zyMacro
  • 675
  • 7
  • 14
  • You should probably show more of the actual problem code so we have more context. Also, don't use snippets for java code. Just use code blocks – codeMagic Jun 15 '17 at 14:07

3 Answers3

2

you need to declare your editor outside onCreate to make it visible to other methods because currently the declaration limits it's scope to only inside onCreate method , in short it's a Local reference variable

  SharedPreferences.Editor editor; 
  // ^^^^^^^^^^  declare it outside

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text_step = (TextView) findViewById(R.id.main_text_step);
        delayHandler = new Handler(this);
        Toolbar toolbar=(Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        editor=getSharedPreferences("DateStep",MODE_PRIVATE).edit();
        // initialize editor
    }

To use editor in other class then declare and initialize it as shown above while using the same file name DateStep to save data in that file.

In Service class , override onCreate in service and apply the same approach

SharedPreferences.Editor editor; 
// ^^^^^^^^^^  declare it outside

@Override
public void onCreate() {
    super.onCreate();
    editor=getSharedPreferences("DateStep",MODE_PRIVATE).edit();
        // initialize editor
}
Pavneet_Singh
  • 36,884
  • 5
  • 53
  • 68
  • When I changed as you told me,the same mistake happens.Service.java still can't recognize editor. – zyMacro Jun 15 '17 at 14:14
  • It's not an issue of using it in other methods. The issue seems to be it not being declared in a *different class* – codeMagic Jun 15 '17 at 14:15
  • you have to declare your `editor` in different class as well as shown above , or you can create a utility class , which uses the context to save passed data to preference – Pavneet_Singh Jun 15 '17 at 14:16
  • It doesn't need (and shouldn't be) declared outside of `onCreate()` if that's the only place it's being used in that class. – codeMagic Jun 15 '17 at 14:16
  • Can editor be declared in service.java not in activity? – zyMacro Jun 15 '17 at 14:17
  • it can be , without any issue , try it and look at [this also](https://stackoverflow.com/questions/9054193/how-to-use-sharedpreferences-to-save-more-than-one-values) plus follow the above advise everywhere in your code – Pavneet_Singh Jun 15 '17 at 14:17
  • All I will use the editor is in service including put and get. – zyMacro Jun 15 '17 at 14:18
  • don't forget to override `oncreate` method in service to initialize the preference – Pavneet_Singh Jun 15 '17 at 14:24
  • as i said `override` `oncreate` method in service and move that code inside `oncreate` , type `oncreate` in your service and select the option and press enter to override it – Pavneet_Singh Jun 15 '17 at 14:27
  • Do you mean it must be declared in onCreate function? – zyMacro Jun 15 '17 at 14:30
  • yup , there is `oncreate` in `service` as well , just override it , confirm here https://developer.android.com/reference/android/app/Service.html#onCreate() – Pavneet_Singh Jun 15 '17 at 14:30
2

You need to commit your changes.

editor.putInt("step",StepDetector.CURRENT_STEP);
editor.putString("date",current_Date);
editor.apply(); // <-- Save the data in the Shared Preferences.

Then in your service you can get the Shared Preferences again and get the values. You don't need to share the editor across the two classes. In the StepService just request the Shared Preferences again:

Context mContext = context;
// ...

mContext.getSharedPreferences("DateStep",MODE_PRIVATE).edit();
// Then get the data you want.

Edit

// In StepService

Editor mEditor;

@Override
public void onCreate() {
    super.onCreate(); 
    mEditor = getApplicationContext().getSharedPreferences("DateStep",MODE_PRIVATE).edit();
    // Then get the data you want anywhere in your Service
}
Eselfar
  • 3,759
  • 3
  • 23
  • 43
  • The problem is service.java can't read variable editor defined in mainActivity.java – zyMacro Jun 15 '17 at 14:15
  • Of course. Precisely because it's defined in the Activity. Just get an another instance of the editor. I've updated my answer above – Eselfar Jun 15 '17 at 14:15
  • All I will use the editor is in service including put and get.So can I only declared it in service? – zyMacro Jun 15 '17 at 14:19
  • If you only use it in service then, yes, just declare, initialize, and use it there – codeMagic Jun 15 '17 at 14:20
  • You can get the Application Context (`getApplicationContext()`) in a Service. Then because the Shared Preferences are accessible from anywhere in the application you can retrieve your data – Eselfar Jun 15 '17 at 14:37
2

I would use an interface to communicate Activity and Service: it's makes code cleaner, easier to read and test. If you have never used them, it may be a bit confusing, but take a minute to understand the code:

ServiceCallback.java

public interface ServiceCallback {
    void updateStepValue(int value, String date);
}

StepService.java

public class StepService extends Service {
   ServiceCallback mCallback;

   public void bindCallback(ServiceCallback callback) {
       mCallback = callback;
   }

   public void unbindCallback() { 
       mCallback = null; 
   }

   // Somewhere in your code, call callback method to send data to Activity
   ...
   mCallback.updateStepValue(5, "15-07-2017");
}

Activity.java

public class Activity implements ServiceCallback {
    SharedPreferences.Editor editor;
    StepService service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        editor = context.getSharedPreferences("preferences_key", Context.MODE_PRIVATE).edit();
        // Once your service is running and assigned to service variable
        // bind activity to it to listen service callbacks
        service.bindCallback(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        service.unbindCallback();
    }

    @Override
    void updateStepValue(int value, String date) {
         editor.putInt("step",value);
         editor.putString("date",date);
         editor.apply();
    }
}
Daniel Luque
  • 116
  • 1
  • 8
  • Thank you.It surely be a better method. – zyMacro Jun 15 '17 at 14:31
  • Does it mean you keep an instance of your Activity in your Service event if the Activity is not used anymore? It doesn't create leaks? – Eselfar Jun 15 '17 at 14:46
  • That's it: you need to call a method to remove the activity's reference on `onDestroy()` or `onResume()` method like this: `public void unbindCallback() { mCallback = null; } ` – Daniel Luque Jun 15 '17 at 14:58