28

I have some shared preferences (latitude, longitude) that I want to access from a service, that is not subclassed from Activity.

In particular, when I try to access getPreferences, this function doesn't exist's on a service. My code is posted below

My goal here is to allow WRITE these shared preferences with my service. Any suggestions/examples that can help me along?

public class MyService extends Service implements Runnable {

    LocationManager mLocationManager;
    Location mLocation;
    MyLocationListener mLocationListener;
    Location currentLocation = null;
    static SharedPreferences settings;
    static SharedPreferences.Editor configEditor;

    public IBinder onBind(Intent intent) {
        return null;
    }

    public void onCreate() {
        settings = this.getPreferences(MODE_WORLD_WRITEABLE);
        configEditor = settings.edit();
        writeSignalGPS();
    }

    private void setCurrentLocation(Location loc) {
        currentLocation = loc;
    }

    private void writeSignalGPS() {
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Looper.prepare();
            mLocationListener = new MyLocationListener();
            mLocationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 1000, 0, mLocationListener);
            Looper.loop();
            //Looper.myLooper().quit();
        } else {
            Toast.makeText(getBaseContext(),
              getResources().getString(R.string.gps_signal_not_found),
              Toast.LENGTH_LONG).show();
        }
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (currentLocation!=null) {
                configEditor.putString("mylatitude", ""+currentLocation.getLatitude());
                configEditor.putString("mylongitude", ""+currentLocation.getLongitude());
                configEditor.commit();
            }
        }
    };

    private class MyLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location loc) {
            if (loc != null) {
                Toast.makeText(getBaseContext(),
                getResources().getString(R.string.gps_signal_found),
                  Toast.LENGTH_LONG).show();
                setCurrentLocation(loc);
                handler.sendEmptyMessage(0);
            }
        }

    @Override
    public void onProviderDisabled(String provider) {}

    @Override
    public void onProviderEnabled(String provider) {}

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
}

I get the error on the line settings = this.getPreferences(MODE_WORLD_WRITEABLE);

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
NullPointerException
  • 36,107
  • 79
  • 222
  • 382

5 Answers5

45

If you are only using one SharedPreferences for your application, have all your code get it via PreferenceManager.getDefaultSharedPreferences().

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • can you explain me a little more what i have to change on my codde to use preference manager? i am searching on google but i can't find info valid for me – NullPointerException Nov 18 '10 at 13:00
  • 1
    @AndroidUser99: You replace calls to `getPreferences()` with a call to `PreferenceManager.getDefaultSharedPreferences()`. – CommonsWare Nov 18 '10 at 13:06
  • i tryed with this: settings = PreferenceManager.getDefaultSharedPreferences(MODE_WORLD_WRITEABLE); but gives me an error, what i am doing wrong? – NullPointerException Nov 18 '10 at 13:08
  • 12
    @AndroidUser99: What is going wrong is that you are not reading the documentation. http://developer.android.com/reference/android/preference/PreferenceManager.html#getDefaultSharedPreferences(android.content.Context) – CommonsWare Nov 18 '10 at 13:11
  • 5
    @AndroidUser99: More specifically, `getDefaultSharedPreferences()` takes a `Context` (e.g., your `Service`) as a parameter. – CommonsWare Nov 18 '10 at 13:13
  • @AndroidUser99: Here is a sample project demonstrating the use of `PreferenceManager.getDefaultSharedPreferences()`: https://github.com/commonsguy/cw-android/tree/master/Prefs/Simple/ – CommonsWare Nov 18 '10 at 13:15
  • ok thanks but using this, i can read and modify in other activitys these two shared preferences, and another shared preferences? in these other activitys i have to change this line to preferencemanager too?? – NullPointerException Nov 18 '10 at 13:17
  • @AndroidUser99: As I wrote in the original answer, have **all** your code get it via `PreferenceManager.getDefaultSharedPreferences()`. – CommonsWare Nov 18 '10 at 13:44
  • you mean in the other activities?? then it will work, i hope it works, i have to change a lot of code lines XD – NullPointerException Nov 18 '10 at 13:50
  • wow... it crashes. Im testing your solution in another of my normal activitys and crashes in this line: configEditor = settings.edit(); i have to change something more? :S it says nullpointerexception – NullPointerException Nov 18 '10 at 13:53
  • ok forget it, it seems to work on my activity!!!!! i will try the service now, thanks mate – NullPointerException Nov 18 '10 at 13:59
  • Just curious... when should you use multiple `SharedPreferences` in one application? – Rudey Apr 17 '14 at 19:47
  • 2
    @RuudLenders: IMHO, an app itself probably does not need multiple `SharedPreferences`, except perhaps in cases where it has its own concept of multiple users (separate from Android's multiple accounts on 4.2+ tablets). However, libraries should use a separate `SharedPreferences`, so they do not accidentally collide with the `SharedPreferences` used by an app incorporating the library. – CommonsWare Apr 17 '14 at 20:14
  • What if you want to set mode for the ``SharedPreferences``? For example, in a service you need to set ``MODE_MULTI_PROCESS``, otherwise preferences are cached. How can you do that with ``PreferenceManager.getDefaultSharedPreferences()`` that doesn't take a mode? – gozzilli Jul 02 '15 at 11:08
  • @gozzilli: "For example, in a service you need to set MODE_MULTI_PROCESS, otherwise preferences are cached" -- or, just use only one process. "How can you do that with PreferenceManager.getDefaultSharedPreferences() that doesn't take a mode?" -- AFAIK, you don't do that with `getDefaultSharedPreferences()`. I have not attempted to share any `SharedPreferences` between processes, let alone the default `SharedPreferences` for an app. – CommonsWare Jul 02 '15 at 11:27
  • @CommonsWare yeah, I think the best answer for that (if you do indeed want a separate process for your service) is this: http://stackoverflow.com/a/23681503/277113 It's a shame that a solution for ``getDefaultSharedPreferences`` doesn't seem to exist. – gozzilli Jul 02 '15 at 11:57
20

Actually, most of you might be running into the problem, that on devices with API >=11, the shared preferences are not set for multi process use by default anymore.

Solution:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    prefs = getSharedPreferences(PREFS, 0 | Context.MODE_MULTI_PROCESS);
} else {
    prefs = getSharedPreferences(PREFS, 0);
}
Till - Appviewer.io
  • 4,529
  • 1
  • 31
  • 35
  • 1
    As per comment on @CommonsWare answer, how can you do this with ``PreferenceManager.getDefaultSharedPreferences()``? I'm in a service and I don't know the name of my default shared preferences. – gozzilli Jul 02 '15 at 11:09
  • Really you save me. Thanx a lottttttttttttttttttt – Prashanth Debbadwar Jul 20 '15 at 13:51
  • `MODE_MULTI_PROCESS` has been deprecated in API 23. See http://developer.android.com/reference/android/content/Context.html#MODE_MULTI_PROCESS – Ryan R Aug 25 '15 at 03:26
  • YES! THANK YOU! ...for Context.MODE_MULTI_PROCESS my issue was that when my service invoked my code block (Widget) a given key in my sharedpreferences had a different value as when invoked by an activity sending a broadcast intent.... re deprecation, looks like i am support to use ContentProvider to resolve this... ??? – tom May 02 '16 at 20:11
  • Wow, what a life saver. – Sukitha Udugamasooriya Aug 10 '16 at 10:43
  • Bro, you're my hero!!!!! – İsa C. Nov 18 '21 at 22:05
2

Little late to help you out on this, but I hope this helps someone in the future. Here is your problem:

    public void onCreate() {
       settings = this.getPreferences(MODE_WORLD_WRITEABLE);
       configEditor = settings.edit();
       writeSignalGPS();
    }

Since you only retrieve the Shared Preference file when the service is created, the file is never properly updated by the service and thus the data is never shared with the application. Before writing to Shared Preferences or retrieving any data that may have changed, make sure to retrieve the Shared Preference file (reload) again such as:

    private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (currentLocation!=null) {
            settings = this.getPreferences(MODE_WORLD_WRITEABLE);
            configEditor = settings.edit();
            configEditor.putString("mylatitude", ""+currentLocation.getLatitude());
            configEditor.putString("mylongitude", ""+currentLocation.getLongitude());
            configEditor.commit();
        }
    }

then in your application:

     settings = this.getPreferences(MODE_WORLD_WRITEABLE);
     String myLat = setttings.getString("mylatitude","");

Also, anything on Android 3.0 that has a scenario where a service and an activity share Shared Prefs, you should use:

     settings = this.getPreferences(MODE_MULTI_PROCESS);
Droid Chris
  • 3,455
  • 28
  • 31
1

If you have declared SharedPreferences as:

private static final String PREFS_NAME = "UserData"; 
private static final String PREFS_VALUE1 = "value1"; 

then use the below code to fetch values:

SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
value1 = preferences.getString(PREFS_VALUE1, "0");

In same way you can even save values to SharedPreferences.

Harpreet
  • 2,990
  • 3
  • 38
  • 52
1

For people who bump into this ... I had a similar problem ... The true cause of the problem is we are trying to get/use a context that is not fully initialized .. I was able to use sharedPreferences normally outside of my constructor for my IntentService.

Arjun
  • 322
  • 4
  • 20