PreferenceFragment ถูกแยกออกจากแพ็คเกจความเข้ากันได้อย่างตั้งใจหรือไม่?


153

ฉันกำลังมองหาการเขียนการตั้งค่าที่สามารถนำไปใช้กับทั้งอุปกรณ์ 3.0 และ 3.0 ก่อน การค้นพบที่PreferenceActivityมีวิธีการที่ไม่สนับสนุน (แม้ว่าจะใช้ในรหัสตัวอย่างที่แนบมา) แต่ฉันก็มองไปที่PreferenceFragementและแพคเกจความเข้ากันได้เพื่อแก้ปัญหาของฉัน

ดูเหมือนว่าPreferenceFragmentจะไม่ได้อยู่ในแพ็คเกจความเข้ากันได้ มีใครบอกฉันได้ไหมว่าสิ่งนี้ตั้งใจหรือไม่ ถ้าเป็นเช่นนั้นฉันสามารถกำหนดช่วงของอุปกรณ์ได้อย่างง่ายดาย (เช่น <3.0 และ> = 3.0) หรือฉันจะต้องกระโดดผ่านห่วงได้หรือไม่? หากไม่ได้รับการยกเว้นโดยเจตนาเราสามารถคาดหวังว่าจะมีแพคเกจความเข้ากันได้รุ่นใหม่หรือไม่ หรือมีวิธีแก้ปัญหาอื่นที่ปลอดภัยที่จะใช้?

ไชโย

เจมส์


1
นี่เป็นวิธีการของฉันในการแก้ปัญหา: stackoverflow.com/questions/14076073/…
ecv

มีคนสร้างบุคคลที่สามPreferenceFragmentที่คุณจะลืมแม้กระทั่งที่นั่น ดูคำตอบของฉัน
theblang

คริส Banes อยู่นี้ในความคิดเห็นในบล็อกของเขา เขาบอกว่าเหตุผลคือ"Because most of Preferences' implementation is hidden, therefore impossible to backport without lots of hackery."
theblang

ดูของฉันคำตอบการปรับปรุง PreferenceFragmentCompatถูกเพิ่มในไลบรารีการสนับสนุนเมื่อเร็ว ๆ นี้
theblang

คำตอบ:


90

การค้นพบว่า PreferenceActivity มีวิธีการที่ไม่สนับสนุน (แม้ว่าจะใช้ในรหัสตัวอย่างที่แนบมา)

วิธีการที่เลิกใช้แล้วจะเลิกใช้ตั้งแต่ Android 3.0 พวกมันใช้ได้ดีกับ Android ทุกรุ่น แต่ทิศทางคือการใช้PreferenceFragmentบน Android 3.0 และสูงกว่า

มีใครบอกฉันได้ไหมว่าสิ่งนี้ตั้งใจหรือไม่

ฉันเดาว่ามันเป็นคำถามของเวลาวิศวกรรม แต่นั่นเป็นเพียงการคาดเดา

ถ้าเป็นเช่นนั้นฉันสามารถกำหนดช่วงของอุปกรณ์ได้อย่างง่ายดาย (เช่น <3.0 และ> = 3.0) หรือฉันจะต้องกระโดดผ่านห่วงได้หรือไม่?

ฉันคิดว่าจะทำได้ "ง่าย" มีPreferenceActivityการนำไปใช้งานสองแบบแยกกันส่วนหนึ่งใช้ส่วนหัวค่ากำหนดและPreferenceFragmentsอีกส่วนใช้วิธีดั้งเดิม เลือกหนึ่งที่ถูกต้องในจุดที่คุณต้องการ (เช่นเมื่อผู้ใช้คลิกที่รายการเมนูตัวเลือก) นี่คือโครงการตัวอย่างที่แสดงสิ่งนี้ หรือมีซิงเกิ้ลPreferenceActivityที่จัดการทั้งสองกรณีเช่นเดียวกับในโครงการตัวอย่างนี้

หากไม่ได้รับการยกเว้นโดยเจตนาเราสามารถคาดหวังว่าจะมีแพคเกจความเข้ากันได้รุ่นใหม่หรือไม่

คุณจะพบว่าเมื่อใดที่พวกเราที่เหลือรู้ว่าจะพูดว่าอย่างไรและเมื่อไร

หรือมีวิธีแก้ปัญหาอื่นที่ปลอดภัยที่จะใช้?

ดูด้านบน.


Mark Cheers ฉันเห็นว่าคุณได้แสดงความคิดเห็นเกี่ยวกับเรื่องนี้ในสถานที่สองแห่ง (กลุ่ม android ของ Google และบล็อกของคุณ) แต่ต้องการคำตอบที่ชัดเจน (เท่าที่ใครจะได้รับสถานการณ์)
James

@James: ใช่แล้ว rub จะอยู่ในนิยาม XML ของการตั้งค่ารับสิ่งที่จะทำงานได้ดีเป็นชิ้นส่วนและเชื่อมต่อกันด้วยกันเนื่องจากฉันไม่แน่ใจว่า<include>ทำงานได้กับ XML การกำหนดค่าตามความชอบ BTW หากคุณเป็นสมาชิกการอัปเดตหนังสืออ้างอิงโครงการนี้ประกาศเมื่อไม่กี่นาทีที่ผ่านมา
CommonsWare

7
ฉันขอโทษ แต่ฉันไม่แน่ใจจริงๆว่าคุณกำลังพยายามทำอะไรที่นี่ คุณไม่ต้องตอบอะไรเลยเพียงแค่คอมเม้นท์ / เดา / อ้างอิงถึงลิงค์ภายนอกที่ไม่เกี่ยวข้องซึ่งไม่มีส่วนเกี่ยวข้องกับปัญหา คำถามคือการละเลยหรือไม่ตั้งใจโดยไม่มีเวอร์ชั่นที่เข้ากันได้ของ PreferenceFragment จะไม่มีวิธีการขยาย PreferenceActivity ในแบบที่คุณอธิบายเพราะถ้า PreferenceFragment ไม่มีอยู่แล้วไม่ได้ทำ getSupportFragmentManager () หรือวิธีอื่นใด จำเป็นต้องใช้ชิ้นส่วนในตอนแรก
Justin Buser

8
@JustinBuser: "คำถามคือการละเลยหรือไม่ตั้งใจ" - เฉพาะคนที่สามารถตอบคำถามนี้ได้สำหรับ Google คุณสามารถหางานได้ที่ Google เพื่อหาคำตอบ "ไม่มีวิธีการขยายการตั้งค่ากิจกรรมในวิธีที่คุณอธิบาย" - คุณสามารถดาวน์โหลดรหัสที่ฉันเชื่อมโยงได้
CommonsWare

9
@JustinBuser สำหรับบันทึกแล้วมาร์คตอบคำถามของฉันแล้ว เห็นได้ชัดว่าฉันยอมรับคำตอบของเขา
James

21

ความหมายที่ลึกซึ้งของคำตอบจาก @CommonsWare คือ - แอปของคุณจะต้องเลือกระหว่าง API ความเข้ากันได้หรือ API ในตัว (ตั้งแต่ SDK 11 เป็นต้นไป) ในความเป็นจริงนั่นคือสิ่งที่คำแนะนำ "ง่าย" ได้ทำไว้ กล่าวอีกนัยหนึ่งถ้าคุณต้องการใช้ PreferenceFragment แอปของคุณต้องใช้ API ส่วนในตัวและจัดการกับวิธีที่เลิกใช้แล้วใน PreferenceActivity ในทางกลับกันหากเป็นสิ่งสำคัญที่แอปของคุณใช้การรองรับ API คุณจะต้องเผชิญกับการไม่มีคลาส PreferenceFragment เลย ดังนั้นการกำหนดเป้าหมายอุปกรณ์ไม่ใช่ปัญหา แต่การกระโดดแบบกระโดดเกิดขึ้นเมื่อคุณต้องเลือกอย่างใดอย่างหนึ่งหรือ API อื่น ๆ ดังนั้นจึงส่งการออกแบบของคุณเพื่อแก้ไขปัญหาที่ไม่คาดคิด ฉันต้องการความเข้ากันได้ API ดังนั้นฉันจะสร้างคลาส PreferenceFragment ของตัวเองและดูว่ามันทำงานอย่างไร ในกรณีที่เลวร้ายที่สุดฉัน

แก้ไข: หลังจากลองดูรหัสที่http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java? av = h - การสร้าง PreferenceFragment ของฉันเองจะไม่เกิดขึ้น ดูเหมือนว่าการใช้งานแบบแพคเกจส่วนตัวใน PreferenceManager แทน 'ป้องกัน' เป็นตัวบล็อกหลัก มันดูเหมือนจะไม่ปลอดภัยหรือมีแรงจูงใจที่ดีที่จะทำสิ่งนั้นและมันก็ไม่ได้ยอดเยี่ยมสำหรับการทดสอบหน่วย แต่ก็ดี ... พิมพ์น้อยกว่าฉันเดาว่า ...

แก้ไข v2: จริงๆแล้วมันเกิดขึ้นและใช้งานได้ แน่นอนว่ามันเป็นเรื่องที่ปวดหัวที่จะทำให้โค้ดใช้งานได้กับ Compatibility API JAR ฉันต้องคัดลอกแพ็คเกจ com.android.preference ประมาณ 70% จาก SDK ไปยังแอปของฉันแล้วต่อสู้กับรหัส Java คุณภาพปานกลางใน Android ฉันใช้ v14 ของ SDK คงเป็นเรื่องที่ง่ายขึ้นสำหรับวิศวกร Goog ที่จะทำสิ่งที่ฉันทำตรงกันข้ามกับสิ่งที่ฉันได้ยินว่าวิศวกร Android บางคนพูดเกี่ยวกับหัวข้อนี้

BTW - ฉันว่าคำว่า "อุปกรณ์การกำหนดเป้าหมายไม่ใช่ปัญหา" หรือไม่? มันคือทั้งหมด ... หากคุณใช้ com.android.preference คุณจะไม่สามารถแลกเปลี่ยนกับ API ความเข้ากันได้โดยไม่ต้องทำการปรับเปลี่ยนครั้งใหญ่ บันทึกสนุก!


ขอให้ฉันตรงไปกว่านี้ หากสิ่งที่คุณสนใจคือการกำหนดเป้าหมายไปที่ Honeycomb และสูงกว่า (ซึ่งมีส่วนแบ่งการตลาดเท่าไหร่) ให้โหวตคำตอบจาก @Commonsware! หากคุณสนใจอุปกรณ์ Android ส่วนใหญ่ในตลาดวันนี้คุณควรอ่านคำตอบของฉัน
หวงแหน

4
คุณยินดีที่จะแบ่งปันวิธีที่คุณทำเช่นนี้? ฉันพบปัญหาเดียวกันทุกประการเฉพาะ PreferenceActivity เท่านั้นที่ต้องใช้ตัวโหลดดังนั้นฉันจึงต้องใช้ไลบรารีความเข้ากันได้
Karakuri

3
@Tenacious ฉันชอบการสอบสวนของคุณ - ทำได้ดีมาก อย่างไรก็ตามฉันรู้สึกว่ามีบางคนควรตั้งค่าการบันทึกตรงกับความคิดเห็นแรกของคุณที่นั่น - รหัสของ Commonsware จะทำงานบนอุปกรณ์ก่อนและโพสต์ HC - ลองก่อนที่จะแสดงความคิดเห็นเช่นนั้น สิ่งที่คุณต้องรู้คือการโยงท้ายที่ใช้ที่รันไทม์เพื่อสนับสนุนอุปกรณ์ก่อนหน้า การตรวจสอบเวอร์ชั่นที่รันไทม์ดูแลการสนับสนุนทั้งครอบครัวของ OS - นี่เป็นรูปแบบ Android ทั่วไป (ไม่ใช่ที่ฉันชอบ - แต่เป็นสิ่งที่สำคัญสำหรับนักพัฒนา Android ในการเรียนรู้และทำความคุ้นเคย) ... ดังนั้นสำหรับผู้อ่านในอนาคต - ดอน ไม่ละแนวทาง
Richard Le Mesurier

@RichardLeMesurier แต่วิธีการของ Commonsware นั้นไม่เหมาะสมหากคุณต้องการการตั้งค่าใน DrawerLayout
newWorld

16

จากคำตอบของคอมมอนส์แวร์รวมถึงการสังเกตการณ์ของ Tenacious ฉันได้พบกับโซลูชันการสืบทอดแบบเดี่ยวที่สามารถกำหนดเป้าหมายเวอร์ชัน Android API ปัจจุบันทั้งหมดด้วยความยุ่งยากน้อยที่สุดและไม่มีการทำซ้ำรหัสหรือทรัพยากร โปรดดูคำตอบของฉันสำหรับคำถามที่เกี่ยวข้องที่นี่: PreferenceActivity Android 4.0 และรุ่นก่อนหน้า

หรือบนบล็อกของฉัน: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

ทดสอบบนแท็บเล็ตสองเครื่องที่รัน 4.0.3 และ 4.0.4 เช่นเดียวกับโทรศัพท์ที่ใช้ 4.0.4 และ 2.3.3 และยังมีโปรแกรมจำลองการทำงาน 1.6


10

ดูPreferenceFragment-Compatจาก Machinarius มันง่ายที่จะดรอปด้วย gradle และฉันลืมไปว่ามันอยู่ที่นั่นด้วยซ้ำ

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

การปรับปรุงที่สำคัญ: แก้ไขล่าสุดในv7 support libraryขณะนี้มีชาวPreferenceFragmentCompat


10

เมื่อเดือนสิงหาคม 2558 Google เปิดตัวLibrary Preference Support v7 ใหม่ใหม่

ตอนนี้คุณสามารถใช้PreferenceFragmentCompatกับใด ๆActivityหรือAppCompatActivity

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);
    }
}

คุณต้องตั้งค่าpreferenceThemeในชุดรูปแบบของคุณ:

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

ด้วยวิธีนี้คุณสามารถปรับแต่งpreferenceThemeสไตล์ให้เป็นเลย์เอาต์ที่ใช้สำหรับการกำหนดค่าตามความชอบแต่ละประเภทโดยไม่กระทบต่อส่วนอื่น ๆ ของกิจกรรมของคุณ


1
ฉันคิดว่าคุณพลาดฟังก์ชั่น: onCreatePreferences
นักพัฒนา Android

สิ่งนี้ช่วยชีวิตฉันไว้! ฉันสงสัยว่าทำไมไม่ปรากฏในโครงสร้างโครงการของ Android Studio ... BTW คุณมีการพิมพ์ผิดในรหัสของคุณ ควรเป็น "ขยายการตั้งค่าการจัดเรียงคอมแพค"
Grzegorz D.

7

คำตอบของ tenacious นั้นถูกต้อง แต่นี่เป็นรายละเอียดเพิ่มเติม

เหตุผลที่คุณไม่สามารถ "สร้างเลย์เอาต์ปกติและผูกองค์ประกอบมุมมองไปยัง sharedprefs ด้วยตนเอง" คือมีการละเว้นที่น่าแปลกใจใน android.preferences API PreferenceActivity และ PreferenceFragment ทั้งสองมีการเข้าถึงวิธีการ PreferenceManager ที่สำคัญที่ไม่ใช่แบบสาธารณะโดยที่คุณไม่สามารถใช้ UI การกำหนดค่าตามความชอบของคุณเอง

โดยเฉพาะอย่างยิ่งเมื่อต้องการสร้างลำดับชั้นของการกำหนดค่าตามความชอบจากไฟล์ XML คุณต้องใช้ PreferenceManager แต่ Constructor ของ PreferenceManager ทั้งหมดเป็นแพ็คเกจแบบส่วนตัวหรือซ่อนอยู่ วิธีการแนบการกำหนดค่าตามความชอบ onClick listeners กับกิจกรรมของคุณยังเป็นแพ็กเกจส่วนตัว

และคุณไม่สามารถหลีกเลี่ยงปัญหานี้ได้โดยใส่การดำเนินการของคุณลงในแพ็คเกจ android.preferences เนื่องจากการไม่ใช้วิธีสาธารณะใน Android API นั้นถูกตัดออกจาก SDK ด้วยความคิดสร้างสรรค์เล็ก ๆ น้อย ๆ ที่เกี่ยวข้องกับการสะท้อนและพร็อกซี่แบบไดนามิกคุณยังสามารถเข้าถึงได้ ทางเลือกเดียวที่ Tenacious พูดคือการแยกแพ็คเกจ android.preference ทั้งหมดรวมถึงคลาสอย่างน้อย 15 คลาส 5 เลย์เอาท์และองค์ประกอบ style.xml และ attrs.xml จำนวนใกล้เคียงกัน

ดังนั้นเพื่อตอบคำถามเดิมเหตุผลที่ Google ไม่ได้รวม PreferenceFragment ไว้ในแพ็คเกจความเข้ากันได้ก็คือพวกเขาจะมีปัญหาเช่นเดียวกับ Tenacious และตัวฉันเอง แม้แต่ Google ก็ไม่สามารถย้อนเวลากลับไปและทำให้วิธีการเหล่านั้นเผยแพร่ต่อสาธารณชนในแพลตฟอร์มเก่า (แม้ว่าฉันหวังว่าพวกเขาจะทำเช่นนั้นในการเปิดตัวในอนาคต)


2

เป้าหมายของฉันคือแอป API 14 แต่เนื่องจากการใช้ห้องสมุดการสนับสนุนสำหรับระบบนำทางแฟนซีบางอย่างผมไม่สามารถใช้android.app.Fragmentและมีการใช้งานandroid.support.v4.app.Fragmentแต่ฉันยังจำเป็นต้องมีPreferenceFragmentในสถานที่ที่ไม่มีการเปลี่ยนแปลงขนาดใหญ่ไปยังรหัสหลัง

ดังนั้นการแก้ไขที่ง่ายของฉันสำหรับการมีทั้งโลกแห่งห้องสมุดสนับสนุนและ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();
    }
}

2

ฉันต้องการรวมการตั้งค่าไว้ในการออกแบบแอปพลิเคชันและให้การสนับสนุนสำหรับ Android 2.3 ดังนั้นฉันยังต้องการการตั้งค่าการจัดเรียง

หลังจากการค้นหาฉันพบandroid-support-v4-preferencesfragment lib lib นี้ประหยัดเวลาได้มากสำหรับการคัดลอกและ refactoring PreferencesFragment ดั้งเดิมตามที่ Tenacious กล่าว ทำงานได้ดีและผู้ใช้เพลิดเพลินไปกับการตั้งค่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.