有关PreferenceActivity的Android弃用方法警告

时间:2013-02-07 16:49:05

标签: android sharedpreferences deprecated android-preferences preferenceactivity

当我尝试按照Android的开发人员指南和教程使用“偏好设置”创建“设置活动”时,我收到警告,例如:

“不推荐使用PreferenceActivity类型的方法addPreferencesFromResource(int)”

代码中的这两行:

getPreferenceManager().setSharedPreferencesName(PREFS_NAME);
addPreferencesFromResource(R.xml.default_values);

我知道这些只是警告,但是当我运行我正在设计的应用程序时,我想知道它们现在或将来是否会引起任何问题。

public class DefaultValues extends PreferenceActivity {

    static final String PREFS_NAME = "defaults";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getPrefs(this);
        getPreferenceManager().setSharedPreferencesName(PREFS_NAME);
        addPreferencesFromResource(R.xml.default_values);
    }

    static SharedPreferences getPrefs(Context context) {
        PreferenceManager.setDefaultValues(context, PREFS_NAME, MODE_PRIVATE,
                R.xml.default_values, false);
        return context.getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
    }
}

5 个答案:

答案 0 :(得分:15)

PreferenceActivity()已过时,但PreferenceFragment()也已过时。 PreferenceFragmentCompat()现在是解决方法:

添加依赖项

implementation "androidx.preference:preference:1.0.0-alpha3"

或者如果您仍在使用支持库:

implementation "com.android.support:preference-v7:27.1.1"

扩展PreferenceFragmentCompat

class MyPreferenceFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.app_preferences)
    }
}

显示您的片段

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    supportFragmentManager.beginTransaction().replace(android.R.id.content, MyPreferenceFragment()).commit()
}

指定首选项主题

在您的AppTheme中,添加以下两个偏好主题之一,具体取决于您认为哪个主题更好:

<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>

答案 1 :(得分:7)

由于该方法已弃用,建议您不要在代码中使用它,因为完全有可能在未来的Android版本中将其删除。但是,我还没有遇到过已经从Android中删除的已弃用的方法。

方法描述中没有提供替代方法,因为首选方法(从API级别11开始)是实例化PreferenceFragment个对象以从资源文件加载首选项。请在此处查看示例代码:PreferenceActivity

答案 2 :(得分:1)

Raghav Sood是对的。但是如果你需要PreferenceFragment坏(我需要在标签中)你可以使用它。但它可以在将来制动,以便更好地将它用于旧的api。 这是我用SupportLibrary和反射做的一点修饰的PreferenceFragment。

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.app.Fragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnKeyListener;
import android.widget.ListView;

@SuppressLint("HandlerLeak")
public abstract class PreferenceFragment
        extends Fragment
{

    private static final String PREFERENCES_TAG = "android:preferences";

    private PreferenceManager mPreferenceManager;
    private ListView mList;
    private boolean viewCreated;
    // private boolean mHavePrefs;
    // private boolean mInitDone;

    /**
     * The starting request code given out to preference framework.
     */
    private static final int FIRST_REQUEST_CODE = 100;

    private static final int MSG_BIND_PREFERENCES = 1;
    private final Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what) {

            case MSG_BIND_PREFERENCES:
                if (viewCreated) {
                    bindPreferences();
                }
                break;
            }
        }
    };

    private final Runnable mRequestFocus = new Runnable()
    {
        @Override
        public void run()
        {
            mList.focusableViewAvailable(mList);
        }
    };

    /**
     * Interface that PreferenceFragment's containing activity should implement
     * to be able to process preference items that wish to switch to a new
     * fragment.
     */
    public interface OnPreferenceStartFragmentCallback
    {
        /**
         * Called when the user has clicked on a Preference that has a fragment
         * class name associated with it. The implementation to should
         * instantiate and switch to an instance of the given fragment.
         */
        boolean onPreferenceStartFragment(PreferenceFragment caller,
                Preference pref);
    }

    @SuppressLint("NewApi")
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        try {
            Constructor<?> constructor = PreferenceManager.class
                    .getDeclaredConstructor(Activity.class, int.class);
            constructor.setAccessible(true);
            mPreferenceManager = (PreferenceManager) constructor.newInstance(
                    getActivity(), FIRST_REQUEST_CODE);
        } catch (Throwable e) {
            throw new RuntimeException(
                    "Could not instantiate PreferenceManager: "
                            + e.getMessage());
        }

    }

    @Override
    public final View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.activity_preferences, null);
        this.viewCreated = true;
        return v;
    }

    // @Override
    // public View onCreateView(LayoutInflater inflater, ViewGroup container,
    // Bundle savedInstanceState) {
    // return inflater.inflate(R.layout.preference_list_fragment, container,
    // false);
    // }

    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);

        // if (mHavePrefs) {
        bindPreferences();
        // }

        // mInitDone = true;

        if (savedInstanceState != null) {
            Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
            if (container != null) {
                final PreferenceScreen preferenceScreen = getPreferenceScreen();
                if (preferenceScreen != null) {
                    preferenceScreen.restoreHierarchyState(container);
                }
            }
        }
    }

    // @Override
    // public void onStart() {
    // super.onStart();
    // IllegalAccessException
    // try {
    // Method m = PreferenceManager.class
    // .getDeclaredMethod("setOnPreferenceTreeClickListener",
    // Class.forName("android.preference.PreferenceManager$OnPreferenceTreeClickListener"));
    // m.invoke(mPreferenceManager, this);
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // mPreferenceManager.setOnPreferenceTreeClickListener(this);
    // }

    @Override
    public void onStop()
    {
        super.onStop();
        try {
            Method m = PreferenceManager.class
                    .getDeclaredMethod("dispatchActivityStop");
            m.setAccessible(true);
            m.invoke(mPreferenceManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // IllegalAccessException
        // try {
        // Method m = PreferenceManager.class
        // .getDeclaredMethod("setOnPreferenceTreeClickListener",
        // Class.forName("android.preference.PreferenceManager$OnPreferenceTreeClickListener"));
        // m.invoke(mPreferenceManager, (Object) null);
        // } catch (Exception e) {
        // e.printStackTrace();
        // }
        // mPreferenceManager.setOnPreferenceTreeClickListener(null);
    }

    @Override
    public void onDestroyView()
    {
        this.viewCreated = false;
        mList = null;
        mHandler.removeCallbacks(mRequestFocus);
        mHandler.removeMessages(MSG_BIND_PREFERENCES);
        super.onDestroyView();
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        try {
            Method m = PreferenceManager.class
                    .getDeclaredMethod("dispatchActivityDestroy");
            m.setAccessible(true);
            m.invoke(mPreferenceManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);

        final PreferenceScreen preferenceScreen = getPreferenceScreen();
        if (preferenceScreen != null) {
            Bundle container = new Bundle();
            preferenceScreen.saveHierarchyState(container);
            outState.putBundle(PREFERENCES_TAG, container);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);

        try {
            Method m = PreferenceManager.class.getDeclaredMethod(
                    "dispatchActivityResult", int.class, int.class,
                    Intent.class);
            m.setAccessible(true);
            m.invoke(mPreferenceManager, requestCode, resultCode, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns the {@link PreferenceManager} used by this fragment.
     * 
     * @return The {@link PreferenceManager}.
     */
    public PreferenceManager getPreferenceManager()
    {
        return mPreferenceManager;
    }

    /**
     * Sets the root of the preference hierarchy that this fragment is showing.
     * 
     * @param preferenceScreen
     *            The root {@link PreferenceScreen} of the preference hierarchy.
     */
    public void setPreferenceScreen(PreferenceScreen preferenceScreen)
    {
        try {
            Method m = PreferenceManager.class.getDeclaredMethod(
                    "setPreferences", PreferenceScreen.class);
            m.setAccessible(true);
            boolean result = (Boolean) m.invoke(mPreferenceManager,
                    preferenceScreen);
            if (result && preferenceScreen != null) {
                postBindPreferences();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Gets the root of the preference hierarchy that this fragment is showing.
     * 
     * @return The {@link PreferenceScreen} that is the root of the preference
     *         hierarchy.
     */
    public PreferenceScreen getPreferenceScreen()
    {
        try {
            Method m = PreferenceManager.class
                    .getDeclaredMethod("getPreferenceScreen");
            m.setAccessible(true);
            return (PreferenceScreen) m.invoke(mPreferenceManager);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Adds preferences from activities that match the given {@link Intent}.
     * 
     * @param intent
     *            The {@link Intent} to query activities.
     */
    public void addPreferencesFromIntent(Intent intent)
    {
        requirePreferenceManager();
        try {
            Method m = PreferenceManager.class
                    .getDeclaredMethod("inflateFromIntent");
            m.setAccessible(true);
            PreferenceScreen ps = (PreferenceScreen) m.invoke(
                    mPreferenceManager, intent, getPreferenceScreen());
            setPreferenceScreen(ps);
        } catch (Throwable e) {

        }
    }

    /**
     * Inflates the given XML resource and adds the preference hierarchy to the
     * current preference hierarchy.
     * 
     * @param preferencesResId
     *            The XML resource ID to inflate.
     */
    public void addPreferencesFromResource(int preferencesResId)
    {
        requirePreferenceManager();

        try {
            Method m = PreferenceManager.class.getDeclaredMethod(
                    "inflateFromResource", Context.class, int.class,
                    PreferenceScreen.class);
            m.setAccessible(true);
            PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(
                    mPreferenceManager, getActivity(), preferencesResId,
                    getPreferenceScreen());
            setPreferenceScreen(prefScreen);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
            Preference preference)
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            try {
                Method m = Preference.class.getDeclaredMethod("getFragment");
                Object o = m.invoke(preference);
                if (o != null
                        && getActivity() instanceof OnPreferenceStartFragmentCallback) {
                    return ((OnPreferenceStartFragmentCallback) getActivity())
                            .onPreferenceStartFragment(this, preference);
                }
            } catch (Throwable e) {
            }
        }
        return false;
    }

    /**
     * Finds a {@link Preference} based on its key.
     * 
     * @param key
     *            The key of the preference to retrieve.
     * @return The {@link Preference} with the key, or null.
     * @see PreferenceGroup#findPreference(CharSequence)
     */
    public Preference findPreference(CharSequence key)
    {
        if (mPreferenceManager == null) {
            return null;
        }
        return mPreferenceManager.findPreference(key);
    }

    private void requirePreferenceManager()
    {
        if (mPreferenceManager == null) {
            throw new RuntimeException(
                    "This should be called after super.onCreate.");
        }
    }

    private void postBindPreferences()
    {
        if (mHandler.hasMessages(MSG_BIND_PREFERENCES))
            return;
        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
    }

    private void bindPreferences()
    {
        final PreferenceScreen preferenceScreen = getPreferenceScreen();
        if (preferenceScreen != null) {
            preferenceScreen.bind(getListView());
        }
    }

    /** @hide */
    public ListView getListView()
    {
        ensureList();
        return mList;
    }

    private void ensureList()
    {
        if (mList != null) {
            return;
        }
        View root = getView();
        if (root == null) {
            throw new IllegalStateException("Content view not yet created");
        }
        View rawListView = root.findViewById(android.R.id.list);
        if (!(rawListView instanceof ListView)) {
            throw new RuntimeException(
                    "Content has view with id attribute 'android.R.id.list' "
                            + "that is not a ListView class");
        }
        mList = (ListView) rawListView;
        if (mList == null) {
            throw new RuntimeException(
                    "Your content must have a ListView whose id attribute is "
                            + "'android.R.id.list'");
        }
        mList.setOnKeyListener(mListOnKeyListener);
        mHandler.post(mRequestFocus);
    }

    private OnKeyListener mListOnKeyListener = new OnKeyListener()
    {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event)
        {
            Object selectedItem = mList.getSelectedItem();
            if (selectedItem instanceof Preference) {
                View selectedView = mList.getSelectedView();
                Preference p = (Preference) selectedItem;
                try {
                    Method m = Preference.class.getDeclaredMethod("onKey",
                            View.class, int.class, KeyEvent.class);
                    m.setAccessible(true);
                    boolean result = (Boolean) m.invoke(p, selectedView,
                            keyCode, event);
                    return result;
                } catch (Throwable e) {
                }
            }
            return false;
        }

    };
}

答案 3 :(得分:1)

首选实现现在使用Fragment s。以下内容适用:

public class DefaultValues extends Activity {

    static final String PREFS_NAME = "defaults";    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Display the fragment as the main content.
        if (savedInstanceState == null)
            getFragmentManager().beginTransaction().add(android.R.id.content, new PrefFragment()).commit();
    }

    public static class PrefFragment extends PreferenceFragment
    {
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);

            getPreferenceManager().setSharedPreferencesName(PREFS_NAME);
            addPreferencesFromResource(R.xml.default_values);
        }
    }
}

答案 4 :(得分:0)

如果您遇到来自以下方法的弃用警告:

addPreferencesFromResource(R.xml.default_values);

您必须使用PreferenceFragment,因为API 11及更高版本需要这样的方法。

以下是如何使用PreferenceFragment的示例:

1.创建/res/xml/preferences.xml以定义我们的首选项。

 <PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

<PreferenceCategory
        android:title="PreferenceCategory A">

    <CheckBoxPreference
            android:key="checkbox_preference"
            android:title="title_checkbox_preference"
            android:summary="summary_checkbox_preference" />

</PreferenceCategory>

<PreferenceCategory
        android:title="PreferenceCategory B">

    <EditTextPreference
            android:key="edittext_preference"
            android:title="title_edittext_preference"
            android:summary="summary_edittext_preference"
            android:dialogTitle="dialog_title_edittext_preference" />

</PreferenceCategory>

2.Create PrefsFragment.java将PreferenceFragment扩展为addPreferencesFromResource。

   package com.example.androidpreferencefragment;

   import android.os.Bundle;
   import android.preference.PreferenceFragment;

   public class PrefsFragment extends PreferenceFragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);

   // Load the preferences from an XML resource
    addPreferencesFromResource(R.xml.preferences);
   }

 }

3.创建SetPreferenceActivity.java以加载PrefsFragment。

package com.example.androidpreferencefragment;

import android.app.Activity;
import android.os.Bundle;

public class SetPreferenceActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);

  getFragmentManager().beginTransaction().replace(android.R.id.content,
                new PrefsFragment()).commit();
 }

}

4.修改主要布局/res/layout/activity_main.xml,以显示首选项。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="@dimen/padding_medium"
    android:text="@string/hello_world"
    tools:context=".MainActivity" />

<CheckBox
    android:id="@+id/prefCheckBox"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="CheckBoxPreference" />

<TextView
    android:id="@+id/prefEditText"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

</LinearLayout>

5.主要活动,MainActivity.java。

package com.example.androidpreferencefragment;

import android.os.Bundle;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.TextView;

public class MainActivity extends Activity {

 CheckBox prefCheckBox;
 TextView prefEditText;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    prefCheckBox = (CheckBox)findViewById(R.id.prefCheckBox);
 prefEditText = (TextView)findViewById(R.id.prefEditText);

 loadPref();
}

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {

  /*
   * Because it's onlt ONE option in the menu.
   * In order to make it simple, We always start SetPreferenceActivity
   * without checking.
   */

  Intent intent = new Intent();
    intent.setClass(MainActivity.this, SetPreferenceActivity.class);
    startActivityForResult(intent, 0); 

    return true;
 }

  @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  // TODO Auto-generated method stub
  //super.onActivityResult(requestCode, resultCode, data);

  /*
   * To make it simple, always re-load Preference setting.
   */

  loadPref();
 }

 private void loadPref(){
  SharedPreferences mySharedPreferences =        PreferenceManager.getDefaultSharedPreferences(this);

  boolean my_checkbox_preference = mySharedPreferences.getBoolean("checkbox_preference", false);
  prefCheckBox.setChecked(my_checkbox_preference);

  String my_edittext_preference = mySharedPreferences.getString("edittext_preference", "");
  prefEditText.setText(my_edittext_preference);

 }

}

5.最后,修改AndroidManifest.xml以添加SetPreferenceActivity。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidpreferencefragment"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="15" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/title_activity_main" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".SetPreferenceActivity"
        android:label="@string/title_activity_main" >
    </activity>
</application>