दिलचस्प पोस्ट
जावा के साथ सेलेनियम वेबड्रायवर का उपयोग कर HTTP प्रतिक्रिया कोड कैसे प्राप्त करें? एक प्रकार से एक नया ऑब्जेक्ट उदाहरण प्राप्त करें एंड्रॉइड वेबव्यू – वेबपेज डिवाइस स्क्रीन पर फ़िट होना चाहिए सी # खिड़कियों एपीआई के माध्यम से फ़ाइल से थंबनेल प्राप्त करें C ++ हेडर फाइलों के लिए विज़ुअल स्टूडियो कहाँ दिखता है? एक बड़ी SQL स्क्रिप्ट निष्पादित करें (GO कमांड्स के साथ) मानचित्र में एक से अधिक स्ट्रिंग कैसे संग्रहित करें? सादा पाठ के रूप में HTML टैग कैसे प्रदर्शित करें आईओएस 7: स्टेटस बार के तहत यूआईटीबलदृश्य दिखाता है डिज़ाइन के अंदर छवि छवि के नीचे अतिरिक्त जगह है पोर्ट 80 (उबंटू / लिनोड) के साथ नोड.जेएस चलाते समय सर्वश्रेष्ठ अभ्यास MYSQL में सामान्यकरण `Enable_shared_from_this` की उपयोगिता क्या है? एंड्रॉइड लॉन्च करेंसूचित करने के बाद रीफ्रेश न करेंडेटासेट चेंजेड नेट में प्राथमिकता कतार

एंड्रॉइड पर SQLite के लिए सर्वोत्तम प्रथाएं क्या हैं?

एंड्रॉइड ऐप के अंदर एक SQLite डेटाबेस पर प्रश्नों को निष्पादित करते समय सबसे अच्छा प्रथाओं को क्या माना जाएगा?

क्या यह सम्मिलित करता है, हटाता है, और एक AsyncTask के doInBackground से क्वेरी को चुनने के लिए सुरक्षित है? या मुझे यूआई थ्रेड का उपयोग करना चाहिए? मुझे लगता है कि डेटाबेस क्वेरीज़ "भारी" हो सकती हैं और UI थ्रेड का उपयोग नहीं करना चाहिए क्योंकि यह ऐप लॉक कर सकता है – परिणामी कोई जवाब नहीं है (ANR)।

अगर मेरे पास कई असिनक टास्क हैं, तो क्या उन्हें एक कनेक्शन साझा करना चाहिए या क्या वे प्रत्येक कनेक्शन को खोलना चाहिए?

क्या इन स्थितियों के लिए कोई सर्वोत्तम पद्धतियां हैं?

वेब के समाधान से एकत्रित समाधान "एंड्रॉइड पर SQLite के लिए सर्वोत्तम प्रथाएं क्या हैं?"

सम्मिलित करता है, अद्यतन, हटाता है और पढ़ता है आमतौर पर कई धागे से ठीक है, लेकिन ब्रैड का उत्तर सही नहीं है। आपको अपने कनेक्शन बनाने और उनका उपयोग करने के बारे में सावधान रहना होगा। ऐसे परिस्थितियां हैं जहां आपके अपडेट कॉल विफल हो जाएंगी, भले ही आपका डेटाबेस दूषित न हो।

मूल जवाब

SqliteOpenHelper वस्तु एक डेटाबेस कनेक्शन पर रखती है। ऐसा प्रतीत होता है कि आपको एक पठन और लिखने का प्रस्ताव है, लेकिन यह वास्तव में नहीं है। केवल-पढ़ने के लिए कॉल करें, और आपको डेटाबेस डेटाबेस लिखने पर ध्यान दिए बिना

तो, एक सहायक उदाहरण, एक डीबी कनेक्शन यहां तक ​​कि अगर आप इसे कई धागे से उपयोग करते हैं, तो एक समय में एक कनेक्शन। SqliteDatabase ऑब्जेक्ट का उपयोग धारावाहिक के लिए जावा लॉक का उपयोग करता है। इसलिए, यदि 100 धागे में एक डीबी उदाहरण है, तो वास्तविक ऑन-डिस्क डाटाबेस को कॉल करने के लिए सीरियल कर दिया गया है।

इसलिए, एक सहायक, एक डीबी कनेक्शन, जो जावा कोड में क्रमबद्ध है। एक थ्रेड, 1000 धागे, यदि आप एक सहायक उदाहरण उन दोनों के बीच साझा करते हैं, तो आपके सभी डीबी एक्सेस कोड सीरियल हैं। और जीवन अच्छा है (इश)।

यदि आप एक ही समय में वास्तविक विशिष्ट कनेक्शन से डेटाबेस को लिखने का प्रयास करते हैं, तो कोई भी विफल हो जाएगा। यह पहली बार किया जाता है जब तक इंतजार नहीं करेगा और फिर लिखना। यह बस आपके परिवर्तन नहीं लिखेंगे इससे भी बदतर, यदि आप SQLiteDatabase पर डालने / अपडेट का सही संस्करण नहीं कहते हैं, तो आपको एक अपवाद नहीं मिलेगा। आपको अपने लॉककैट में एक संदेश मिलेगा, और वह यह होगा।

तो, कई धागे? एक सहायक का उपयोग करें अवधि। यदि आप केवल एक धागा लिखेंगे, तो आप कई कनेक्शन का उपयोग करने में सक्षम हो सकते हैं, और आपका पढ़ना तेज़ हो जाएगा, लेकिन खरीदार सावधान रहना मैंने इतना परीक्षण नहीं किया है

यहां एक ब्लॉग पोस्ट है जिसमें अधिक विस्तार और एक उदाहरण ऐप शामिल है

  • एंड्रॉइड स्काइलाइट लॉकिंग (अद्यतन लिंक 6/18/2012)
  • एंड्रॉइड-डाटाबेस-लॉकिंग-कॉलीज़ेंस-उदाहरण के लिए टिटलाब द्वारा गिटहब पर

ग्रे और मैं वास्तव में अपने ORmlite के आधार पर एक ORM उपकरण लपेट कर रहे हैं, जो एंड्रॉइड डाटाबेस कार्यान्वयन के साथ मूल रूप से काम करता है और सुरक्षित निर्माण / कॉलिंग संरचना का वर्णन करता है जो मैं ब्लॉग पोस्ट में बताता हूं। यह बहुत जल्द बाहर होना चाहिए जरा देखो तो।


इस दौरान, ब्लॉग पोस्ट का पालन करें:

  • सिंगल एसक्यूएलएक्ट कनेक्शन

पहले उल्लेख किए गए लॉकिंग उदाहरण के 2point0 द्वारा कांटा की जांच भी करें:

  • एंड्रॉइड-डाटाबेस-लॉकिंग-कॉलीज़ेंस-उदाहरण गिटहब पर 2point0 द्वारा

समवर्ती डेटाबेस एक्सेस

मेरे ब्लॉग पर एक ही लेख (मुझे अधिक स्वरूपण पसंद है)

मैंने एक छोटे से लेख लिखा था, जो बताता है कि आपके एंड्रॉइड डाटाबेस थ्रेड को सुरक्षित कैसे बना सकता है।


मान लें कि आपके पास अपना स्वयं का SQLiteOpenHelper है

public class DatabaseHelper extends SQLiteOpenHelper { ... } 

अब आप डेटाबेस को अलग थ्रेड में डाटा लिखना चाहते हैं।

  // Thread 1 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); SQLiteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close(); // Thread 2 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); SQLiteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close(); 

आपको अपने लॉककैट में निम्नलिखित संदेश मिलेंगे और आपके परिवर्तनों में से कोई भी लिखा नहीं जाएगा।

 android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5) 

यह हो रहा है क्योंकि हर बार जब आप नई SQLiteOpenHelper वस्तु बनाते हैं तो आप वास्तव में नए डेटाबेस कनेक्शन बना रहे हैं। यदि आप एक ही समय में वास्तविक विशिष्ट कनेक्शन से डेटाबेस को लिखने का प्रयास करते हैं, तो कोई भी विफल हो जाएगा। (उपरोक्त उत्तर से)

डेटाबेस को कई सूत्रों के साथ उपयोग करने के लिए हमें यह सुनिश्चित करना होगा कि हम एक डेटाबेस कनेक्शन का उपयोग कर रहे हैं।

सिंगलटन क्लास डेटाबेस प्रबंधक बनाते हैं जो एक SQLiteOpenHelper ऑब्जेक्ट को पकड़ और वापस करेगा।

 public class DatabaseManager { private static DatabaseManager instance; private static SQLiteOpenHelper mDatabaseHelper; public static synchronized void initializeInstance(SQLiteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized, call initialize(..) method first."); } return instance; } public SQLiteDatabase getDatabase() { return new mDatabaseHelper.getWritableDatabase(); } } 

अद्यतित कोड जो डेटाबेस को अलग थ्रेड में डेटा लिखते हैं, वह इस तरह दिखेगा।

  // In your application class DatabaseManager.initializeInstance(new MySQLiteOpenHelper()); // Thread 1 DatabaseManager manager = DatabaseManager.getInstance(); SQLiteDatabase database = manager.getDatabase() database.insert(…); database.close(); // Thread 2 DatabaseManager manager = DatabaseManager.getInstance(); SQLiteDatabase database = manager.getDatabase() database.insert(…); database.close(); 

यह आपको एक और क्रैश लाएगा

 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase 

चूंकि हम केवल एक डेटाबेस कनेक्शन का उपयोग कर रहे हैं, विधि getDatabase () थ्रेड 1 और थ्रेड 2 के लिए SQLiteDatabase ऑब्जेक्ट का एक ही उदाहरण लौटाते हैं । क्या हो रहा है, Thread1 डेटाबेस बंद कर सकता है, जबकि थ्रेड 2 अभी भी इसका उपयोग कर रहा है। यही कारण है कि हमारे पास IllegalStateException दुर्घटना है

हमें यह सुनिश्चित करने की आवश्यकता है कि कोई भी डाटाबेस का उपयोग न करें और उसके बाद ही इसे बंद कर दें। Stackoveflow पर कुछ लोगों को कभी भी अपने SQLiteDatabase बंद करने की सिफारिश की यह केवल बेवकूफ़ नहीं लग रहा है बल्कि आपको निम्न लॉगकट संदेश के साथ भी सम्मान करता है।

 Leak found Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed 

कार्यशील नमूना

 public class DatabaseManager { private int mOpenCounter; private static DatabaseManager instance; private static SQLiteOpenHelper mDatabaseHelper; private SQLiteDatabase mDatabase; public static synchronized void initializeInstance(SQLiteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized, call initializeInstance(..) method first."); } return instance; } public synchronized SQLiteDatabase openDatabase() { mOpenCounter++; if(mOpenCounter == 1) { // Opening new database mDatabase = mDatabaseHelper.getWritableDatabase(); } return mDatabase; } public synchronized void closeDatabase() { mOpenCounter--; if(mOpenCounter == 0) { // Closing database mDatabase.close(); } } } 

इसका प्रयोग निम्न प्रकार से करें:

 SQLiteDatabase database = DatabaseManager.getInstance().openDatabase(); database.insert(...); // database.close(); Don't close it directly! DatabaseManager.getInstance().closeDatabase(); // correct way 

हर बार जब आपको डेटाबेस की आवश्यकता होती है, तो आपको डेटाबेस मैनेजर क्लास के ओपनडेटाबेस () विधि को कॉल करना चाहिए। इस पद्धति के अंदर, हमारे पास एक काउंटर है, जो बताता है कि डेटाबेस कितनी बार खोलता है। यदि यह एक के बराबर है, तो इसका मतलब है कि हमें नया डेटाबेस कनेक्शन बनाने की आवश्यकता है, यदि नहीं, तो डेटाबेस कनेक्शन पहले से ही बनाया गया है।

वही डाटाबेस में बंद होता है () विधि हर बार जब हम इस विधि को कहते हैं, काउंटर कम हो जाता है, जब भी यह शून्य हो जाता है, हम डेटाबेस कनेक्शन बंद कर रहे हैं


अब आप अपने डेटाबेस का उपयोग करने में सक्षम होना चाहिए और सुनिश्चित करें कि यह थ्रेड सुरक्षित है

  • लंबे समय से चलने वाले कार्यों ( AsyncTask +) के लिए Thread या AsyncTask उपयोग करें। यह देखने के लिए अपने ऐप का परीक्षण करें कि वह कहां है। अधिकांश कार्यों (शायद) को धागा की आवश्यकता नहीं होती है, क्योंकि अधिकांश ऑपरेशन (शायद) केवल कुछ पंक्तियों को शामिल करते हैं थोक कार्रवाई के लिए एक थ्रेड का उपयोग करें
  • थ्रेड्स के बीच डिस्क पर प्रत्येक डीबी के लिए एक SQLiteDatabase उदाहरण साझा करें और ओपन कनेक्शन का ट्रैक रखने के लिए एक गिनती प्रणाली को लागू करें।

क्या इन स्थितियों के लिए कोई सर्वोत्तम पद्धतियां हैं?

अपनी सभी कक्षाओं के बीच एक स्थिर फ़ील्ड साझा करें मैं उस और अन्य चीजों के लिए एक सिंगलटन के आसपास रखता था जिसे साझा करने की आवश्यकता होती है। एक गिनती योजना (आम तौर पर परमाणुइंटेगर का उपयोग करके) का उपयोग भी सुनिश्चित करने के लिए किया जाना चाहिए कि आप डेटाबेस को कभी भी बंद नहीं करते या इसे खोलकर नहीं छोड़ते हैं

मेरा समाधान:

सबसे वर्तमान संस्करण के लिए, https://github.com/jakarCo/databasemanager देखें लेकिन मैं कोड को आज तक यहां तक ​​रखने की कोशिश करूंगा। यदि आप मेरे समाधान को समझना चाहते हैं, तो कोड देखें और मेरे नोट पढ़ें। मेरे नोट्स आमतौर पर बहुत उपयोगी होते हैं

  1. CodeManager नामक एक नई फ़ाइल में कोड कॉपी / पेस्ट करें। (या इसे गिटूब से डाउनलोड)
  2. DatabaseManager onUpgrade का विस्तार करें और onUpgrade और onUpgrade लागू करें जैसे आप सामान्य रूप से करेंगे। डिस्क पर अलग-अलग डेटाबेस के लिए आप एक DatabaseManager वर्ग के कई उप-वर्ग बना सकते हैं।
  3. getDb() वर्ग का उपयोग करने के लिए अपने उपवर्ग को getDb() करें और getDb() को कॉल करें
  4. प्रत्येक उपवर्ग के लिए कॉल close()

कॉपी / पेस्ट करने के लिए कोड:

 import android.content.Context; import android.database.sqlite.SQLiteDatabase; import java.util.concurrent.ConcurrentHashMap; /** Extend this class and use it as an SQLiteOpenHelper class * * DO NOT distribute, sell, or present this code as your own. * for any distributing/selling, or whatever, see the info at the link below * * Distribution, attribution, legal stuff, * See https://github.com/JakarCo/databasemanager * * If you ever need help with this code, contact me at support@androidsqlitelibrary.com (or support@jakar.co ) * * Do not sell this. but use it as much as you want. There are no implied or express warranties with this code. * * This is a simple database manager class which makes threading/synchronization super easy. * * Extend this class and use it like an SQLiteOpenHelper, but use it as follows: * Instantiate this class once in each thread that uses the database. * Make sure to call {@link #close()} on every opened instance of this class * If it is closed, then call {@link #open()} before using again. * * Call {@link #getDb()} to get an instance of the underlying SQLiteDatabse class (which is synchronized) * * I also implement this system (well, it's very similar) in my <a href="http://androidslitelibrary.com">Android SQLite Libray</a> at http://androidslitelibrary.com * * */ abstract public class DatabaseManager { /**See SQLiteOpenHelper documentation */ abstract public void onCreate(SQLiteDatabase db); /**See SQLiteOpenHelper documentation */ abstract public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); /**Optional. * * */ public void onOpen(SQLiteDatabase db){} /**Optional. * */ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {} /**Optional * */ public void onConfigure(SQLiteDatabase db){} /** The SQLiteOpenHelper class is not actually used by your application. * */ static private class DBSQLiteOpenHelper extends SQLiteOpenHelper { DatabaseManager databaseManager; private AtomicInteger counter = new AtomicInteger(0); public DBSQLiteOpenHelper(Context context, String name, int version, DatabaseManager databaseManager) { super(context, name, null, version); this.databaseManager = databaseManager; } public void addConnection(){ counter.incrementAndGet(); } public void removeConnection(){ counter.decrementAndGet(); } public int getCounter() { return counter.get(); } @Override public void onCreate(SQLiteDatabase db) { databaseManager.onCreate(db); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { databaseManager.onUpgrade(db, oldVersion, newVersion); } @Override public void onOpen(SQLiteDatabase db) { databaseManager.onOpen(db); } @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { databaseManager.onDowngrade(db, oldVersion, newVersion); } @Override public void onConfigure(SQLiteDatabase db) { databaseManager.onConfigure(db); } } private static final ConcurrentHashMap<String,DBSQLiteOpenHelper> dbMap = new ConcurrentHashMap<String, DBSQLiteOpenHelper>(); private static final Object lockObject = new Object(); private DBSQLiteOpenHelper sqLiteOpenHelper; private SQLiteDatabase db; private Context context; /** Instantiate a new DB Helper. * <br> SQLiteOpenHelpers are statically cached so they (and their internally cached SQLiteDatabases) will be reused for concurrency * * @param context Any {@link android.content.Context} belonging to your package. * @param name The database name. This may be anything you like. Adding a file extension is not required and any file extension you would like to use is fine. * @param version the database version. */ public DatabaseManager(Context context, String name, int version) { String dbPath = context.getApplicationContext().getDatabasePath(name).getAbsolutePath(); synchronized (lockObject) { sqLiteOpenHelper = dbMap.get(dbPath); if (sqLiteOpenHelper==null) { sqLiteOpenHelper = new DBSQLiteOpenHelper(context, name, version, this); dbMap.put(dbPath,sqLiteOpenHelper); } //SQLiteOpenHelper class caches the SQLiteDatabase, so this will be the same SQLiteDatabase object every time db = sqLiteOpenHelper.getWritableDatabase(); } this.context = context.getApplicationContext(); } /**Get the writable SQLiteDatabase */ public SQLiteDatabase getDb(){ return db; } /** Check if the underlying SQLiteDatabase is open * * @return whether the DB is open or not */ public boolean isOpen(){ return (db!=null&&db.isOpen()); } /** Lowers the DB counter by 1 for any {@link DatabaseManager}s referencing the same DB on disk * <br />If the new counter is 0, then the database will be closed. * <br /><br />This needs to be called before application exit. * <br />If the counter is 0, then the underlying SQLiteDatabase is <b>null</b> until another DatabaseManager is instantiated or you call {@link #open()} * * @return true if the underlying {@link android.database.sqlite.SQLiteDatabase} is closed (counter is 0), and false otherwise (counter > 0) */ public boolean close(){ sqLiteOpenHelper.removeConnection(); if (sqLiteOpenHelper.getCounter()==0){ synchronized (lockObject){ if (db.inTransaction())db.endTransaction(); if (db.isOpen())db.close(); db = null; } return true; } return false; } /** Increments the internal db counter by one and opens the db if needed * */ public void open(){ sqLiteOpenHelper.addConnection(); if (db==null||!db.isOpen()){ synchronized (lockObject){ db = sqLiteOpenHelper.getWritableDatabase(); } } } } 

डेटाबेस बहु-थ्रेडिंग के साथ बहुत लचीला है। मेरे ऐप्स ने कई तरह के थ्रेड्स से अपने डीबी को एक साथ मारा और यह सिर्फ ठीक है। कुछ मामलों में मुझे एक साथ डीबी को एक साथ मारते हुए कई प्रक्रियाएं होती हैं और वह भी ठीक काम करती हैं I

आपके एएससीएनसी कार्य – जब आप कर सकते हैं, तो उसी कनेक्शन का उपयोग करें, लेकिन यदि आपको करना है, तो अलग कार्य से डीबी तक पहुंचने के लिए इसका ठीक है।

डीमैटरो का उत्तर मेरे मामले के लिए ठीक काम करता है मुझे लगता है कि फ़ंक्शन को सिंक्रनाइज़ किए जाने के रूप में घोषित करना बेहतर है। कम से कम मेरे मामले के लिए, यह शून्य सूचक आवेदक को लागू करेगा अन्यथा, उदाहरण के लिए मिलते हैं डब्लूरेबेटडेटाबेस अभी एक धागे में नहीं लौटाया गया है और ओपन डीबेस एक दूसरे धागे में कहा जाता है।

 public synchronized SQLiteDatabase openDatabase() { if(mOpenCounter.incrementAndGet() == 1) { // Opening new database mDatabase = mDatabaseHelper.getWritableDatabase(); } return mDatabase; } 

SQLiteDatabase API की मेरी समझ यह है कि यदि आपके पास एक बहु थ्रेडेड एप्लिकेशन है, तो आप एक एकल SQLiteDatabase ऑब्जेक्ट को एक एकल डेटाबेस की ओर इशारा कर सकते हैं।

ऑब्जेक्ट निश्चित रूप से बनाया जा सकता है लेकिन सम्मिलित / अपडेट विफल हो जाते हैं यदि अलग थ्रेड / प्रोसेस (भी) अलग SQLiteDatabase ऑब्जेक्ट्स का उपयोग शुरू करते हैं (जैसे हम जेडीबीसी कनेक्शन में कैसे उपयोग करते हैं)।

यहां एकमात्र समाधान 1 SQLiteDatabase ऑब्जेक्ट्स के साथ छड़ी करना है और जब भी 1 थ्रेड से अधिक में स्टार्टट्रांससंज़ () का उपयोग किया जाता है, तो एंड्रॉइड लॉकिंग को विभिन्न थ्रेड्स में प्रबंधित करता है और एक समय में अनन्य अपडेट एक्सेस के लिए केवल 1 थ्रेड को ही अनुमति देता है।

इसके अलावा आप डेटाबेस से "रीड्स" भी कर सकते हैं और एक अलग थ्रेड (एक और धागा लिखते हैं) में एक ही SQLiteDatabase ऑब्जेक्ट का उपयोग कर सकते हैं और कभी भी डेटाबेस भ्रष्टाचार नहीं होगा "पढ़ने के धागे" डेटाबेस से डेटा को " लिखते थ्रेड "डेटा बनाते हैं, हालांकि दोनों एक ही SQLiteDatabase ऑब्जेक्ट का उपयोग करते हैं

यह कैसे जेडीबीसी में कनेक्शन ऑब्जेक्ट से अलग है, अगर आप पढ़ने के लिए और थ्रेड लिखने के बीच कनेक्शन ऑब्जेक्ट (ऑप्शन का इस्तेमाल) करते हैं तो हम संभवत: अनकही डाटा भी प्रिंट करेंगे।

मेरे एंटरप्राइज़ एप्लिकेशन में, मैं सशर्त चेक का उपयोग करने की कोशिश करता हूं ताकि यूआई थ्रेड को कभी इंतजार न करना पड़े, जबकि बीजी धागा SQLiteDatabase ऑब्जेक्ट (केवल) मैं यूआई क्रियाओं की भविष्यवाणी करने की कोशिश करता हूं और बीजी धागा को 'एक्स' सेकंड के लिए चलने से रोकता हूं। इसके अलावा कोई भी SQLiteDatabase कनेक्शन ऑब्जेक्ट को सौंपने का प्रबंधन करने के लिए प्राथमिकता प्रश्न रख सकता है ताकि UI थ्रेड इसे पहले प्राप्त हो।

कुछ घंटों के लिए इस के साथ संघर्ष करने के बाद, मैंने पाया है कि आप केवल एक डीबी सहायक ऑब्जेक्ट प्रति डीबी निष्पादन का उपयोग कर सकते हैं। उदाहरण के लिए,

 for(int x = 0; x < someMaxValue; x++) { db = new DBAdapter(this); try { db.addRow ( NamesStringArray[i].toString(), StartTimeStringArray[i].toString(), EndTimeStringArray[i].toString() ); } catch (Exception e) { Log.e("Add Error", e.toString()); e.printStackTrace(); } db.close(); } 

के रूप में करने के लिए apposed:

 db = new DBAdapter(this); for(int x = 0; x < someMaxValue; x++) { try { // ask the database manager to add a row given the two strings db.addRow ( NamesStringArray[i].toString(), StartTimeStringArray[i].toString(), EndTimeStringArray[i].toString() ); } catch (Exception e) { Log.e("Add Error", e.toString()); e.printStackTrace(); } } db.close(); 

हर बार एक नया डीबीएडैप्टर बनाने के लिए लूप रीटरेट एकमात्र तरीका था जिसमे मैं अपने सहायक वर्ग के माध्यम से एक डाटाबेस में मिल सकता था।

कुछ मुद्दे होने के बाद, मुझे लगता है कि मुझे समझ में आ रहा है कि मैं गलत क्यों रहा हूं।

मैंने एक डेटाबेस आवरण वर्ग लिखा था जिसमें एक close() , जिसे open() दर्पण के रूप में सहायक बंद कहा जाता था, जिसे GetWriteableDatabase कहा जाता था और फिर एक ContentProvider पर माइग्रेट किया था ContentProvider लिए मॉडल ContentProvider SQLiteDatabase.close() उपयोग नहीं करता है जो मुझे लगता है कि एक बड़ा सुराग है क्योंकि कोड का उपयोग करता है getWriteableDatabase कुछ उदाहरणों में मैं अभी भी सीधी पहुंच (स्क्रीन सत्यापन क्वेरीज़ मुख्य में कर रहा था इसलिए मैं एक getWriteableDatabase / rawQuery मॉडल ।

मैं सिंगलटन का उपयोग करता हूं और करीब दस्तावेज में थोड़ा अशुभ टिप्पणी है

किसी भी खुले डेटाबेस वस्तु को बंद करें

(मेरे बोल्डिंग)

इसलिए मुझे आंतरायिक क्रैश हुआ है, जहां मैं डेटाबेस का उपयोग करने के लिए पृष्ठभूमि थ्रेड का उपयोग करता हूं और वे अग्रभूमि के समान ही चलते हैं।

इसलिए मुझे लगता है कि close() बलों को संदर्भित करने वाले किसी अन्य थ्रेड्स के बावजूद बंद करने के लिए डेटाबेस को बंद किया जाता है – इतना ही close() खुद मेल मिलते getWriteableDatabase लेकिन किसी भी खुली अनुरोध को बंद करने पर बल देता है। अधिकांश समय यह समस्या नहीं है क्योंकि कोड एकल थ्रेडिंग है, लेकिन बहु-थ्रेडेड मामलों में हमेशा सिंक के उद्घाटन और समापन का मौका होता है।

SqliteDatabaseHelper कोड उदाहरण की गणना करता है, तो आप बता सकते हैं कि केवल एक बार जब आप एक स्थिति चाहते हैं, जहां आप बैकअप प्रति बनाना चाहते हैं, और आप सभी कनेक्शन बंद करना चाहते हैं और SqLite को बल देना चाहते हैं किसी भी कैश्ड सामग्री को दूर लिखें – हो सकता है कि दूसरे शब्दों में, सभी एप्लीकेशन डाटाबेस गतिविधि को रोक दें, अगर हेल्पर ने ट्रैक खो दिया हो, तो किसी भी फाइल स्तरीय गतिविधि (बैकअप / पुनर्स्थापना) करें तो फिर से सभी को फिर से शुरू करें

यद्यपि यह एक नियंत्रित तरीके से कोशिश करने और बंद करने के लिए एक अच्छा विचार है, लेकिन वास्तविकता यह है कि एंड्रॉइड अपने वीएम को कचरा देने का अधिकार सुरक्षित रखता है ताकि किसी भी बंद को कैश्ड अद्यतनों के जोखिम को कम नहीं किया जा रहा हो, लेकिन इसकी गारंटी नहीं दी जा सकती है कि डिवाइस पर बल दिया गया है, और यदि आप अपने कर्सर को सही तरीके से मुक्त कर चुके हैं और डेटाबेस के संदर्भ (जो कि स्थैतिक सदस्य नहीं हो) तो सहायक ने डेटाबेस को वैसे भी बंद कर दिया होगा।

तो मेरा यही तरीका है कि दृष्टिकोण है:

एक सिंगलटन आवरण से खोलने के लिए getWriteableDatabase का उपयोग करें। (एक संदर्भ के लिए जरूरत को हल करने के लिए मैं स्थिर संदर्भ से एप्लिकेशन संदर्भ को प्रदान करने के लिए एक व्युत्पन्न अनुप्रयोग वर्ग का उपयोग किया था)।

सीधे बंद कॉल कभी नहीं

किसी भी ऑब्जेक्ट में परिणामी डेटाबेस को कभी भी संग्रहित न करें, जिसमें स्पष्ट रूप से कोई गुंजाइश नहीं है और एक गहन बंद (ट्रिगर) ट्रिगर करने के लिए संदर्भ गणना पर भरोसा करते हैं।

यदि फ़ाइल स्तर पर हैंडलिंग कर रही है, तो सभी डाटाबेस गतिविधि को रोकें और फिर बंद करें, बस इस मामले पर भगोड़ा धागा है, जब आप उचित लेनदेन लिखते हैं तो भगोड़ा धागा असफल हो जायेगा और बंद डाटाबेस में कम से कम सही लेनदेन होगा आंशिक लेनदेन के संभावित रूप से फ़ाइल स्तर की प्रतिलिपि से

आप Google I / O 2017 पर प्रकाशित नए आर्किटेक्चर दृष्टिकोण को लागू करने का प्रयास कर सकते हैं

इसमें कक्ष नामक नए ORM लाइब्रेरी भी शामिल है

इसमें तीन मुख्य घटक हैं: @ एंटीटी, @ डाओ और डैटबेस @

User.java

 @Entity public class User { @PrimaryKey private int uid; @ColumnInfo(name = "first_name") private String firstName; @ColumnInfo(name = "last_name") private String lastName; // Getters and setters are ignored for brevity, // but they're required for Room to work. } 

UserDao.java

 @Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE uid IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") User findByName(String first, String last); @Insert void insertAll(User... users); @Delete void delete(User user); } 

AppDatabase.java

 @Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); } 

मुझे पता है कि प्रतिक्रिया देर हो चुकी है, लेकिन एंड्रॉइड में एसक्यूलेट प्रश्नों को निष्पादित करने का सबसे अच्छा तरीका कस्टम कंटेंट प्रदाता के माध्यम से है। इस तरह से यूआई डेटाबेस क्लास के साथ decoupled है (वर्ग जो SQLiteOpenHelper वर्ग को फैली हुई है) इसके अलावा, क्वेरी पृष्ठभूमि पृष्ठभूमि (कर्सर लोडर) में क्रियान्वित की जाती हैं।