ContentResolver.requestSync एक सिंक को ट्रिगर क्यों नहीं करता है?


112

मैं Google IO - स्लाइड 26 पर चर्चा की गई सामग्री-प्रदाता-समन्वयन एडेप्टर पैटर्न को लागू करने का प्रयास कर रहा हूं । मेरा सामग्री प्रदाता काम कर रहा है, और जब मैं देव टूल सिंक परीक्षक से इसे ट्रिगर करता हूं, तो मेरा सिंक काम करता है, हालांकि जब मैं ContentResolver कहता हूं। मेरे ContentProvider से requestSync (खाता, प्राधिकरण, बंडल), मेरा सिंक कभी ट्रिगर नहीं होता है।

ContentResolver.requestSync(
        account, 
        AUTHORITY, 
        new Bundle());

संपादित करें - जोड़ा गया स्निपेट

<service
    android:name=".sync.SyncService"
    android:exported="true">
    <intent-filter>
        <action
            android:name="android.content.SyncAdapter" />
    </intent-filter>
    <meta-data android:name="android.content.SyncAdapter"
    android:resource="@xml/syncadapter" />
</service>

--Edit

मेरी समन्वयन सेवा के साथ मेरे Syncadcape.xml में शामिल हैं:

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"  
    android:contentAuthority="AUTHORITY"
    android:accountType="myaccounttype"
    android:supportsUploading="true"
/>

निश्चित नहीं है कि अन्य कोड क्या उपयोगी होगा। अनुरोध के लिए पास किया गया खाता सिंक "myaccounttype" का है और कॉल करने के लिए दिया गया AUTHORITY मेरे syc अनुकूलक xml से मेल खाता है।

क्या ContentResolver.requestSync सिंक का अनुरोध करने का सही तरीका है? ऐसा लगता है कि सिंक परीक्षक उपकरण सीधे सेवा से जुड़ जाता है और कॉल सिंक करना शुरू कर देता है, लेकिन ऐसा लगता है कि यह सिंक आर्किटेक्चर के साथ एकीकरण के उद्देश्य को हरा देता है।

अगर वह सिंक का अनुरोध करने का सही तरीका है तो सिंक परीक्षक काम क्यों करेगा, लेकिन ContentResolver.requestSync पर मेरा कॉल नहीं? क्या मुझे बंडल में पारित करने की आवश्यकता है?

मैं एम्यूलेटर में 2.1 और 2.2 पर चलने वाले उपकरणों का परीक्षण कर रहा हूं।


3
मेरी समस्या यह थी कि सिंक एडॉप्टर में मेरा ब्रेक पॉइंट नहीं हो रहा था ... तब मुझे एहसास हुआ कि मैं एक सेवा को डीबग करने की कोशिश कर रहा हूं ... आशा है कि यह मेरे जैसे अन्य लोगों की मदद करता है।
डांगाल

2
सिंक एडेप्टर सेवा में ब्रेकपाइंट ट्रिगर करने में विफल हो जाएगा। ऐसा इसलिए है क्योंकि सिंक एडाप्टर सेवा एक अलग प्रक्रिया में चलती है। यह वही है जो @danglang पर इशारा कर रहा था। यह प्रश्न भी देखें: stackoverflow.com/questions/8559458/…
कोन्सटेंटिन शुबर्ट

1
मेरे मामले android:process=":sync"में सिंक सेवा से हटाने पर डिबगर को चोंच के बिंदुओं पर मारा। इससे पहले सिंक सेवा स्वयं काम कर रही थी, क्योंकि मैं onPerformSyncदूसरी प्रक्रिया की ओर से विधि से लॉग संदेश देख सकता था ।
सेर्गेई

एक अन्य कारण वाईफाई बंद है, इसलिए यदि आप नकली डेटा के साथ सिंक करने की कोशिश कर रहे हैं, तो अपना कनेक्शन जांचें।
एलन वेलोसो

जवाबों:


280

कॉलिंग requestSync()केवल {खाता, ContentAuthority} जोड़ी पर काम करेगी जो सिस्टम को ज्ञात है। एंड्रॉइड को यह बताने के लिए आपके ऐप को कई चरणों से गुजरने की आवश्यकता है जो आप एक विशिष्ट प्रकार के खाते का उपयोग करके एक विशिष्ट प्रकार की सामग्री को सिंक्रनाइज़ करने में सक्षम हैं। यह AndroidManifest में ऐसा करता है।

1. एंड्रॉइड को सूचित करें कि आपका एप्लिकेशन पैकेज सिंकिंग प्रदान करता है

सबसे पहले, AndroidManifest.xml में, आपको घोषित करना होगा कि आपके पास एक सिंक सेवा है:

<service android:name=".sync.mySyncService" android:exported="true">
   <intent-filter>
      <action android:name="android.content.SyncAdapter" /> 
    </intent-filter>
    <meta-data 
        android:name="android.content.SyncAdapter" 
        android:resource="@xml/sync_myapp" /> 
</service>

<service>टैग का नाम विशेषता सिंक से कनेक्ट करने के लिए आपकी कक्षा का नाम है ... मैं एक सेकंड में उससे बात करूंगा।

निर्यात किया गया सच सेट करना इसे अन्य घटकों के लिए दृश्यमान बनाता है (आवश्यकता है तो ContentResolverइसे कॉल कर सकते हैं)।

आशय फ़िल्टर यह एक आशय को सिंक करने का अनुरोध करने देता है। (यह तब Intentहोता है ContentResolverजब आप कॉल करते हैं ContentResolver.requestSync()या संबंधित शेड्यूलिंग तरीके।)

<meta-data>टैग नीचे चर्चा की जाएगी।

2. एंड्रॉइड एक सेवा प्रदान करें जिसका उपयोग आपके सिंक एडेप्टर को खोजने के लिए किया जाता है

तो वर्ग ही ... यहाँ एक उदाहरण है:

public class mySyncService extends Service {

    private static mySyncAdapter mSyncAdapter = null;

    public SyncService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (mSyncAdapter == null) {
            mSyncAdapter = new mySyncAdapter(getApplicationContext(), true);
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return mSyncAdapter.getSyncAdapterBinder();
    }
}

आपकी कक्षा का विस्तार होना चाहिए Serviceया उसके किसी उपवर्ग को लागू करना चाहिए, उसे लागू public IBinder onBind(Intent)करना चाहिए और SyncAdapterBinderजब यह कहा जाता है तो वापस लौटना चाहिए ... आपको एक प्रकार का चर चाहिए AbstractThreadedSyncAdapter। तो जैसा कि आप देख सकते हैं, उस वर्ग में यह सब कुछ बहुत ज्यादा है। सेवा प्रदान करने का एकमात्र कारण यह है कि Android के लिए अपनी कक्षा को क्वेरी करने के लिए एक मानक इंटरफ़ेस प्रदान करता है कि आपका क्या SyncAdapterहै।

3. class SyncAdapterवास्तव में सिंक करने के लिए प्रदान करें ।

mySyncAdapter वह स्थान है जहाँ वास्तविक सिंक तर्क स्वयं संग्रहीत होता है। onPerformSync()सिंक करने का समय होने पर इसकी विधि को कॉल किया जाता है। मुझे लगता है कि आपके पास पहले से ही यह जगह है।

4. एक खाता-प्रकार और एक सामग्री प्राधिकरण के बीच एक बंधन स्थापित करें

AndroidManifest पर फिर से पीछे मुड़कर देखें, तो <meta-data>हमारी सेवा में अजीब टैग एक महत्वपूर्ण टुकड़ा है जो एक ContentAuthority और एक खाते के बीच बंधन स्थापित करता है। यह बाह्य रूप से एक और xml फ़ाइल को संदर्भित करता है (इसे आप जो भी पसंद करते हैं, अपने ऐप से प्रासंगिक है।) चलिए सिंक_myapp.xml देखें:

<?xml version="1.0" encoding="utf-8" ?> 
<sync-adapter 
    xmlns:android="http://schemas.android.com/apk/res/android"   
    android:contentAuthority="com.android.contacts"
    android:accountType="com.google" 
    android:userVisible="true" /> 

ठीक है, तो यह क्या करता है? यह एंड्रॉइड को बताता है कि हमने जो सिंक एडेप्टर परिभाषित किया है (वह वर्ग जिसे <service>टैग के नाम तत्व में कहा गया था, जिसमें टैग शामिल है जो <meta-data>इस फ़ाइल को संदर्भित करता है ...) कॉमन.ओक स्टाइल अकाउंट का उपयोग करके संपर्कों को सिंक करेगा।

आपके सभी कंटेंटअथॉरिटी स्ट्रिंग्स को सभी मैच करना है, और जो आप सिंक कर रहे हैं, उसके साथ मैच करें - यह एक स्ट्रिंग होनी चाहिए जिसे आप परिभाषित करते हैं, यदि आप अपना खुद का डेटाबेस बना रहे हैं, या यदि आप ज्ञात कर रहे हैं, तो आपको कुछ मौजूदा डिवाइस स्ट्रिंग्स का उपयोग करना चाहिए। डेटा प्रकार (जैसे संपर्क या कैलेंडर ईवेंट या आपके पास क्या है।) उपरोक्त ("com.android.contacts") संपर्क प्रकार डेटा (आश्चर्य, आश्चर्य) के लिए ContentAuthority string होना चाहिए।

accountType में उन ज्ञात खाता प्रकारों में से एक का मिलान भी करना होता है जो पहले से ही दर्ज हैं, या इसे आपके द्वारा बनाए जा रहे मेल से मेल खाना है (इसमें आपके सर्वर पर स्थिति प्राप्त करने के लिए AccountAuthenticator का उप-वर्ग बनाना शामिल है ... एक लेख, खुद के बारे में बताएं।) फिर से, "com.google" परिभाषित स्ट्रिंग की पहचान है ... google.com शैली खाता क्रेडेंशियल (फिर, यह एक आश्चर्य नहीं होना चाहिए)।

5. किसी दिए गए खाते / ContentAuthority जोड़ी पर सिंक सक्षम करें

अंत में, सिंक को सक्षम करना होगा। आप अपने ऐप पर जाकर और मिलान खाते के भीतर अपने ऐप के बगल में स्थित चेकबॉक्स को सेट करके कंट्रोल पैनल में अकाउंट्स एंड सिंक पेज में कर सकते हैं। वैकल्पिक रूप से, आप इसे अपने ऐप में कुछ सेटअप कोड में कर सकते हैं:

ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

सिंक होने के लिए, आपके खाते / प्राधिकरण की जोड़ी को सिंक करने में सक्षम होना चाहिए (ऊपर की तरह) और सिस्टम पर समग्र वैश्विक सिंक ध्वज सेट होना चाहिए, और डिवाइस में नेटवर्क कनेक्टिविटी होनी चाहिए।

यदि आपका खाता / प्राधिकरण सिंक या वैश्विक सिंक अक्षम है, तो कॉल करने से RequestSync () का प्रभाव पड़ता है - यह एक ध्वज सेट करता है जिसे सिंक का अनुरोध किया गया है, और जैसे ही सिंक सक्षम होता है, वैसे ही प्रदर्शन किया जाएगा।

इसके अलावा, एमजीवी के अनुसार , ContentResolver.SYNC_EXTRAS_MANUALआपके अनुरोध के एक्स्ट्रा बंडल में सही होने के लिए सेटिंगसंकट एंड्रॉइड से एक सिंक को मजबूर करने के लिए कहेंगे, भले ही वैश्विक सिंक बंद हो (यहां आपके उपयोगकर्ता का सम्मान हो!)

अंत में, आप ContentResolver फ़ंक्शंस के साथ एक आवधिक अनुसूचित सिंक को फिर से सेट कर सकते हैं।

6. कई खातों के निहितार्थ पर विचार करें

एक ही प्रकार के एक से अधिक खाते (दो @ gmail.com खाते एक डिवाइस या दो फेसबुक अकाउंट, या दो ट्विटर अकाउंट आदि) पर रखना संभव है।) आपको ऐसा करने के आवेदन के प्रभावों पर विचार करना चाहिए। यदि आपके पास दो खाते हैं, तो आप संभवतः दोनों को एक ही डेटाबेस तालिकाओं में सिंक करने का प्रयास नहीं करना चाहते हैं। शायद आपको यह निर्दिष्ट करने की आवश्यकता है कि एक समय में केवल एक ही सक्रिय हो सकता है, और यदि आप खातों को स्विच करते हैं, तो टेबल को फ्लश करें और फिर से सिंक करें। (एक संपत्ति पृष्ठ के माध्यम से जो यह सवाल करता है कि क्या खाते मौजूद हैं)। हो सकता है कि आप प्रत्येक खाते के लिए एक अलग डेटाबेस बनाएँ, हो सकता है कि अलग-अलग तालिकाएँ, प्रत्येक तालिका में एक प्रमुख स्तंभ हो। सभी आवेदन विशिष्ट और कुछ सोचा के योग्य। ContentResolver.setIsSyncable(Account account, String authority, int syncable)यहां रुचि हो सकती है। setSyncAutomatically()यह नियंत्रित करता है कि खाता / प्राधिकरण जोड़ी की जाँच की जाए या नहींअनियंत्रित , जबकि setIsSyncable()लाइन को अनचेक और ग्रे करने का एक तरीका प्रदान करता है ताकि उपयोगकर्ता इसे चालू न कर सके। आप एक खाते को सिंकेबल और दूसरे को सिंकेबल (डीएसएबल) नहीं कर सकते हैं।

7. ContentResolver.notifyChange () से अवगत रहें

एक मुश्किल बात। ContentResolver.notifyChange()एक फ़ंक्शन है जिसका उपयोग ContentProviderएंड्रॉइड को सूचित करने के लिए किया जाता है कि स्थानीय डेटाबेस को बदल दिया गया है। यह दो कार्य करता है, सबसे पहले, यह अद्यतन करने के लिए उस सामग्री का अनुसरण करने वाले कर्सर का कारण होगा, और बदले में आवश्यक और अमान्य और फिर से तैयार करना ListView, आदि ... यह बहुत जादुई है, डेटाबेस में परिवर्तन होता है और आपके ListViewबस अपडेट स्वचालित रूप से होते हैं। बहुत बढ़िया। इसके अलावा, जब डेटाबेस बदलता है, तो एंड्रॉइड आपके सामान्य शेड्यूल के बाहर भी आपके लिए सिंक का अनुरोध करेगा, ताकि उन परिवर्तनों को डिवाइस से निकाल लिया जाए और जितनी जल्दी हो सके सर्वर से सिंक किया जाए। कमाल भी।

हालांकि एक किनारे का मामला है। यदि आप सर्वर से खींचते हैं, और एक अपडेट को अंदर धकेलते हैं ContentProvider, तो यह कर्तव्यपूर्वक कॉल notifyChange()करेगा और एंड्रॉइड जाएगा, "ओह, डेटाबेस में बदलाव, बेहतर उन्हें सर्वर पर डाल दिया!" (दोह!) अच्छी तरह से लिखे जाने के ContentProvidersलिए कुछ परीक्षण होंगे, यह देखने के लिए कि क्या परिवर्तन नेटवर्क से या उपयोगकर्ता से आया है, और syncToNetworkइस व्यर्थ डबल-सिंक को रोकने के लिए बूलियन ध्वज को झूठा सेट करेगा । यदि आप डेटा को एक में ContentProviderफीड कर रहे हैं, तो आपको यह पता लगाना है कि इस काम को कैसे किया जाए - अन्यथा आप हमेशा दो सिंक करेंगे जब केवल एक की जरूरत हो।

8. खुशी महसूस करो!

एक बार जब आपके पास यह सब xml मेटाडाटा हो जाता है, और सिंक सक्षम हो जाता है, तो एंड्रॉइड को पता चल जाएगा कि आपके लिए सब कुछ कैसे कनेक्ट करना है, और सिंक काम करना शुरू कर देता है। इस बिंदु पर, बहुत सी चीजें जो अच्छी हैं, बस जगह पर क्लिक करेंगी और यह बहुत कुछ जादू जैसा महसूस होगा। का आनंद लें!


11
ContentResolver.setSyncAutomatically (खाता, योग्यता, सत्य);
jcwenger

1
कोई सम्स्या नहीं, मै खुश हूं कि सहायता कर सका। फिर से एक शैली के दृष्टिकोण से, अगर "AUTHORITY" और "myaccounttype" आपके द्वारा उपयोग किए जा रहे वास्तविक तार हैं (और साइट पर कॉपी-पेस्ट के लिए नमूने नहीं हैं), तो आपको निश्चित रूप से अपने नामकरण सम्मेलनों को साफ करने की आवश्यकता है। उन तारों को सभी डिवाइस में अद्वितीय होना चाहिए, और यदि आप किसी अन्य प्रोग्रामर को अधिकार के लिए मिलान स्ट्रिंग के साथ एक पैकेज बनाते हैं और आपको एक विरोधाभास मिलता है, तो आप वास्तविक परेशानी में भाग जाएंगे। चीयर्स!
jcwenger

22
आप वैश्विक सिंक सेटिंग्स बंद होने के बावजूद एक सिंक का अनुरोध कर सकते हैं। बस ContentResolver.SYNC_EXTRAS_MANUALएक्स्ट्रा बंडल में सही करने के लिए एक सेट जोड़ें और आप सिंक को मजबूर कर देंगे :)
mgv

2
@kaciula: मुझे किसी का भी पता नहीं है, लेकिन डिवाइस को याद होगा कि उसे सिंक करने की आवश्यकता है, और जैसे ही वैश्विक सिंक चालू होता है, यह एक बंद कर देगा। आपको वास्तव में इस पर उपयोगकर्ता को ट्रम्प करने की कोशिश नहीं करनी चाहिए - विशेष रूप से "ग्लोबल सिंक ऑफ" के रूप में क्रिटिकल स्थितियों में बैटरी को बचाने के प्रमुख तरीकों में से एक है। यदि आप वास्तव में सिंक किए जा रहे डेटा के बारे में चिंतित हैं, तो एक पॉपअप पर विचार करें जो उपयोगकर्ता को बताता है कि डेटा क्यों नहीं चल रहा है, अगर यह थोड़ी देर के लिए बैठा है। इस तरह आप उन उपयोगकर्ताओं को शिक्षित कर सकते हैं जिन्होंने गलती से अपने उपकरणों को गलत तरीके से बदल दिया है और वे भूल जाने की स्थिति में बिजली-उपयोगकर्ताओं को याद दिलाते हैं।
13:22 पर jcwenger

2
यह जोड़ने के लायक हो सकता है कि यदि आप addPeriodicSync () का उपयोग करना चाहते हैं, तो यह केवल तभी काम करता है जब आप ALS setSyncAutomatically () में काम करते हैं - मैंने कहा कि हताशा से बाहर निकलकर, SOMETING काम करने की कोशिश कर रहा है। मुझे पता है कि यह मूल प्रश्न का हिस्सा नहीं था, लेकिन यह ऐसा पूर्ण उत्तर है!
Android.weasel

0

मैं खाता setIsSyncableप्रबंधक setAuthTokenविधि के बाद शांत हो रहा था । लेकिन पहुंचने setAuthTokenसे पहले setIsSyncableही फंक्शन लौट आया । आदेश परिवर्तन के बाद सब कुछ ठीक हो गया!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.