1

I have the following function:

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
    if (s.equals("service_enabled")) {
        boolean shouldStart = sharedPreferences.getBoolean(s, false);
        Intent intent = new Intent(getActivity(), HUD.class);
        if (shouldStart) {  // Turn on
            getActivity().startService(intent);
        } else {            // Turn off
            getActivity().stopService(intent);
        }

    }
}

The function is called when a change is done to my PreferenceFragment. The service Hud is (probably) running if shouldStart == false, and then I want to stop it. This works as expected if you just click the option twice; the service starts, and stops. However, if you start it, go back to the previous activity, and enter this fragment again, and try to disable it, the following happends:

01-25 22:22:44.848  32548-32548/net.hath.drawcut E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at android.content.ComponentName.<init>(ComponentName.java:75)
        at android.content.Intent.<init>(Intent.java:3558)
        at net.hath.drawcut.ui.fragment.PrefsFragment.onSharedPreferenceChanged(PrefsFragment.java:35)
        at android.app.SharedPreferencesImpl$EditorImpl.notifyListeners(SharedPreferencesImpl.java:475)
        at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:385)
        at android.preference.Preference.tryCommit(Preference.java:1349)
        at android.preference.Preference.persistBoolean(Preference.java:1615)
        at android.preference.TwoStatePreference.setChecked(TwoStatePreference.java:83)
        at android.preference.TwoStatePreference.onClick(TwoStatePreference.java:69)
        at android.preference.Preference.performClick(Preference.java:949)
        at android.preference.PreferenceScreen.onItemClick(PreferenceScreen.java:215)
        at android.widget.AdapterView.performItemClick(AdapterView.java:298)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1100)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:2749)
        at android.widget.AbsListView$1.run(AbsListView.java:3423)
        at android.os.Handler.handleCallback(Handler.java:725)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5227)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
        at dalvik.system.NativeStart.main(Native Method)

Line 35 is Intent intent = new Intent(getActivity(), HUD.class);.

What is happening here?

MartinHaTh
  • 1,417
  • 1
  • 13
  • 25
  • Please upload the complete stacktrace – Emmanuel Jan 25 '14 at 21:36
  • You mentioned HUD is a service, is Line 35 the approach you take in starting the service? It's likely that getActivity() is null for some reason, in which case starting the service could be done like Intent intent=new Intent("com.demo.service.ServiceClass"); this.startService(intent); – Ryhan Jan 25 '14 at 21:52
  • That could be, but this is in a fragment, which means I don't have the start- or stopService methods; i need to use `getActivity()` for that. But wouldn't it be weird if `getActivity()` suddenly returned `null`, just because a service was started? – MartinHaTh Jan 25 '14 at 22:03

3 Answers3

1

After debugging for a while I found the problem: getActivity() returned null (just like Ryan said :).

The solution I used were from this answer to a similar question.

private Activity activity;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    this.activity = activity;
}

and replace getActivity() with activity. Not really pretty, and it probably is prone to bugs, but it works.

Community
  • 1
  • 1
MartinHaTh
  • 1,417
  • 1
  • 13
  • 25
1

You register your preference listener, but then your fragment is detached, and when you come back to the activity a new one is created.

Your old fragment instance is still around, held by the preferences as a listener.

What you need to do is unregister your fragment as a preference listener when you detach it from the activity, and register it again when you are attached again. This way you ensure that your fragment has a valid activity reference.

njzk2
  • 38,969
  • 7
  • 69
  • 107
0

another way:

private Context mContex;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
      mContext = getActivity();

}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if (s.equals("service_enabled")) {
    boolean shouldStart = sharedPreferences.getBoolean(s, false);
    Intent intent = new Intent(mContext, HUD.class);
    if (shouldStart) {  // Turn on
        mContext.startService(intent);
    } else {            // Turn off
        mContext.stopService(intent);
    }

}

}