Today i encountered a very strange behavior. I know, I'm using deprecated APIs but nonetheless, this should not be possible from my understanding.
I have a android.preference.PreferenceActivity
in which I put the following xml via addPreferenceFromResource
:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
android:id="@+id/et_server_endpoint"
android:key="server_endpoint"
android:hint="http://192.168.100.42:8080"
android:title="Server Endpoint"
android:summary="Sets the Server Endpoint for the search"
android:dialogTitle="Server Endpoint Settings"
android:dialogMessage="Set the Servers endpoint"
/>
<SeekBarPreference
android:id="@+id/sb_phone_threshold"
android:key="match_treshold"
android:title="Matching Threshold"
android:summary="Sets the minimum Score for matches"
android:defaultValue="60"
android:min="40"
android:max="90"
app:adjustable="true"
app:showSeekBarValue="true"/>
</PreferenceScreen>
Note that SeekBarPreference
is an android.support.v7.preference.Preference
I have no problem inflating the xml. The Screen shows as expected. The problem comes when I want to get a reference to it:
PreferenceActivity.findPreference(key)
is supposed to return an android.preference.Preference
class (which the SeekBarPreference
is not).
but this code returns a valid Pref:
Preference match_treshold = findPreference("match_treshold");
I'm not allowed to cast it:
if (match_treshold instanceof SeekBarPreference){}
because of
error: incompatible types: Preference cannot be converted to SeekBarPreference
But surprisingly, if I debug the code I get this
It states, that the class is android.preference.SeekbarPreference
. If I google that, all I can find is https://developer.android.com/reference/android/support/v7/preference/SeekBarPreference
which states that it's based on android.preference.SeekBarPreference
. But I cannot find this specific class.
Beside the - from my point of view - poor design decision, to not inherit support.v7 Preferences from the Android ones: What the hell is going on there?
EDIT: Due to request I post the Activity class
package com.my.company.domain.namespace;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.preference.SeekBarPreference;
import android.util.Log;
public class PrefActivity extends PreferenceActivity {
private SharedPreferences mPrefs;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
addPreferencesFromResource(R.xml.glass_prefs);
Preference matchTreshold = findPreference("match_treshold");
// code doesn't compile
// if (match_treshold instanceof SeekBarPreference){}
Log.d("Pref", "onCreate: SeekBarClass=" + matchTreshold.getClass().getName());
//prints 'android.preference.SeekBarPreference'
//one cannot import android.preference.SeekBarPreference
}
}
you need to add
implementation 'com.android.support:preference-v7:28.0.0'
to the build.gradle deps
The SeekBarPreference
object that you end up with in an android.preference.PreferenceActivity
is indeed an android.preference.SeekBarPreference
. The issue here is that that class is hidden in the SDK (source), so Android Studio will not suggest it for auto-completion, nor will it import it automatically. Since you're using the support libraries in your project, and the support version of SeekBarPreference
is publicly available, that will be the class Android Studio tries to use there, thus the conflict.
Unfortunately, PreferenceActivity
does not check from where the preference XML is coming, so it will happily create an instance of that platform class whenever it sees a <SeekBarPreference>
tag. This is arguably a bug, but I'm not sure they'd consider it so, as that class is nowhere mentioned in the documentation.
You possibly could still use the platform SeekBarPreference
, as it should work like any other basic Preference
, though it might get a little hairy if you need to manipulate it directly. However, writing your own, as you've mentioned, is certainly a more solid, accessible solution. The platform class (linked above) is a rather simple Preference
subclass, so you could even just copy that out into your project, almost as is. The relevant layouts (here and here) are similarly straightforward, and don't rely on anything else hidden from the SDK.