android.support 如何破坏 Java 类型安全?
How does android.support break Javas type safety?
今天我遇到了一个非常奇怪的行为。我知道,我使用的是已弃用的 API,但尽管如此,根据我的理解,这应该是不可能的。
我有一个 android.preference.PreferenceActivity
,其中我通过 addPreferenceFromResource
放置了以下 xml:
<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>
请注意 SeekBarPreference
是一个 android.support.v7.preference.Preference
我给 xml 充气没问题。屏幕按预期显示。当我想获得对它的引用时,问题就来了:
PreferenceActivity.findPreference(key)
应该 return 一个 android.preference.Preference
class(SeekBarPreference
不是)。
但是此代码 return 是一个有效的 Pref:
Preference match_treshold = findPreference("match_treshold");
不允许我施放它:
if (match_treshold instanceof SeekBarPreference){}
因为
error: incompatible types: Preference cannot be converted to SeekBarPreference
但令人惊讶的是,如果我调试代码,我会得到这个
它指出,class 是 android.preference.SeekbarPreference
。如果我 google 那,我能找到的就是 https://developer.android.com/reference/android/support/v7/preference/SeekBarPreference
表示它基于 android.preference.SeekBarPreference
。但是我找不到这个具体的 class.
除了 - 在我看来 - 糟糕的设计决策,不继承 Android 的 support.v7 首选项:那到底是怎么回事?
编辑:
由于要求我 post 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
}
}
你需要添加
implementation 'com.android.support:preference-v7:28.0.0'
到 build.gradle 部门
您最终在 android.preference.PreferenceActivity
中得到的 SeekBarPreference
对象确实是 android.preference.SeekBarPreference
。这里的问题是 class 隐藏在 SDK (source) 中,因此 Android Studio 不会建议它自动完成,也不会自动导入它。由于您在项目中使用支持库,并且 SeekBarPreference
的支持版本是公开可用的,因此 class Android Studio 会尝试在那里使用,因此会发生冲突。
不幸的是,PreferenceActivity
不会检查首选项 XML 的来源,因此它会在看到 [=15= 时愉快地创建该平台 class 的实例] 标签。这可以说是一个错误,但我不确定他们会这么认为,因为文档中没有提到 class。
您可能仍然可以使用平台 SeekBarPreference
,因为它应该像任何其他基本的 Preference
一样工作,但如果您需要直接操作它可能会有点麻烦。但是,正如您所提到的,自己编写肯定是一种更可靠、更易于访问的解决方案。平台 class(上面链接)是一个相当简单的 Preference
subclass,因此您甚至可以将其复制到您的项目中,几乎是原样。相关布局 (here and here) 同样简单明了,不依赖于 SDK 中隐藏的任何其他内容。
今天我遇到了一个非常奇怪的行为。我知道,我使用的是已弃用的 API,但尽管如此,根据我的理解,这应该是不可能的。
我有一个 android.preference.PreferenceActivity
,其中我通过 addPreferenceFromResource
放置了以下 xml:
<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>
请注意 SeekBarPreference
是一个 android.support.v7.preference.Preference
我给 xml 充气没问题。屏幕按预期显示。当我想获得对它的引用时,问题就来了:
PreferenceActivity.findPreference(key)
应该 return 一个 android.preference.Preference
class(SeekBarPreference
不是)。
但是此代码 return 是一个有效的 Pref:
Preference match_treshold = findPreference("match_treshold");
不允许我施放它:
if (match_treshold instanceof SeekBarPreference){}
因为
error: incompatible types: Preference cannot be converted to SeekBarPreference
但令人惊讶的是,如果我调试代码,我会得到这个
它指出,class 是 android.preference.SeekbarPreference
。如果我 google 那,我能找到的就是 https://developer.android.com/reference/android/support/v7/preference/SeekBarPreference
表示它基于 android.preference.SeekBarPreference
。但是我找不到这个具体的 class.
除了 - 在我看来 - 糟糕的设计决策,不继承 Android 的 support.v7 首选项:那到底是怎么回事?
编辑: 由于要求我 post 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
}
}
你需要添加
implementation 'com.android.support:preference-v7:28.0.0'
到 build.gradle 部门
您最终在 android.preference.PreferenceActivity
中得到的 SeekBarPreference
对象确实是 android.preference.SeekBarPreference
。这里的问题是 class 隐藏在 SDK (source) 中,因此 Android Studio 不会建议它自动完成,也不会自动导入它。由于您在项目中使用支持库,并且 SeekBarPreference
的支持版本是公开可用的,因此 class Android Studio 会尝试在那里使用,因此会发生冲突。
不幸的是,PreferenceActivity
不会检查首选项 XML 的来源,因此它会在看到 [=15= 时愉快地创建该平台 class 的实例] 标签。这可以说是一个错误,但我不确定他们会这么认为,因为文档中没有提到 class。
您可能仍然可以使用平台 SeekBarPreference
,因为它应该像任何其他基本的 Preference
一样工作,但如果您需要直接操作它可能会有点麻烦。但是,正如您所提到的,自己编写肯定是一种更可靠、更易于访问的解决方案。平台 class(上面链接)是一个相当简单的 Preference
subclass,因此您甚至可以将其复制到您的项目中,几乎是原样。相关布局 (here and here) 同样简单明了,不依赖于 SDK 中隐藏的任何其他内容。