Apakah PreferenceFragment sengaja dikeluarkan dari paket kompatibilitas?

153

Saya ingin menulis preferensi yang dapat diterapkan pada perangkat 3.0 dan pra-3.0. Menemukan yang PreferenceActivityberisi metode yang sudah usang (meskipun ini digunakan dalam kode sampel yang menyertainya), saya melihat PreferenceFragementdan paket kompatibilitas untuk menyelesaikan kesengsaraan saya.

Tampaknya, itu PreferenceFragmenttidak ada dalam paket kompatibilitas. Adakah yang bisa memberi tahu saya apakah ini disengaja? Jika demikian, dapatkah saya dengan mudah menargetkan berbagai perangkat (yaitu <3.0 dan> = 3.0) atau akankah saya harus melewati rintangan? Jika tidak sengaja dikecualikan, dapatkah kita mengharapkan rilis baru dari paket kompatibilitas? Atau adakah solusi lain yang aman untuk digunakan?

Bersulang

James

James
sumber
1
Ini adalah pendekatan saya untuk memecahkan masalah: stackoverflow.com/questions/14076073/...
ecv
Seseorang membuat pihak ketiga PreferenceFragmentyang akan Anda lupakan bahkan ada di sana. Lihat jawaban saya .
theblang
Chris Banes membahas ini dalam komentar di blog-nya . Dia mengatakan bahwa alasannya adalah,"Because most of Preferences' implementation is hidden, therefore impossible to backport without lots of hackery."
theblang
Lihat jawaban saya yang diperbarui . PreferenceFragmentCompatbaru-baru ini ditambahkan ke perpustakaan dukungan.
theblang

Jawaban:

90

Menemukan bahwa PreferenceActivity berisi metode yang sudah usang (meskipun ini digunakan dalam kode sampel yang menyertainya)

Metode yang sudah usang tidak digunakan lagi di Android 3.0. Mereka baik-baik saja di semua versi Android, tetapi arahnya adalah untuk menggunakan PreferenceFragmentAndroid 3.0 dan lebih tinggi.

Adakah yang bisa memberi tahu saya apakah ini disengaja?

Dugaan saya adalah ini soal waktu rekayasa, tapi itu hanya dugaan.

Jika demikian, dapatkah saya dengan mudah menargetkan berbagai perangkat (yaitu <3.0 dan> = 3.0) atau akankah saya harus melewati rintangan?

Saya menganggap itu dilakukan "dengan mudah". Memiliki dua PreferenceActivityimplementasi terpisah , satu menggunakan header preferensi dan PreferenceFragmentsyang lainnya menggunakan pendekatan asli. Pilih yang tepat di titik yang Anda butuhkan (misalnya, ketika pengguna mengklik item menu opsi). Berikut adalah contoh proyek yang menunjukkan ini. Atau, miliki satu PreferenceActivityyang menangani kedua kasus, seperti dalam proyek sampel ini .

Jika tidak sengaja dikecualikan, dapatkah kita mengharapkan rilis baru dari paket kompatibilitas?

Anda akan mengetahui kapan kita semua mencari tahu, yaitu, jika dan kapan kapal itu dikirim.

Atau adakah solusi lain yang aman untuk digunakan?

Lihat di atas.

CommonsWare
sumber
Tanda Ceria. Saya telah melihat bahwa Anda telah membuat komentar tentang hal ini di beberapa tempat (grup google android dan blog Anda) tetapi menginginkan jawaban yang pasti (sejauh yang bisa diberikan keadaan).
James
@ James: Ya, gosokan akan berada dalam preferensi definisi XML, mendapatkan sesuatu yang akan berfungsi dengan baik sebagai fragmen dan juga disatukan, karena saya tidak yakin <include>bekerja dengan preferensi XML. BTW, jika Anda seorang pelanggan, pembaruan buku yang merujuk proyek ini diumumkan beberapa menit yang lalu.
CommonsWare
7
Maaf, tapi saya tidak begitu yakin apa yang ingin Anda sampaikan di sini. Anda tidak menjawab apa pun, hanya berkomentar / menebak / merujuk ke tautan eksternal yang tidak relevan yang tidak ada hubungannya dengan masalah tersebut. Pertanyaannya adalah apakah kelalaian itu disengaja, tanpa versi kompatibilitas PreferenceFragment tidak ada cara untuk memperluas PreferenceActivity dengan cara yang telah Anda jelaskan karena jika PreferenceFragment tidak ada maka jangan getSupportFragmentManager () atau metode lainnya diperlukan untuk menggunakan fragmen di tempat pertama.
Justin Buser
8
@JustinBuser: "Pertanyaannya adalah apakah kelalaian itu disengaja atau tidak" - satu-satunya orang yang bisa menjawab itu bekerja untuk Google. Anda dipersilakan untuk mendapatkan pekerjaan di Google untuk mencoba mencari tahu. "tidak ada cara memperluas PreferenceActivity seperti yang Anda gambarkan" - Anda dipersilakan untuk mengunduh kode yang saya tautkan.
CommonsWare
9
@JustinBuser Sebagai catatan, Mark memang menjawab pertanyaan saya. Itu terbukti dari saya menerima jawabannya.
James
21

Implikasi halus dari jawaban dari @CommonsWare adalah bahwa - aplikasi Anda harus memilih antara API kompatibilitas atau API fragmen bawaan (sejak SDK 11 atau lebih). Sebenarnya itulah yang dilakukan oleh rekomendasi "mudah". Dengan kata lain, jika Anda ingin menggunakan PreferenceFragment, aplikasi Anda perlu menggunakan API fragmen bawaan dan menangani metode yang sudah tidak digunakan lagi di PreferenceActivity. Sebaliknya, jika penting bahwa aplikasi Anda menggunakan compat. API Anda akan dihadapkan dengan tidak memiliki kelas PreferenceFragment sama sekali. Dengan demikian, perangkat penargetan tidak menjadi masalah, tetapi kehebohan terjadi ketika Anda harus memilih salah satu atau API lainnya dan dengan demikian mengirimkan desain Anda ke solusi yang tidak terduga. Saya perlu compat. API jadi saya akan membuat kelas PreferenceFragment saya sendiri dan melihat cara kerjanya. Dalam skenario terburuk saya

EDIT: Setelah mencoba dan melihat kode di http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java? av = h - membuat PreferenceFragment saya sendiri tidak akan terjadi. Tampaknya penggunaan liberal paket-pribadi di PreferenceManager bukannya 'protected' adalah pemblokir utama. Sepertinya tidak ada keamanan atau motivasi yang sangat bagus untuk melakukan itu dan itu tidak bagus untuk pengujian unit tapi oh well ... kurang mengetik saya kira ...

EDIT v2: Sebenarnya itu terjadi dan berhasil. Jelas sakit kepala untuk membuat kode berfungsi dengan JAR API Kompatibilitas. Saya harus menyalin sekitar 70% paket com.android.preference dari SDK ke aplikasi saya dan kemudian bergulat dengan kode Java yang biasanya berkualitas biasa-biasa saja di Android. Saya menggunakan v14 dari SDK. Akan jauh lebih mudah bagi seorang insinyur Goog untuk melakukan apa yang saya lakukan, bertentangan dengan apa yang saya dengar beberapa insinyur Android katakan tentang topik ini.

BTW - apakah saya mengatakan "perangkat penargetan tidak menjadi masalah"? Benar-benar adalah ... jika Anda menggunakan com.android.preference Anda tidak akan dapat bertukar dengan API Kompatibilitas tanpa refactoring utama. Log yang menyenangkan!

Gigih
sumber
Biarkan saya lebih langsung. Jika yang Anda pedulikan adalah menargetkan Honeycomb dan lebih tinggi (yang memiliki pangsa pasar berapa?) Lalu pilih jawaban dari @Commonsware! Jika Anda peduli dengan sebagian besar perangkat Android yang ada di pasaran saat ini, Anda harus membaca tanggapan saya.
Tenacious
4
maukah Anda membagikan bagaimana Anda melakukan ini? Saya mengalami masalah yang persis sama, hanya PreferenceActivity saya harus menggunakan Loader dan karena itu saya harus menggunakan perpustakaan kompatibilitas.
Karakuri
3
@Tenacious Saya suka investigasi Anda - bagus sekali. Namun, saya merasa seseorang harus meluruskan komentar pertama Anda di sana - kode Commonsware akan berfungsi pada perangkat pre & post HC - coba dulu sebelum membuat komentar seperti itu. Hal yang perlu Anda sadari adalah ikatan yang digunakan pada saat runtime untuk mendukung perangkat sebelumnya. Pemeriksaan versi saat runtime menangani mendukung kedua keluarga OS - ini adalah pola Android yang umum (bukan yang saya suka - tetapi yang penting bagi pengembang Android untuk belajar & menjadi akrab dengan) ... Jadi bagi pembaca di masa mendatang - don bisa menolak pendekatan baik.
Richard Le Mesurier
@RichardLeMesurier tetapi metode Commonsware tidak tepat jika Anda memerlukan preferensi di dalam DrawerLayout
neworld
16

Membangun berdasarkan jawaban CommonsWare serta pengamatan Tenacious, saya telah datang dengan solusi kelas turunan tunggal yang mampu menargetkan semua versi Android API saat ini dengan kerepotan minimal dan tanpa duplikasi kode atau sumber daya. Silakan lihat jawaban saya untuk pertanyaan terkait di sini: PreferenceActivity Android 4.0 dan sebelumnya

atau di blog saya: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

Diuji pada dua tablet yang menjalankan 4.0.3 dan 4.0.4 serta ponsel yang menjalankan 4.0.4 dan 2.3.3 dan juga sebuah emulator yang menjalankan 1.6.

Paman Kode Monyet
sumber
10

Lihat PreferenceFragment-Compat dari Machinarius. Sangat mudah untuk turun dengan gradle dan saya lupa bahwa itu ada di sana.

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

Perbarui penting: The Revisi terbaru dari v7 support librarysekarang memiliki native PreferenceFragmentCompat .

theblang
sumber
10

Pada Agustus 2015 Google merilis Perpustakaan Dukungan Preferensi v7 yang baru .

Sekarang Anda dapat menggunakan PreferenceFragmentCompat dengan ActivityatauAppCompatActivity

public static class PrefsFragment extends PreferenceFragmentCompat {

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

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

Anda harus mengatur preferenceThemetema Anda:

<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
  ...
  <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

Dengan cara ini Anda dapat mengubahsuaikan preferenceThemeke gaya tata letak yang digunakan untuk setiap jenis preferensi tanpa memengaruhi bagian lain dari Aktivitas Anda.

Gabriele Mariotti
sumber
1
Saya pikir Anda melewatkan fungsi: onCreatePreferences
pengembang android
Ini menyelamatkan hari saya! Saya bertanya-tanya mengapa ini tidak terlihat dalam Struktur Proyek Android Studio ... ?? BTW Anda memiliki salah ketik dalam kode Anda. Seharusnya "extendsFreferenceFragmentCompat"
Grzegorz D.
7

Jawaban Tenacious benar, tetapi di sini ada beberapa detail.

Alasan Anda tidak dapat "membuat tata letak normal dan mengikat komponen tampilan ke sharedprefs secara manual" adalah bahwa ada beberapa kelalaian mengejutkan di API android.preferences. PreferenceActivity dan PreferenceFragment keduanya memiliki akses ke metode PreferenceManager non-publik yang kritis, yang tanpanya Anda tidak dapat mengimplementasikan UI preferensi Anda sendiri.

Khususnya, untuk membuat hierarki Preferensi dari file XML, Anda harus menggunakan PreferenceManager, tetapi semua konstruktor PreferenceManager adalah paket-pribadi atau tersembunyi. Metode melampirkan Preferensi onClick pendengar ke aktivitas Anda juga paket-pribadi.

Dan Anda tidak dapat menyiasatinya dengan secara diam-diam meletakkan implementasi Anda dalam paket android.preferences, karena metode non-publik di API Android sebenarnya dihilangkan dari SDK. Dengan sedikit kreativitas yang melibatkan refleksi dan proksi dinamis, Anda masih bisa mendapatkannya. Satu-satunya alternatif, seperti yang dikatakan Tenacious, adalah memotong seluruh paket preferensi android.pre, termasuk setidaknya 15 kelas, 5 tata letak, dan sejumlah elemen style.xml dan attrs.xml yang serupa.

Jadi untuk menjawab pertanyaan awal, alasan Google tidak memasukkan PreferenceFragment dalam paket kompatibilitas adalah bahwa mereka akan mengalami kesulitan yang sama persis seperti Tenacious dan saya sendiri. Bahkan Google tidak dapat kembali ke masa lalu dan mempublikasikan metode-metode tersebut di platform lama (meskipun saya berharap mereka melakukannya di rilis mendatang).

mhsmith
sumber
2

Target aplikasi saya adalah API +14 tetapi karena menggunakan pustaka dukungan untuk beberapa navigasi mewah, saya tidak bisa menggunakan android.app.Fragmentdan harus menggunakan android.support.v4.app.Fragment, tetapi saya juga harus ada PreferenceFragmentdi tempat tanpa perubahan besar pada kode di belakang.

Jadi perbaikan mudah saya untuk memiliki kedua dunia perpustakaan dukungan dan PreferenceFragment:

private android.support.v4.app.Fragment fragment;
private android.app.Fragment nativeFragment = null;

private void selectItem(int position) {
    fragment = null;
    boolean useNativeFragment = false;
    switch (position) {
    case 0:
        fragment = new SampleSupprtFragment1();
        break;
    case 1:
        fragment = new SampleSupprtFragment2();
        break;
    case 2:
        nativeFragment = new SettingsFragment();
        useNativeFragment = true;
        break;
    }
    if (useNativeFragment) {
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, nativeFragment).commit();
    } else {
        if (nativeFragment != null) {
            getFragmentManager().beginTransaction().remove(nativeFragment)
                .commit();
            nativeFragment = null;
        }
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, fragment).commit();
    }
}
Mohsen Afshin
sumber
2

Saya perlu mengintegrasikan Preferensi ke dalam desain aplikasi dan tetap mendukung Android 2.3. Jadi saya masih membutuhkan PreferencesFragment.

Setelah beberapa pencarian saya menemukan lib android-support-v4-preferensifragment . Lib ini menghemat banyak waktu untuk menyalin dan refactoring PreferensiFragment asli seperti kata Tenacious. Bekerja dengan baik dan pengguna menikmati preferensi.

dunia baru
sumber