จะใช้อะไรแทน“ addPreferencesFromResource” ใน PreferenceActivity


360

ฉันเพิ่งสังเกตเห็นความจริงที่ว่าวิธีการaddPreferencesFromResource(int preferencesResId)ทำเครื่องหมายถูกคัดค้านในเอกสารของ Android ( รายการอ้างอิง )

น่าเสียดายที่ไม่มีวิธีการอื่นให้ในคำอธิบายของวิธีการ

วิธีใดที่ควรใช้แทนเพื่อเชื่อมต่อ preferencesScreen.xml กับ PreferenceActivity ที่ตรงกัน?


2
WannaGetHigh ให้แนวทางที่ตรงไปตรงมามากที่stackoverflow.com/questions/23523806/ …
Sabin

วิธีแก้ปัญหายังคงใช้addPreferencesFromResource(int preferencesResId)อยู่ ฉันพลาดอะไรไปรึเปล่า ?
Jammo

@ Jammo ใช่ แต่มันถูกย้ายจากกิจกรรมเป็นชิ้นส่วนเพื่อสะท้อนวิธีการใหม่ในการทำ -> ส่วน
WannaGetHigh

คำตอบ:


332

ไม่มีวิธีการอื่นให้ไว้ในคำอธิบายของวิธีการเนื่องจากวิธีการที่ต้องการ (ณ ระดับ API 11) คือการสร้างอินสแตนซ์ของวัตถุPreferenceFragmentเพื่อโหลดการตั้งค่าของคุณจากไฟล์ทรัพยากร ดูตัวอย่างรหัสได้ที่นี่: PreferenceActivity


ขอบคุณมากสำหรับคำตอบของคุณ. ฉันเพิ่งทำตามคำแนะนำที่เลิกใช้แล้วจาก "การพัฒนา Video2Brain-Android" ซึ่งทำให้ฉันใช้วิธีรุ่น PreferenceActivity Btw: ฉันชอบที่จะให้คะแนนคำตอบของคุณว่ามีประโยชน์ถ้าฉันทำได้
mweisz

33
ตอนนี้เฉพาะถ้า PreferenceFragment รวมอยู่ในแพ็คเกจที่ใช้งานร่วมกันได้มันจะสมเหตุสมผลที่จะใช้stackoverflow.com/questions/5501431/ …
christoff

1
เนื่องจากฉันใช้ Action Bar Sherlock ฉันจึงติดตามบล็อกต่อไปนี้เพื่อแก้ปัญหานี้โปรดดู ... commonsware.com/blog/2012/10/16/…
บางคนที่ไหนสักแห่ง

2
คุณยังคงต้องเรียกใช้ addPreferencesFromResource (int PreferencesID) หากคุณต้องการให้แอปย้อนกลับเข้ากันได้กับระดับ API ก่อนหน้า 11 (Android 3.0) แต่ฉันคิดว่าคุณสามารถพิจารณาอุปกรณ์เก่าเหล่านั้นที่ถูกตัดออกเช่นกัน
Einar Sundgren

5
@EinarSundgren ฉันเป็นเจ้าของ Nexus One และรุ่นที่ใช้ได้สูงสุดของฉันคือ 2.2: คุณจะไม่หยุดฉัน! ฉันจะไม่เลิกใช้เลย! โดย Power of Grayskull ... ฉันมีพลัง!
TechNyquist

186

ในการเพิ่มข้อมูลเพิ่มเติมให้กับคำตอบที่ถูกต้องด้านบนหลังจากอ่านตัวอย่างจาก Android-erฉันพบว่าคุณสามารถแปลงกิจกรรมการตั้งค่าของคุณเป็นส่วนย่อยของการตั้งค่าได้อย่างง่ายดาย หากคุณมีกิจกรรมต่อไปนี้:

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

การเปลี่ยนแปลงเพียงอย่างเดียวที่คุณต้องทำคือการสร้างคลาสแฟรกเมนต์ภายในย้ายaddPreferencesFromResources()ไปยังแฟรกเมนต์และเรียกใช้แฟรกเมนต์จากกิจกรรมดังนี้:

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

อาจมีรายละเอียดปลีกย่อยอื่น ๆ เพื่อทำให้การตั้งค่าที่ซับซ้อนมากขึ้นจากชิ้นส่วน; ถ้าเป็นเช่นนั้นฉันหวังว่ามีคนบันทึกพวกเขาที่นี่


6
เยี่ยมมากขอบคุณสำหรับสิ่งนี้ Java และประเภทของการคิดนี้จะถูกลบออกเพื่อให้ห่างไกลจากโลกเล็ก ๆ น้อย ๆ .net ดีของฉัน :)
ทอม

44
ทำไมพวกเขาถึงคิดค่าเสื่อมราคาaddPreferencesFromResources()เพื่อการค้าสำหรับ PreferenceFragment? ดูเหมือนไม่จำเป็นจากมุมมองเริ่มต้น
Howdy_McGee

4
การโทรต้องใช้ API ระดับ 11
mehmet

1
แล้วถ้าเป็น API ในระดับ 9 ล่ะ @mehmet
gumuruh

2
คำตอบที่ยอดเยี่ยม! มีวิธีใดที่จะทำให้สำเร็จโดยไม่ต้องเปลี่ยน android.R.id.content? ดูเหมือนไม่งดงามให้ฉันด้วยเหตุผลบางอย่าง ... (ผมที่ถูกต้องหากผิด im)
tomer.z

37

@Garret Wilson ขอบคุณมาก! ในฐานะที่เป็นการเข้ารหัส noob สำหรับ Android ฉันได้รับการติดอยู่กับปัญหาความเข้ากันไม่ได้ของการตั้งค่าเป็นเวลาหลายชั่วโมงและฉันพบว่ามันน่าผิดหวังมากที่พวกเขาเลิกใช้วิธี / แนวทางบางอย่างสำหรับคนใหม่ที่ API เก่าไม่รองรับ ต้องหันไปใช้วิธีแก้ปัญหาทุกประเภทเพื่อให้แอปของคุณทำงานในอุปกรณ์ที่หลากหลาย มันน่าผิดหวังจริงๆ!

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

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

ทดสอบในสองตัวเลียนแบบ (2.2 และ 4.2) ด้วยความสำเร็จ

ทำไมรหัสของฉันดูเส็งเคร็ง:

ฉันเป็น noob สำหรับ Android ที่เข้ารหัสและฉันไม่ใช่แฟน java ที่ยิ่งใหญ่ที่สุด

เพื่อหลีกเลี่ยงคำเตือนที่เลิกใช้และบังคับให้ Eclipse ให้ฉันรวบรวมฉันต้องหันไปใช้คำอธิบายประกอบ แต่สิ่งเหล่านี้ดูเหมือนจะมีผลกับคลาสหรือวิธีการเท่านั้นดังนั้นฉันจึงต้องย้ายโค้ดไปยังสองวิธีใหม่เพื่อใช้ประโยชน์จากสิ่งนี้

ฉันไม่ต้องการเขียนรหัสทรัพยากร xml ของฉันสองครั้งทุกครั้งที่ฉันคัดลอกและวางคลาสสำหรับ PreferenceActivity ใหม่ดังนั้นฉันจึงสร้างตัวแปรใหม่เพื่อเก็บค่านี้

ฉันหวังว่านี่จะเป็นประโยชน์กับคนอื่น

PS: ขอโทษสำหรับมุมมองความเห็นของฉัน แต่เมื่อคุณมาใหม่และหาอุปสรรคดังกล่าวคุณไม่สามารถช่วยได้ แต่ที่จะได้รับความผิดหวัง!


โอ้ ... ฉันเพิ่งสังเกตว่าฉันต้องเปลี่ยนชื่อคลาสภายนอกสองครั้งทุกครั้งที่ฉันคัดลอกและวาง มีวิธีหนึ่งที่จะหลีกเลี่ยงสิ่งนี้ได้โดยการส่งผ่าน prefs ไปที่ระดับชั้นใน คุณไม่สามารถสร้างคอนสตรัคเตอร์ในคลาสที่รับ prefs เป็นพารามิเตอร์ได้เนื่องจากไม่แนะนำให้ใช้กับคลาสที่ได้รับ PreferenceFragment นอกจากนี้คุณไม่สามารถสร้างวิธีในคลาสภายในเพื่อรับ prefs และเรียกใช้ addPreferencesFromResource ทันทีเนื่องจาก addPreferencesFromResource ต้องเรียกหลังจาก super.onCreate ถูกเรียกใช้และ onCreate จะไม่ถูกเรียกหลังจากคลาส PreferenceFragment ได้รับ ...
ecv

... ถูกยกตัวอย่าง ดังนั้นคุณต้องสร้างตัวแปรใหม่ในคลาสภายในสร้างเมธอด set สาธารณะในคลาสภายในปล่อยให้ addPreferencesFromResource อยู่ที่ใดหลังจากเรียก super.onCreate ภายใน onCreate อินสแตนซ์ของคลาสตั้งค่า prefs และใช้มันในการเรียกไปยัง getFragmentManager () ... เหมือนเมื่อก่อน
ecv

2
รหัสของคุณเป็นผู้ช่วยชีวิต !! ฉันพยายามกำหนดเป้าหมายทั้งโทรศัพท์เก่าและใหม่และเสียเวลา 3 วันและคำตอบนั้นง่ายมาก ขอบคุณ
Devdatta Tengshe

22

วิธีการของฉันใกล้กับGarret Wilson มาก (ขอบคุณฉันโหวตให้คุณ)

นอกจากนี้ยังให้ความเข้ากันได้กับ Android <3

ฉันเพิ่งรู้ว่าทางออกของฉันยิ่งใกล้กับKevin Remoมากขึ้น มันเป็นเพียงบิตสะอาดกว่า (เพราะไม่ต้องพึ่งพา"คาดหวัง" antipattern )

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

สำหรับ "ของจริง" ( แต่ที่ซับซ้อนมากขึ้น) ตัวอย่างเช่นดูNusicPreferencesActivityและNusicPreferencesFragment


@SuppressLint("NewApi")- หลีกเลี่ยง - ให้แม่นยำยิ่งขึ้น คุณเรียกใช้มันสำหรับ apis ต่ำหรือไม่? มันจะโยนVerifyError
Mr_and_Mrs_D

ฉันทดสอบข้างต้นบนอีมูเลเตอร์ที่รัน API ระดับ 10 APK สร้างขึ้นโดยใช้ SDK เวอร์ชัน 19 คุณใช้ SDK รุ่นใดในการสร้าง คุณใช้อุปกรณ์ API ระดับใด คุณรันบนอีมูเลเตอร์หรืออุปกรณ์ทางกายภาพหรือไม่? ข้อผิดพลาดเกิดขึ้นเมื่อใด หาก Ur building ด้วย SDK <= 16 ดูการตอบกลับนี้
schnatterer

คุณไม่มีจุด - และเพิ่ม @Mr_and_Mrs_D หากคุณต้องการให้ฉันได้รับแจ้ง สำหรับ VE อ่านได้ที่นี่: stackoverflow.com/questions/20271593/… . @SuppressLint("NewApi")เป็นเพียงรูปแบบที่ไม่ดี
Mr_and_Mrs_D

@M ถ้าเช่นนั้นข้อเสนอเกี่ยวกับวิธีหลีกเลี่ยง@SuppressLint("NewApi")ในสถานการณ์เฉพาะนี้เป็นอย่างไร
schnatterer

@TargetApi(Build.VERSION_CODES.HONEYCOMB)- ไม่ใช่คำเตือนสำหรับ api ใด ๆ :)
Mr_and_Mrs_D

6

แทนที่จะใช้ข้อยกเว้นเพียงใช้:

if (Build.VERSION.SDK_INT >= 11)

และการใช้งาน

@SuppressLint("NewApi")

เพื่อระงับคำเตือน


1
เพราะไม่มีอะไรอื่นนอกจากความผิดพลาด: D
Ishtiaq

1
ถ้ามันผิดพลาด ... จากนั้นลองจับมัน: D
gumuruh

0

แทนที่จะใช้ a PreferenceActivityเพื่อโหลดค่ากำหนดโดยตรงให้ใช้ค่าAppCompatActivityหรือเทียบเท่าที่โหลดค่าPreferenceFragmentCompatที่โหลดค่ากำหนดของคุณ เป็นส่วนหนึ่งของห้องสมุดสนับสนุน (ตอนนี้เป็น Android Jetpack) และให้ความเข้ากันได้กับ API 14

ในของคุณbuild.gradleเพิ่มการอ้างอิงสำหรับไลบรารีการสนับสนุนการกำหนดค่าตามความชอบ:

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

หมายเหตุ: เราจะสมมติว่าคุณได้สร้าง XML การกำหนดค่าตามความชอบของคุณแล้ว

สำหรับกิจกรรมของคุณให้สร้างคลาสกิจกรรมใหม่ หากคุณใช้ชุดรูปแบบวัสดุคุณควรขยายAppCompatActivityแต่คุณสามารถยืดหยุ่นได้ด้วยวิธีนี้:

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

ตอนนี้สำหรับส่วนที่สำคัญ: สร้างชิ้นส่วนที่โหลดค่ากำหนดของคุณจาก XML:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

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

สำหรับข้อมูลเพิ่มเติมโปรดอ่านนักพัฒนาซอฟต์แวร์ Android เอกสารPreferenceFragmentCompatสำหรับ

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