isValidFragment Android API 19
当我使用Android KitKat尝试我的应用程序时,我在PreferenceActivity中出错 PreferenceActivity的子类必须重写isValidFragment(String),以验证Fragment类是否有效!com.crbin1.labeltodo.ActivityReference未检查片段com.crbin1.labeltodo.StockPreferenceFragment是否有效 在文档中,我找到了以下解释 受保护的布尔值isValidFragment(字符串碎片名称) 在API级别19中添加 子类应重写此方法,并验证给定片段是否是要附加到此活动的有效类型。对于为早于KITKAT的android:targetSdkVersion构建的应用程序,默认实现返回true。对于更高版本,它将抛出异常isValidFragment Android API 19,android,android-fragments,android-4.4-kitkat,Android,Android Fragments,Android 4.4 Kitkat,当我使用Android KitKat尝试我的应用程序时,我在PreferenceActivity中出错 PreferenceActivity的子类必须重写isValidFragment(String),以验证Fragment类是否有效!com.crbin1.labeltodo.ActivityReference未检查片段com.crbin1.labeltodo.StockPreferenceFragment是否有效 在文档中,我找到了以下解释 受保护的布尔值isValidFragment(字符串
我找不到任何解决问题的示例。试试这个。。。这就是我们检查片段有效性的方法
protected boolean isValidFragment(String fragmentName) {
return StockPreferenceFragment.class.getName().equals(fragmentName);
}
使用实际的4.4设备进行验证: (1) 如果proguard.cfg文件包含以下行(): (2) 而最有效的实施方式是:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class EditPreferencesHC extends PreferenceActivity {
...
protected boolean isValidFragment (String fragmentName) {
return "com.fullpackage.MyPreferenceFragment".equals(fragmentName);
}
}
出于好奇,您也可以这样做:
@Override
protected boolean isValidFragment(String fragmentName) {
return MyPreferenceFragmentA.class.getName().equals(fragmentName)
|| MyPreferenceFragmentB.class.getName().equals(fragmentName)
|| // ... Finish with your last fragment.
;}
此API是由于新发现的漏洞而添加的。请看或 2013年12月10日 “我们最近向Android安全团队披露了一个新的漏洞。[…]更准确地说,任何使用导出的活动扩展PreferenceActivity类的应用程序都会自动受到攻击。Android KitKat中提供了一个修补程序。如果您想知道为什么代码现在会被破坏,那是因为Android KitKat修补程序要求应用程序覆盖新方法PreferenceActivity.isValidFragment、 已经添加到Android框架中。”——来自上面的第一个链接
我发现可以在加载时从标题资源中获取片段名称的副本:
public class MyActivity extends PreferenceActivity
{
private static List<String> fragments = new ArrayList<String>();
@Override
public void onBuildHeaders(List<Header> target)
{
loadHeadersFromResource(R.xml.headers,target);
fragments.clear();
for (Header header : target) {
fragments.add(header.fragment);
}
}
...
@Override
protected boolean isValidFragment(String fragmentName)
{
return fragments.contains(fragmentName);
}
}
公共类MyActivity扩展了PreferenceActivity
{
私有静态列表片段=新的ArrayList();
@凌驾
public void onBuildHeaders(列表目标)
{
loadHeadersFromResource(R.xml.headers,目标);
片段。清除();
用于(标题:目标){
添加(header.fragment);
}
}
...
@凌驾
受保护的布尔值isValidFragment(字符串碎片名称)
{
返回fragments.contains(fragmentName);
}
}
这样,如果我想更新代码中的片段列表,我就不需要记住更新它们
我本来希望直接使用getHeaders()
和现有的头列表,但似乎在调用isValidFragment()
之前,活动在onBuildHeaders()
之后被销毁并重新创建
这可能是因为我正在测试的Nexus7实际上没有进行两个窗格的首选项活动。因此也需要静态列表成员。我不确定lane的实现是否没有讨论过的漏洞,但如果没有,那么我认为更好的解决方案是避免使用该静态列表,只需执行以下操作:
@Override
protected boolean isValidFragment(String fragmentName)
{
ArrayList<Header> target = new ArrayList<>();
loadHeadersFromResource(R.xml.pref_headers, target);
for (Header h : target) {
if (fragmentName.equals(h.fragment)) return true;
}
return false;
}
@覆盖
受保护的布尔值isValidFragment(字符串碎片名称)
{
ArrayList target=新的ArrayList();
loadHeadersFromResource(R.xml.pref_头,目标);
用于(标题h:目标){
if(fragmentName.equals(h.fragment))返回true;
}
返回false;
}
这是我的解决方案:
- 如果你需要动态重建头
- 如果您使用extras启动首选项活动-onBuildHeaders()方法将失败!(使用以下启动意图附加项-为什么?-很简单,因为从未调用onBuildHeaders()): Intent.putExtra(PreferenceActivity.EXTRA\u SHOW\u FRAGMEN,Fragment.class.getName()); Intent.putExtra(PreferenceActivity.EXTRA\u无\u头,true)
/**
* Preference Header for showing settings and add view as two panels for tablets
* for ActionBar we need override onCreate and setContentView
*/
public class SettingsPreferenceActivity extends PreferenceActivity {
/** valid fragment list declaration */
private List<String> validFragmentList;
/** some example irrelevant class for holding user session */
SessionManager _sessionManager;
@Override
public void onBuildHeaders(List<Header> target) {
/** load header from res */
loadHeadersFromResource(getValidResId(), target);
}
/**
* this API method was added due to a newly discovered vulnerability.
*/
@Override
protected boolean isValidFragment(String fragmentName) {
List<Header> headers = new ArrayList<>();
/** fill fragments list */
tryObtainValidFragmentList(getValidResId(), headers);
/** check id valid */
return validFragmentList.contains(fragmentName);
}
/** try fill list of valid fragments */
private void tryObtainValidFragmentList(int resourceId, List<Header> target) {
/** check for null */
if(validFragmentList==null) {
/** init */
validFragmentList = new ArrayList();
} else {
/** clear */
validFragmentList.clear();
}
/** load headers to list */
loadHeadersFromResource(resourceId, target);
/** set headers class names to list */
for (Header header : target) {
/** fill */
validFragmentList.add(header.fragment);
}
}
/** obtain valid res id to build headers */
private int getValidResId() {
/** get session manager */
_sessionManager = SessionManager.getInstance();
/** check if user is authorized */
if (_sessionManager.getCurrentUser().getWebPart().isAuthorized()) {
/** if is return full preferences header */
return R.xml.settings_preferences_header_logged_in;
} else {
/** else return short header */
return R.xml.settings_preferences_header_logged_out;
}
}
}
/**
*首选项标题,用于将设置和添加视图显示为平板电脑的两个面板
*对于ActionBar,我们需要覆盖onCreate和setContentView
*/
公共类设置PreferenceActivity扩展了PreferenceActivity{
/**有效的片段列表声明*/
私有列表validFragmentList;
/**用于举行用户会话的一些示例无关类*/
SessionManager_SessionManager;
@凌驾
public void onBuildHeaders(列表目标){
/**从res加载标题*/
loadHeadersFromResource(getValidResId(),目标);
}
/**
*由于新发现的漏洞,添加了此API方法。
*/
@凌驾
受保护的布尔值isValidFragment(字符串碎片名称){
列表标题=新建ArrayList();
/**填充碎片列表*/
tryObtainValidFragmentList(getValidResId(),标头);
/**检查id是否有效*/
返回validFragmentList.contains(fragmentName);
}
/**尝试填充有效片段的列表*/
私有void tryObtainValidFragmentList(int-resourceId,List-target){
/**检查空值*/
if(validFragmentList==null){
/**初始化*/
validFragmentList=新的ArrayList();
}否则{
/**清楚的*/
validFragmentList.clear();
}
/**将标题加载到列表*/
loadHeadersFromResource(资源ID,目标);
/**将标题类名称设置为列表*/
用于(标题:目标){
/**填满*/
validFragmentList.add(header.fragment);
}
}
/**获取有效的res id以生成标头*/
私有int getValidResId(){
/**获取会话管理器*/
_sessionManager=sessionManager.getInstance();
/**检查用户是否被授权*/
if(_sessionManager.getCurrentUser().getWebPart().isAuthorized()){
/**如果是返回完整首选项标题*/
返回R.xml.settings\u preferences\u header\u logged\u;
}否则{
/**否则返回短标题*/
返回R.xml.settings\u preferences\u header\u logged\u;
}
}
}
以下是
/**
* Preference Header for showing settings and add view as two panels for tablets
* for ActionBar we need override onCreate and setContentView
*/
public class SettingsPreferenceActivity extends PreferenceActivity {
/** valid fragment list declaration */
private List<String> validFragmentList;
/** some example irrelevant class for holding user session */
SessionManager _sessionManager;
@Override
public void onBuildHeaders(List<Header> target) {
/** load header from res */
loadHeadersFromResource(getValidResId(), target);
}
/**
* this API method was added due to a newly discovered vulnerability.
*/
@Override
protected boolean isValidFragment(String fragmentName) {
List<Header> headers = new ArrayList<>();
/** fill fragments list */
tryObtainValidFragmentList(getValidResId(), headers);
/** check id valid */
return validFragmentList.contains(fragmentName);
}
/** try fill list of valid fragments */
private void tryObtainValidFragmentList(int resourceId, List<Header> target) {
/** check for null */
if(validFragmentList==null) {
/** init */
validFragmentList = new ArrayList();
} else {
/** clear */
validFragmentList.clear();
}
/** load headers to list */
loadHeadersFromResource(resourceId, target);
/** set headers class names to list */
for (Header header : target) {
/** fill */
validFragmentList.add(header.fragment);
}
}
/** obtain valid res id to build headers */
private int getValidResId() {
/** get session manager */
_sessionManager = SessionManager.getInstance();
/** check if user is authorized */
if (_sessionManager.getCurrentUser().getWebPart().isAuthorized()) {
/** if is return full preferences header */
return R.xml.settings_preferences_header_logged_in;
} else {
/** else return short header */
return R.xml.settings_preferences_header_logged_out;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<preference-headers
xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs1Fragment"
android:title="Change Your Name" />
<header
android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs2Fragment"
android:title="Change Your Group''s Name" />
<header
android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs3Fragment"
android:title="Change Map View" />
</preference-headers>
@Override
protected boolean isValidFragment(String fragmentName)
{
// return AppPreferencesFragment.class.getName().contains(fragmentName);
return fragmentName.contains (AppPreferencesFragment.class.getName());
}
@Override
protected boolean isValidFragment(String fragmentName) {
try {
Class cls = Class.forName(fragmentName);
return (cls.getSuperclass().equals(PreferenceFragment.class));
// true if superclass is PreferenceFragmnet
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return false;
}
@Override
protected boolean isValidFragment (String fragmentName) {
for (Class<?> cls : ImePreferences.class.getDeclaredClasses()) {
if (cls.getName().equals(fragmentName)){return true;}
}
return false;
}