web-dev-qa-db-ja.com

PreferenceActivity Android 4.0以前

Android 4.0のApiDemosでさまざまな設定アクティビティを試してみると、PreferencesFromCode.Javaで一部のメソッドが非推奨になっていることがコードでわかります。

だから私の質問は次のとおりです。PreferenceFragmentを使用する場合、すべてのバージョンで動作しますか、それとも3.0または4.0以降のみで動作しますか。

もしそうなら、それは2.2と2.3でも動作するものを使用する必要がありますか?

36
just_user

PreferenceFragmentは2.2および2.3では動作しません(APIレベル11以降のみ)。最高のユーザーエクスペリエンスを提供し、古いAndroid=バージョンを引き続きサポートする場合、ここでのベストプラクティスは、2つのPreferenceActivityクラスを実装し、どちらを実行するかを決定することですただし、このメソッドには非推奨のAPIの呼び出しが含まれていますが、それを避けることはできません。

したがって、たとえば、preference_headers.xml

<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android" > 
    <header Android:fragment="your.package.PrefsFragment" 
        Android:title="...">
        <extra Android:name="resource" Android:value="preferences" />
    </header>
</preference-headers>

および標準のpreferences.xml(APIレベルが低いため、あまり変更されていません):

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

次に、PreferenceFragmentの実装が必要です。

public static class PrefsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

最後に、PreferenceActivityをサポートするまたはサポートしないAPIレベルのために、PreferenceFragmentsの2つの実装が必要です。

public class PreferencesActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        addPreferencesFromResource(R.xml.other);
    }
}

そして:

public class OtherPreferencesActivity extends PreferenceActivity {
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }
}

設定画面をユーザーに表示する時点で、どちらを開始するかを決定します。

if (Build.VERSION.SDK_INT < 11) {
    startActivity(new Intent(this, PreferencesActivity.class));
} else {
    startActivity(new Intent(this, OtherPreferencesActivity.class));
}

したがって、基本的に、フラグメントごとにxmlファイルがあり、APIレベルが11未満の場合、これらの各xmlファイルを手動でロードし、両方のアクティビティで同じ設定を使用します。

59
Leo

@Mef PreferencesActivityとOtherPreferencesActivityの両方(2つのPrefsActivitiesがPITAである)が不要になるように、答えをさらに簡略化できます。

OnBuildHeaders()メソッドをPreferencesActivityに入れると、Android v11より前のバージョンでエラーがスローされないことがわかりました。 2.3.6で、しかしAndroid 1.6でした。しかし、いくつかのいじくり回した後、次のコードがすべてのバージョンで動作し、1つのアクティビティのみが必要であることがわかりました。

public class PreferencesActivity extends PreferenceActivity {
    protected Method mLoadHeaders = null;
    protected Method mHasHeaders = null;

    /**
     * Checks to see if using new v11+ way of handling PrefFragments.
     * @return Returns false pre-v11, else checks to see if using headers.
     */
    public boolean isNewV11Prefs() {
        if (mHasHeaders!=null && mLoadHeaders!=null) {
            try {
                return (Boolean)mHasHeaders.invoke(this);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
        }
        return false;
    }

    @Override
    public void onCreate(Bundle aSavedState) {
        //onBuildHeaders() will be called during super.onCreate()
        try {
            mLoadHeaders = getClass().getMethod("loadHeadersFromResource", int.class, List.class );
            mHasHeaders = getClass().getMethod("hasHeaders");
        } catch (NoSuchMethodException e) {
        }
        super.onCreate(aSavedState);
        if (!isNewV11Prefs()) {
            addPreferencesFromResource(R.xml.preferences);
            addPreferencesFromResource(R.xml.other);
        }
    }

    @Override
    public void onBuildHeaders(List<Header> aTarget) {
        try {
            mLoadHeaders.invoke(this,new Object[]{R.xml.pref_headers,aTarget});
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }   
    }
}

このように、1つのアクティビティ、AndroidManifest.xmlの1つのエントリ、および設定を呼び出すときに1行だけが必要です。

startActivity(new Intent(this, PreferencesActivity.class);

2013年10月の更新:Eclipse/Lintは非推奨のメソッドの使用について警告しますが、警告は無視してください。必要な場合にのみメソッドを使用します。これは、v11 +スタイルの設定がなく、使用する必要がある場合に使用します。これは問題ありません。廃止されたコードを説明しても怖がらないでください。Android廃止されたメソッドはすぐには削除されません。発生した場合、このクラスはもう必要ありません。推奨されないメカニズムは、最新のAPIバージョンで何かを処理するためのより良い方法があることを警告するためにありますが、それを考慮したら、その後の警告を安全に無視できます。廃止されたメソッドへのすべての呼び出しを削除すると、コードが新しいデバイスでのみ実行されるようになります。したがって、下位互換性の必要性はまったくなくなります。

18

newish lib が役立つかもしれません。

UnifiedPreferenceは、API v4以降のAndroid Preferenceパッケージのすべてのバージョンを操作するためのライブラリです。

6
scottyab

以前の回答の問題は、(addPreferenceFromResource()の複数の呼び出しにより)事前に設定されたデバイス上のすべての設定を1つの画面にスタックすることです。

リストとして最初の画面を必要とし、次に設定のある画面(設定ヘッダーの使用など)が必要な場合は、 互換性のある設定の公式ガイド

5
David Vávra

http://developer.Android.com/guide/topics/ui/settings.html#PreferenceHeaders から始めて、「古い「プリファレンスヘッダー付きのバージョン」を使用することをお勧めします。そこのガイドは非常に役立ち、うまく機能します。ガイドに続く明示的な例を次に示します。

だからファイルから始めます preference_header_legacy.xml for Android HoneyComb以前のシステム

<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android">
<Preference 
    Android:title="OLD Test Title"
    Android:summary="OLD Test Summary"  >
    <intent 
        Android:targetPackage="example.package"
        Android:targetClass="example.package.SettingsActivity"
        Android:action="example.package.PREFS_ONE" />
</Preference>

次にファイルを作成 preference_header.xml for Android HoneyComb +を搭載したシステム

<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header 
    Android:fragment="example.package.SettingsFragmentOne"
    Android:title="NEW Test Title"
    Android:summary="NEW Test Summary" />
</preference-headers>

次に作成 preferences.xml 設定を保持するファイル...

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android" >
        <CheckBoxPreference
        Android:key="pref_key_auto_delete"
        Android:summary="@string/pref_summary_auto_delete"
        Android:title="@string/pref_title_auto_delete"
        Android:defaultValue="false" />
</PreferenceScreen>

次にファイルを作成します SettingsActivity.Java

package example.project;
import Java.util.List;
import Android.annotation.SuppressLint;
import Android.os.Build;
import Android.os.Bundle;
import Android.preference.PreferenceActivity;

public class SettingsActivity extends PreferenceActivity{
final static String ACTION_PREFS_ONE = "example.package.PREFS_ONE";

@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    String action = getIntent().getAction();
    if (action != null && action.equals(ACTION_PREFS_ONE)) {
        addPreferencesFromResource(R.xml.preferences);
    }
    else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // Load the legacy preferences headers
        addPreferencesFromResource(R.xml.preference_header_legacy);
    }
}

@SuppressLint("NewApi")
@Override
public void onBuildHeaders(List<Header> target) {
    loadHeadersFromResource(R.xml.preference_header, target);
}
}

次にクラスを作成します SettingsFragmentOne.Java

package example.project;
import Android.annotation.SuppressLint;
import Android.os.Bundle;
import Android.preference.PreferenceFragment;

@SuppressLint("NewApi")
public class SettingsFragmentOne extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);
}
}

AndroidManifest.xml<application>タグの間にこのブロックを追加しました

<activity 
   Android:label="@string/app_name"
   Android:name="example.package.SettingsActivity"
   Android:exported="true">
</activity>

そして最後に、<wallpaper>タグについて...

<wallpaper xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:description="@string/description"
Android:thumbnail="@drawable/ic_thumbnail"
Android:settingsActivity="example.package.SettingsActivity"
/>
2
EnzoAtari

私は このライブラリ を使用していますが、これにはAARmavenCentralが含まれているため、Gradleを使用している場合は簡単に含めることができます。

compile 'com.github.machinarius:preferencefragment:0.1.1'

1
theblang