Apa yang harus digunakan daripada “addPreferencesFromResource” di PreferenceActivity?

360

Saya hanya memperhatikan fakta bahwa metode addPreferencesFromResource(int preferencesResId)ini ditandai tidak digunakan lagi dalam dokumentasi Android ( Entri Referensi ).

Sayangnya, tidak ada metode alternatif yang disediakan dalam deskripsi metode ini.

Metode mana yang harus digunakan sebagai gantinya untuk menghubungkan preferensiScreen.xml ke PreferenceActivity yang cocok?

mweisz
sumber
2
Pendekatan yang sangat mudah disediakan oleh WannaGetHigh di stackoverflow.com/questions/23523806/…
Sabin
Solusinya masih ada gunakan addPreferencesFromResource(int preferencesResId). Apakah saya melewatkan sesuatu?
Jammo
@Jammo Ya tetapi telah dipindahkan dari Aktivitas ke Fragmen untuk mencerminkan cara baru melakukannya -> fragmen.
MauTinggiTinggi

Jawaban:

332

Tidak ada metode alternatif yang disediakan dalam deskripsi metode karena pendekatan yang disukai (pada API level 11) adalah untuk instantiate objek PreferenceFragment untuk memuat preferensi Anda dari file sumber daya. Lihat contoh kode di sini: PreferenceActivity

Hacker dimuliakan
sumber
Terimakasih banyak atas jawaban Anda. Saya hanya mengikuti instruksi usang dari "Video2Brain-Android Development" yang mengarahkan saya untuk menggunakan versi metode PreferenceActivity. Btw: Saya ingin menilai jawaban Anda bermanfaat jika saya hanya bisa.
mweisz
33
Sekarang hanya jika PreferenceFragment dimasukkan dalam paket kompatibilitas, masuk akal untuk menggunakannya stackoverflow.com/questions/5501431/...
christoff
1
Karena saya menggunakan Action Bar Sherlock, saya mengikuti blog berikut untuk menyelesaikan masalah ini, lihat ... commonsware.com/blog/2012/10/16/
Seseorang di suatu tempat
2
Masih Anda perlu memanggil addPreferencesFromResource (int PreferencesID) jika Anda ingin aplikasi kompatibel dengan tingkat api lebih awal dari 11 (Android 3.0). Tapi saya kira Anda dapat mempertimbangkan perangkat lama itu juga sudah tidak berlaku lagi.
Einar Sundgren
5
@EinarSundgren Saya pemilik Nexus One dan versi maks saya yang tersedia adalah 2.2: Anda tidak akan menghentikan saya! Saya TIDAK AKAN PERNAH ditinggalkan! Dengan Kekuatan Grayskull ... Saya Memiliki Kekuatan!
TechNyquist
186

Untuk menambahkan lebih banyak informasi ke jawaban yang benar di atas, setelah membaca contoh dari Android-er saya menemukan Anda dapat dengan mudah mengubah aktivitas preferensi Anda menjadi fragmen preferensi. Jika Anda memiliki aktivitas berikut:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.my_preference_screen);
    }
}

Satu-satunya perubahan yang harus Anda lakukan adalah membuat kelas fragmen internal, memindahkannya addPreferencesFromResources()ke fragmen, dan meminta fragmen dari aktivitas, seperti ini:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
    }

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

Mungkin ada seluk-beluk lain untuk membuat preferensi yang lebih kompleks dari fragmen; jika demikian, saya harap seseorang mencatatnya di sini.

Garret Wilson
sumber
6
Bagus, terima kasih untuk ini. Java dan jenis pemikiran ini sejauh ini dihapus dari dunia .net kecilku yang menyenangkan :)
Tom
44
Mengapa mereka terdepresiasi addPreferencesFromResources()dalam perdagangan untuk PreferenceFragment? Tampaknya tidak perlu dari sudut pandang pemula.
Howdy_McGee
4
Panggilan membutuhkan API level 11
mehmet
1
jadi bagaimana jika API ada di Level 9? @mehmet
gumuruh
2
Jawaban yang luar biasa! apakah ada cara untuk mencapai ini tanpa mengubah android.R.id.content? tampaknya tidak cocok bagi saya untuk beberapa alasan ... (koreksi saya jika saya salah)
tomer.z
37

@ Garret Wilson Terima kasih banyak! Sebagai noob untuk pengkodean android, saya telah terjebak dengan masalah ketidakcocokan preferensi selama berjam-jam, dan saya merasa sangat mengecewakan mereka mencela penggunaan beberapa metode / pendekatan untuk yang baru yang tidak didukung oleh API yang lebih lama sehingga harus menggunakan segala macam solusi untuk membuat aplikasi Anda berfungsi dalam berbagai perangkat. Benar-benar membuat frustrasi!

Kelas Anda sangat bagus, karena memungkinkan Anda untuk tetap bekerja di API baru dengan preferensi seperti dulu, tetapi tidak kompatibel ke belakang. Karena saya mencoba menjangkau berbagai perangkat, saya bermain-main sedikit untuk membuatnya berfungsi di pra-API 11 perangkat serta di API yang lebih baru:

import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

public class MyPrefsActivity extends PreferenceActivity
{
    private static int prefs=R.xml.myprefs;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        try {
            getClass().getMethod("getFragmentManager");
            AddResourceApi11AndGreater();
        } catch (NoSuchMethodException e) { //Api < 11
            AddResourceApiLessThan11();
        }
    }

    @SuppressWarnings("deprecation")
    protected void AddResourceApiLessThan11()
    {
        addPreferencesFromResource(prefs);
    }

    @TargetApi(11)
    protected void AddResourceApi11AndGreater()
    {
        getFragmentManager().beginTransaction().replace(android.R.id.content,
                new PF()).commit();
    }

    @TargetApi(11)
    public static class PF extends PreferenceFragment
    {       
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(MyPrefsActivity.prefs); //outer class
            // private members seem to be visible for inner class, and
            // making it static made things so much easier
        }
    }
}

Diuji dalam dua emulator (2.2 dan 4.2) dengan sukses.

Mengapa kode saya terlihat sangat jelek:

Saya noob untuk coding Android, dan saya bukan penggemar java terbesar.

Untuk menghindari peringatan yang sudah usang dan memaksa Eclipse untuk mengizinkan saya mengkompilasi, saya harus menggunakan anotasi, tetapi ini tampaknya hanya memengaruhi kelas atau metode, jadi saya harus memindahkan kode ke dua metode baru untuk memanfaatkan ini.

Saya tidak ingin menulis id sumber daya xml saya dua kali kapan saja saya menyalin & menempelkan kelas untuk PreferenceActivity baru, jadi saya membuat variabel baru untuk menyimpan nilai ini.

Saya harap ini akan bermanfaat bagi orang lain.

PS: Maaf atas pandangan saya yang berpendapat, tetapi ketika Anda datang baru dan menemukan cacat seperti itu, Anda tidak bisa menahan diri untuk frustrasi!

ecv
sumber
Oh well ... Saya baru sadar saya harus mengganti nama kelas luar dua kali kapan saja saya salin & tempel. Sebenarnya ada cara untuk menghindari ini, dengan melewati prefs ke innerclass. Anda tidak boleh membuat konstruktor kelas dalam yang menerima prefs sebagai parameter karena tampaknya tidak direkomendasikan untuk kelas turunan PreferenceFragment. Selain itu, Anda tidak boleh membuat metode di kelas dalam untuk mendapatkan prefs dan memanggil addPreferencesFromResource segera, karena addPreferencesFromResource perlu dipanggil setelah super.onCreate telah dipanggil, dan onCreate tidak dipanggil tepat setelah kelas turunan PreferensiFragment telah ...
ecv
... telah dipakai. Jadi, Anda perlu membuat variabel baru di kelas dalam, membuat metode kumpulan publik untuk itu di kelas dalam, meninggalkan addPreferencesFromResource di mana setelah panggilan ke super.onCreate, di dalam onCreate, instantiate kelas dalam, atur prefs , dan gunakan dalam panggilan untuk getFragmentManager () ... seperti sebelumnya.
ecv
2
Kode Anda telah menjadi penyelamat !! Saya mencoba menargetkan ponsel lama dan baru, dan menghabiskan 3 hari .. Dan jawabannya sangat sederhana. Terima kasih
Devdatta Tengshe
22

Pendekatan saya sangat dekat dengan pendekatan Garret Wilson (terima kasih, saya memilih Anda;)

Selain itu memberikan kompatibilitas ke bawah dengan Android <3.

Saya baru menyadari bahwa solusi saya bahkan lebih dekat dengan yang dibuat oleh Kevin Remo . Ini hanya sedikit lebih bersih (karena tidak bergantung pada antipattern "expection" ).

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            onCreatePreferenceActivity();
        } else {
            onCreatePreferenceFragment();
        }
    }

    /**
     * Wraps legacy {@link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl
     * < 11).
     */
    @SuppressWarnings("deprecation")
    private void onCreatePreferenceActivity() {
        addPreferencesFromResource(R.xml.preferences);
    }

    /**
     * Wraps {@link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >=
     * 11).
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void onCreatePreferenceFragment() {
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new MyPreferenceFragment ())
                .commit();
    }
}

Untuk contoh "nyata" (tetapi lebih kompleks) lihat NusicPreferencesAktivitas dan NusicPreferencesFragment .

pemalas
sumber
@SuppressLint("NewApi")- Hindari - lebih tepat. Apakah Anda menjalankannya untuk apis rendah? Ini akan melemparVerifyError
Mr_and_Mrs_D
Saya menguji di atas pada emulator yang menjalankan API level 10, APK dibangun menggunakan SDK Versi 19. Versi SDK apa yang Anda gunakan untuk membangun? Di tingkat mana API perangkat Anda jalankan? Apakah Anda menjalankannya di emulator atau pada perangkat fisik? Kapan tepatnya kesalahan terjadi? Jika Ur Anda membangun dengan SDK <= 16, lihat respons ini .
schnatterer
Anda melewatkan intinya - dan menambahkan @Mr_and_Mrs_D jika Anda ingin saya diberitahu. Untuk VE baca di sini: stackoverflow.com/questions/20271593/… . Itu @SuppressLint("NewApi")hanya gaya buruk
Mr_and_Mrs_D
@ M Nah, bagaimana dengan proposal tentang bagaimana menghindari @SuppressLint("NewApi")dalam situasi khusus ini?
schnatterer
@TargetApi(Build.VERSION_CODES.HONEYCOMB)- tidak semua peringatan untuk api apa pun :)
Mr_and_Mrs_D
6

Alih-alih pengecualian, cukup gunakan:

if (Build.VERSION.SDK_INT >= 11)

dan gunakan

@SuppressLint("NewApi")

untuk menekan peringatan.

Peter
sumber
1
karena tidak melakukan apa-apa selain crash: D
Ishtiaq
1
jika macet ... maka coba dan tangkap: D
gumuruh
0

Alih-alih menggunakan a PreferenceActivity untuk memuat preferensi secara langsung, gunakan a AppCompatActivityatau yang setara yang memuat aPreferenceFragmentCompat yang memuat preferensi Anda. Itu bagian dari perpustakaan dukungan (sekarang Android Jetpack) dan menyediakan kompatibilitas kembali ke API 14.

Di Anda build.gradle, tambahkan ketergantungan untuk pustaka dukungan preferensi:

dependencies {
    // ...
    implementation "androidx.preference:preference:1.0.0-alpha1"
}

Catatan: Kami akan menganggap Anda memiliki preferensi Anda XML sudah dibuat.

Untuk aktivitas Anda, buat kelas aktivitas baru. Jika Anda menggunakan tema materi, Anda harus memperluas AppCompatActivity, tetapi Anda bisa fleksibel dengan ini:

public class MyPreferencesActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_preferences_activity)
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, MyPreferencesFragment())
                    .commitNow()
        }
    }
}

Sekarang untuk bagian yang penting: buat sebuah fragmen yang memuat preferensi Anda dari XML:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.my_preferences_fragment); // Your preferences fragment
    }
}

Untuk informasi lebih lanjut, baca Android Developers docs untuk PreferenceFragmentCompat.

Willie Chalmers III
sumber