android.support如何破坏Java类型的安全性?

时间:2018-12-12 13:44:08

标签: android types android-appcompat preference

今天,我遇到了一个非常奇怪的行为。我知道,我正在使用不赞成使用的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>

请注意,SeekBarPreferenceandroid.support.v7.preference.Preference

我毫无疑问地将xml夸大了。屏幕显示预期。当我想获得对它的引用时就会出现问题:

PreferenceActivity.findPreference(key)应该返回一个android.preference.Preference类(而SeekBarPreference不是)。

但是此代码返回有效的Pref:

 Preference match_treshold = findPreference("match_treshold");

我不允许投放它:

 if (match_treshold instanceof SeekBarPreference){}

因为

  

错误:类型不兼容:首选项无法转换为SeekBarPreference

但是令人惊讶的是,如果我调试代码,我会得到 Debugging SeekBarPreference

它声明该类为android.preference.SeekbarPreference。如果我用谷歌搜索,我只能找到https://developer.android.com/reference/android/support/v7/preference/SeekBarPreference

表示它基于android.preference.SeekBarPreference。但是我找不到这个特定的班级。

-在我看来-糟糕的设计决策,不要继承自support.v7 Android的首选项:到底发生了什么?

编辑: 根据要求,我发布了Activity类

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
    }
}

您需要添加

  

实现'com.android.support:preference-v7:28.0.0'

到build.gradle部门

1 个答案:

答案 0 :(得分:1)

您最终在SeekBarPreference中使用的android.preference.PreferenceActivity对象确实是android.preference.SeekBarPreference。这里的问题是该类隐藏在SDK(source)中,因此Android Studio不会建议将其自动完成,也不会自动将其导入。由于您正在使用项目中的支持​​库,并且SeekBarPreference的支持版本是公开可用的,因此Android Studio将在此处尝试使用该类,从而产生冲突。

不幸的是,PreferenceActivity不会检查首选项XML的来源,因此只要看到<SeekBarPreference>标记,它将很高兴地创建该平台类的实例。可以说这是一个错误,但是我不确定他们是否会这样考虑,因为该类在文档中没有提到。

您可能仍可以使用平台SeekBarPreference,因为它应该像任何其他基本Preference一样工作,尽管如果您需要直接操作它可能会有些麻烦。但是,正如您所提到的,编写自己的书肯定是一个更可靠,更易于访问的解决方案。平台类(上面链接)是一个相当简单的Preference子类,因此您甚至可以将其照原样复制到项目中。相关布局(herehere)同样简单明了,并且不依赖于SDK中隐藏的其他任何内容。