2012-04-17 16 views
35

एंड्रॉइड 4.0 के लिए एपिडेमोस में विभिन्न वरीयता गतिविधियों को आजमाते हुए, मैं कोड में देखता हूं कि कुछ तरीकों को PreferencesFromCode.java में बहिष्कृत किया गया है, उदाहरण के लिए।वरीयता सक्रियता एंड्रॉइड 4.0 और इससे पहले

तो मेरा सवाल यह है कि: यदि मैं वरीयताप्रवाह का उपयोग करता हूं, तो यह सभी संस्करणों या केवल 3.0 या 4.0 के लिए काम करेगा?

यदि हां, तो मुझे 2.2 और 2.3 के लिए यह काम क्या करना चाहिए?

+2

नहीं पसंद है, लेकिन गूगल डेवलपर की साइट में पूर्व हनीकोम्ब उपकरणों के साथ संगतता के मुद्दों के बारे में उपयोगी जानकारी देने के लिए शुरू किया: http://developer.android.com/training/backward-compatible-ui /index.html –

+0

वरीयता फ़्रेगमेंट के लिए एक तृतीय पक्ष बैकपोर्ट है। [मेरा जवाब] देखें (http://stackoverflow.com/a/22462743/1747491)। – theblang

+0

जैसा कि @pcans ने नीचे टिप्पणी की है, जवाब अब आधिकारिक एंड्रॉइड प्रलेखन में है: http://developer.android.com/guide/topics/ui/settings.html#BackCompatHeaders –

उत्तर

58

PreferenceFragment 2.2 और 2.3 (केवल API स्तर 11 और ऊपर) पर काम नहीं करेगा। यदि आप सबसे अच्छे उपयोगकर्ता अनुभव की पेशकश करना चाहते हैं और अभी भी पुराने एंड्रॉइड संस्करणों का समर्थन करना चाहते हैं, तो यहां पर सबसे अच्छा अभ्यास दो PreferenceActivity कक्षाओं को लागू करने और रनटाइम पर निर्णय लेने के लिए प्रतीत होता है। हालांकि, इस विधि में अभी भी बहिष्कृत एपीआई को कॉल करना शामिल है, लेकिन आप इससे बच नहीं सकते हैं।

तो उदाहरण के लिए, आप एक 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 की wo कार्यान्वयन, API स्तरों का समर्थन या PreferenceFragments समर्थन नहीं करने के लिए:

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 स्तरोंके लिए इन xml फ़ाइलें के प्रत्येक लोड11, और दोनों गतिविधियां समान वरीयताओं का उपयोग करती हैं।

+0

अंतर्दृष्टिपूर्ण उत्तर। वास्तव में Google की आवश्यकता है क्योंकि एंड्रॉइड ऐप्स को पीछे संगत बनाने के लिए हमें उचित दस्तावेज देने में असफल रहा। हाल ही में हाल ही में चीजें बदलना शुरू हो गया है (ऊपर टिप्पणी देखें) –

+3

अच्छा विचार, केवल समस्या तब होती है जब आप गतिविधि शुरू करने वाले नहीं होते हैं, इस प्रकार आप निर्णय लेने के लिए निर्णय नहीं ले सकते हैं। वह, और आप फीचर डिटेक्शन के विरोध में एपीआई-स्तरीय पहचान का उपयोग कर रहे हैं (क्लासलोडर्स का उपयोग करके यह जांचने के लिए कि वरीयता फ़्रेगमेंट मौजूद है या नहीं)। उपयोगकर्ता जो अपनी build.prop फ़ाइल को एपीआई 10 से 11 (या उच्चतर) तक जाने के लिए संपादित करता है, उसे क्रैश होगा। – Tom

+3

अब यह यहां प्रलेखित है: http://developer.android.com/guide/topics/ui/settings.html#BackCompatHeaders – pcans

18

@Mef आपका उत्तर और भी सरल बनाया जा सकता है ताकि आपको प्राथमिकताएं और अन्य प्राथमिकताएं दोनों की आवश्यकता न हो (2 प्रीफ़ाएक्टिविटीयां एक पिटा है)।

मुझे पता चला है कि आप ऑनबिल्डहेडर() विधि को अपनी प्राथमिकताएं सक्रियता में डाल सकते हैं और v11 से पहले एंड्रॉइड संस्करणों द्वारा कोई त्रुटि नहीं डाली जाएगी। OnBildHeaders के अंदर loadHeadersFromResource() होने के बाद 2.3.6 पर फेंक और अपवाद नहीं हुआ, लेकिन एंड्रॉइड 1.6 पर किया। हालांकि कुछ tinkering के बाद, मैंने पाया कि निम्नलिखित कोड सभी संस्करणों में काम करेगा ताकि केवल एक गतिविधि की आवश्यकता हो (मामलों को बहुत सरल बनाना)।

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

इस तरह आप केवल एक गतिविधि, अपने AndroidManifest.xml में एक प्रविष्टि और एक लाइन की जरूरत है जब आप अपनी प्राथमिकताओं आह्वान:

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

अद्यतन अक्टू 2013: ग्रहण/एक प्रकार का वृक्ष के बारे में आपको चेतावनी देगा बहिष्कृत विधि का उपयोग कर, लेकिन केवल चेतावनी को अनदेखा करें। हम केवल तभी विधि का उपयोग कर रहे हैं जब हमें करना होगा, जो कि जब भी हमारे पास v11 + शैली प्राथमिकताएं नहीं होती हैं और इसका उपयोग करना चाहिए, जो ठीक है।जब आप इसके लिए जिम्मेदार होते हैं तो बहिष्कृत कोड के बारे में डरो मत, एंड्रॉइड जल्द ही बहिष्कृत विधियों को कभी भी नहीं हटाएगा। यदि यह कभी हुआ होता है, तो आपको अब इस कक्षा की भी आवश्यकता नहीं होगी क्योंकि आपको केवल नए उपकरणों को लक्षित करने के लिए मजबूर होना होगा। आपको चेतावनी देने के लिए बहिष्कृत तंत्र है कि नवीनतम एपीआई संस्करण पर कुछ संभालने का एक बेहतर तरीका है, लेकिन एक बार जब आप इसके लिए जिम्मेदार हो जाते हैं, तो आप तब से चेतावनी को सुरक्षित रूप से अनदेखा कर सकते हैं। बहिष्कृत विधियों के लिए सभी कॉल को हटाने से न केवल आपके कोड को नए उपकरणों पर चलाने के लिए मजबूर किया जाएगा - इस प्रकार पिछड़ा संगत होने की आवश्यकता को अस्वीकार कर दिया जाएगा।

+3

1.6 पर आपके पास अपवाद है कि Dalvik सभी विधियों को लोड करने की कोशिश कर रहा है (या उनके अस्तित्व की जांच कर रहा है) भले ही उन्हें रनटाइम पर नहीं कहा जाता है। यह व्यवहार 2.0 में बदल दिया गया है, इसलिए यही कारण है कि 2.3.6 में कोई अपवाद नहीं है। – bigstones

+0

@ कोड बंदर को शामिल करें आप वहां वरीयता फ़्रेगमेंट xml का उपयोग कहां करते हैं? – Maxrunner

+0

@Maxrunner इनबिल्डहेडर() में आप "pre.xml.pref_headers" को प्रतिस्थापित करेंगे, जिसमें आपकी प्राथमिकता Headers.xml फ़ाइल को संदर्भित किया गया है। आम तौर पर, आपके पास केवल एक ऐसी फ़ाइल होनी चाहिए, अन्यथा केवल "मुख्य" को सूचीबद्ध करें। ऑनक्रेट() में जहां addPreferencesFromResource() लाइनें स्थित हैं, वहीं आप अपनी विभिन्न प्राथमिकताओं Fragment.xml फ़ाइलों के सभी आर int संदर्भों को सूचीबद्ध करेंगे। सरल सेटिंग्स में केवल एक फ़ाइल हो सकती है, लेकिन यह वह जगह है जहां आपके पास आमतौर पर ऐसी कई prefs खंड फ़ाइलें होती हैं। बस अपने ऐप में शामिल सभी के लिए एक लाइन जोड़ें। –

5

पिछले उत्तरों के साथ समस्या यह है कि यह प्री-होनकॉम डिवाइस पर सभी प्राथमिकताओं को एक स्क्रीन पर ढेर कर देगा (addPreferenceFromResource() की एकाधिक कॉल के कारण)।

आप सूची के रूप में पहली स्क्रीन और फिर वरीयताओं (जैसे वरीयता हेडर का उपयोग के रूप में) के साथ स्क्रीन की जरूरत है, तो आप Official guide to compatible preferences

6

का उपयोग करना चाहिए वहाँ एक newish lib कि मदद कर सकता है है।

UnifiedPreference एपीआई v4 और ऊपर से एंड्रॉयड पसंद पैकेज के सभी संस्करणों के साथ काम करने के लिए एक पुस्तकालय है।

+0

मैंने कोशिश की, लेकिन इसे संकलित करने के लिए नहीं मिला। –

1

मैं कहना है कि यदि आप http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeaders पर शुरू और "वरीयता हेडर के साथ पुराने संस्करणों का समर्थन के लिए" अनुभाग में नीचे अपने तरीके से काम इसे और अधिक समझ कर देगा चाहता था। गाइड बहुत उपयोगी है और अच्छी तरह से काम करता है। यहाँ एक स्पष्ट उदाहरण उनके गाइड निम्नलिखित है:

तो मधुकोश

<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_legacy.xml के साथ शुरू अगला Honeycomb के साथ Android प्रणाली के लिए फ़ाइल बनाने preference_header.xml +

<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" 
/> 
0

मैं this library, जो mavenCentral में एक AAR ताकि आप आसानी से इसे शामिल कर सकते हैं का उपयोग कर रहा यदि आप Gradle का उपयोग कर रहे हैं।अब के लिए संबंधित

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

संबंधित मुद्दे