2011-06-24 13 views
16

registerContentObserver() का उपयोग करने वाले सभी उदाहरण ContentProvider इंटरफ़ेस के माध्यम से ऐसा करते हैं। लेकिन कर्सर के पास registerContentObserver() कॉल है, इसलिए मुझे लगता है कि एंड्रॉइड लोगों ने कुछ गहरे जादू को एक साथ रखा है जो SQLite कर्सर पर अपडेट प्राप्त करने की अनुमति देगा जब सक्रिय परिणाम सेट की पंक्तियों में से एक बदल गई है। या तो मैं इसे गलत कर रहा हूं, या ऐसा कोई जादू नहीं है। यहां कोड है जिसके साथ मैं काम कर रहा हूं, उम्मीद है कि जब मैं पंक्ति # 1 में मान को अपडेट करने के लिए बटन पर क्लिक करता हूं तो मुझे onChange() कॉलबैक मिलेगा। कोई विचार?रजिस्टर कंटेंट ऑब्सर्वर() कच्चे SQLite कर्सर

public class MainActivity extends Activity { 
    private static final String DATABASE_NAME = "test.db"; 
    public static final String TAG = "dbtest"; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     Button make = (Button)findViewById(R.id.btn_make_record); 
     make.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { 
       MyOpenHelper oh = new MyOpenHelper(v.getContext()); 
       SQLiteDatabase wdb = oh.getWritableDatabase(); 
       ContentValues cv = new ContentValues(); 
       cv.put("value", String.valueOf(System.currentTimeMillis())); 
       if (wdb.insert(MyOpenHelper.TABLE_NAME, null, cv) == -1) { 
        Log.d(TAG, "Unable to insert row"); 
       } else { 
        Log.d(TAG, "Inserted row "); 
       } 
       wdb.close(); 
      } 
     }); 

     Button update = (Button)findViewById(R.id.btn_update_record); 
     update.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { 
       MyOpenHelper oh = new MyOpenHelper(v.getContext()); 
       SQLiteDatabase wdb = oh.getWritableDatabase(); 
       ContentValues cv = new ContentValues(); 
       cv.put("value", String.valueOf(System.currentTimeMillis())); 
       int count = wdb.update(MyOpenHelper.TABLE_NAME, cv, "_id = ?", new String[] {"1"}); 
       Log.d(TAG, "Updated " + count + " row(s)"); 
       wdb.close(); 
      } 
     }); 

     MyOpenHelper oh = new MyOpenHelper(this); 
     SQLiteDatabase rdb = oh.getReadableDatabase(); 
     Cursor c = rdb.query(MyOpenHelper.TABLE_NAME, null, "_id = ?", new String[] {"1"}, null, null, null); 
     startManagingCursor(c); 
     contentObserver = new MyContentObserver(new Handler()); 
     c.registerContentObserver(contentObserver); 
    } 

    private class MyContentObserver extends ContentObserver { 
     MyContentObserver(Handler handler) { 
      super(handler); 
     } 

     public boolean deliverSelfNotifications() { 
      return true; 
     } 

     public void onChange(boolean selfChange) { 
      super.onChange(selfChange); 
      Log.d(TAG, "Saw a change in row # 1"); 
     } 
    } 

    MyContentObserver contentObserver; 

    public class MyOpenHelper extends SQLiteOpenHelper { 
     private static final int DATABASE_VERSION = 1; 
     private static final String TABLE_NAME = "test"; 
     private static final String TABLE_CREATE = 
       "CREATE TABLE " + TABLE_NAME + " (" + 
       "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 
       "value TEXT);"; 

     MyOpenHelper(Context context) { 
      super(context, DATABASE_NAME, null, DATABASE_VERSION); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      db.execSQL(TABLE_CREATE); 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      // TODO Auto-generated method stub  
     } 
    } 
} 
+0

अरे आदमी, स्वीकृत उत्तर गलत है, मुझे पता है कि यह आपका उत्तर है लेकिन यह सही नहीं है। –

उत्तर

15

कोई लेकर्स नहीं है? अच्छी तरह से खुद को खोदने और इसे समझने का एक उत्कृष्ट बहाना। मेरे लिए उत्सुक हो सकता है, यदि आप मंच स्रोत डाउनलोड करते हैं तो प्रासंगिक फाइलें देखने के लिए हैं:

ढांचे/आधार/कोर/जावा/एंड्रॉइड/डेटाबेस/एसक्लाइट/SQLiteCursor.java ढांचे/आधार/कोर /java/android/database/AbstractCursor.java

ऐसा लगता है कि mContentObservable एक कर्सर में सेट किए गए कैश किए गए परिणाम से चलने वाले प्रोग्राम के विभिन्न हिस्सों को सिग्नल करने के लिए है, और अवलोकन योग्य कैश किए गए परिणाम से संकेत है उपभोक्ताओं को पता चले कि कैश को डंप/अपडेट किया गया है। जब अंतर्निहित डेटास्टोर का उपयोग किया जाता है तो यह घटनाओं को आग लगाने के लिए SQLite कार्यान्वयन में नहीं जुड़ा होता है।

बिल्कुल आश्चर्य की बात नहीं है, लेकिन डॉक्स को मैंने सोचा कि शायद मुझे कुछ याद आ रहा था।

+0

जो मुझे समझ में नहीं आता है वह सामग्री प्रदाता विशेष बनाता है? यदि ContentProvider को SQLiteDatabase द्वारा समर्थित किया गया है, तो इसके रजिस्टरकंटेंट ऑब्सर्वर() सही चीज़ कैसे करते हैं? – jfritz42

+1

यह सामग्री रिज़ॉल्वर के माध्यम से हुक अप करता है। जब प्रदाता कॉल को सूचित करता है तो यूरी के लिए रिज़ॉल्वर पर बदलें, रिज़ॉल्यूवर सभी पर्यवेक्षकों को वापस बुलाए जाने का ख्याल रखता है। – mikerowehl

+0

@ jfritz42 एक 'ContentProvider' पढ़ने और लिखने दोनों के लिए ज़िम्मेदार है। इसलिए, भले ही इसे SQLite डेटाबेस द्वारा समर्थित किया गया हो, फिर भी यह लिखने के संचालन के बाद किसी भी श्रोताओं को कॉल कर सकता है। – Felix

20

यह वास्तव में संभव है।

आपको उरी कहीं (एक स्थिर हो सकता है) को परिभाषित करना होगा। तब

public static final Uri URI_MY_TABLE = 
    Uri.parse("sqlite://com.example.<your-app-package>/table"); 

जब आप डेटाबेस डेटा आप फोन अद्यतन:

मैं कुछ इस तरह उपयोग करने के लिए सलाह होगा

context.getContentResolver().notifyChange(Constants.URI_MY_TABLE, null); 

और CursorLoader से आप की तरह कुछ करने के लिए लिख रहे हैं:

final ForceLoadContentObserver observer; 

public MyCursorLoader(final Context context, ...) { 
    super(context); 
    // ... 
    this.observer = new ForceLoadContentObserver(); 
} 

@Override 
public Cursor loadInBackground() { 
    SQLiteDatabase db = this.dbHelper.getReadableDatabase(); 
    final Cursor c = queryDatabase(db); 
    if (c != null) { 
     // Ensure the cursor window is filled 
     c.getCount(); 
     // this is to force a reload when the content change 
     c.registerContentObserver(this.observer); 
     // this make sure this loader will be notified when 
     // a notifyChange is called on the URI_MY_TABLE 
     c.setNotificationUri(getContext().getContentResolver(), 
      Constants.URI_MY_TABLE); 
    } 
    return c; 
} 

ForceLoadContentObserverलोडर कक्षा के अंदर एक सार्वजनिक स्थिर आंतरिक कक्षा है, यदि आप समर्थन लाइब्रेरी का उपयोग कर रहे हैं तो यह android.support.v4.content.Loader होगा।ForceLoadContentObserver

ही लोडर में सुनिश्चित करें कि आप forceReload अगर डेटा परिवर्तन: CursorLoader usage without ContentProvider:

@Override 
protected void onStartLoading() { 
    if (this.cursor != null) { 
     deliverResult(this.cursor); 
    } 
    // this takeContentChanged() is important! 
    if (takeContentChanged() || this.cursor == null) { 
     forceLoad(); 
    } 
} 

अपने CursorLoader यदि आप नहीं जानते कि यह कैसे लिखने के लिए एक अच्छी शुरुआत है

आपका कर्सर एडाप्टर अब इस तरह आरंभ किया जाना चाहिए:

public MyCursorAdapter(Context context, Cursor c) { 
    super(context, c, 0); 
} 

ContentResolver uri आप की स्थापना पर पर्यवेक्षक को अधिसूचित करने का ख्याल रखना होगा।

यह ठीक है कि ContentProvider काम करता है।

आप एक लोडर आप एक ही सामान कर सकते हैं का उपयोग नहीं कर रहे हैं, तो महत्वपूर्ण संशोधनों हैं:

  • कॉल ContentResolver.notifyChange (यूआरआइ, नल); जब आप डेटा
  • कॉल Cursor.setNotificationUri (ContentResolver, URI) को बदलें; जब आप कर्सर लोड करते हैं

इस तरह जब आप पर्यवेक्षक को पंजीकृत करते हैं तो आपको अधिसूचना डेटा बदलते समय अधिसूचित किया जाएगा।

+1

यह बहुत अच्छी तरह से काम करता है! धन्यवाद Daniele – Shatazone

+0

कमाल समाधान Daniele !! क्या मैं आईओएस पर वही काम कर सकता हूं? –

+0

मुझे वास्तव में संदेह है कि गीत चौबे, लोडर और कंटेंट रीसोलवर एंड्रॉइड फ्रेमवर्क का हिस्सा हैं :-) –

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