環境設定を使用して設定アクティビティを作成するために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);
}
}
このメソッドは非推奨であるため、Androidの将来のバージョンで削除される可能性があるため、コードで使用しないことをお勧めします。ただし、Androidから実際に削除された非推奨のメソッドにはまだ遭遇していません。
(APIレベル11の時点で)推奨されるアプローチは、リソースファイルからプリファレンスをロードするために PreferenceFragment オブジェクトをインスタンス化することであるため、メソッドの説明には代替メソッドは提供されていません。こちらのサンプルコードを参照してください: PreferenceActivity
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()
}
preferenceThemeを指定
AppThemeに、見栄えが良いと思うテーマに応じて、次の設定テーマのいずれかを追加します。
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
推奨される実装では、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);
}
}
}
ラガブ・スードは正しいです。しかし、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;
}
};
}
このような方法で非推奨の警告が表示された場合:
addPreferencesFromResource(R.xml.default_values);
API 11以降ではこのようなメソッドが必要なため、PreferenceFragmentを使用する必要があります。
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.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>