Jason Hanley
Jason Hanley

Reputation: 3225

Is onSharedPreferenceChanged always called on the UI thread

I have a singleton class that registers a preference change listener like:

PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext())
            .registerOnSharedPreferenceChangeListener(
                    preferencesChangeListener);

When certain preferences are changed my onSharedPreferenceChanged method will notify interested components about an event. One of these interested components updates data in a ListAdapter. I'm getting some exceptions indicating that this list adapter is being modified by a thread that is not the UI thread.

I've reviewed the code paths that change the adapter data and don't see anything wrong. My only suspiscion is that onSharedPreferenceChanged in the preference change listener is not being called on the UI thread.

The docs indicate that this method is called on the UI thread

This callback will be run on your main thread.

Has anyone seen situations where this is not the case? Does it matter that I registered my preference change listener with the application context?

Update: Here is the stack trace. The array size is always 0 with this exception. This is why I am taking a look at the shared preference listener since this is the only code path where I clear the data in the adapter. The index is non-zero, so it indicates there was data there before.

> java.lang.IndexOutOfBoundsException: Invalid index 51, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
at java.util.ArrayList.get(ArrayList.java:311)
at com.palta.earthquake.EarthquakeAdapter.getItem(EarthquakeAdapter.java:56)
at com.palta.earthquake.EarthquakeAdapter.getView(EarthquakeAdapter.java:86)
at android.widget.AbsListView.obtainView(AbsListView.java:1294)
at android.widget.ListView.makeAndAddView(ListView.java:1727)
at android.widget.ListView.fillUp(ListView.java:682)
at android.widget.ListView.fillGap(ListView.java:628)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:2944)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2065)
at android.widget.ListView.onTouchEvent(ListView.java:3315)
at android.view.View.dispatchTouchEvent(View.java:3765)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:905)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1701)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1116)
at android.app.Activity.dispatchTouchEvent(Activity.java:2093)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1685)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1802)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4914)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)

Upvotes: 1

Views: 1215

Answers (1)

bigstones
bigstones

Reputation: 15267

Are you running the app on Android <=2.2? If yes, commit() implementation changed in 2.3 so that it's always executed in main thread (hence onSharedPreferenceChanged() too), but not in 2.2.

See this thread.

Upvotes: 1

Related Questions