Android बैकअप / पुनर्स्थापना: आंतरिक डेटाबेस का बैकअप कैसे लें?


86

मैंने BackupAgentHelperउपलब्ध कराए FileBackupHelperगए बैकअप का उपयोग करके और मेरे पास मूल डेटाबेस को पुनर्स्थापित करने के लिए लागू किया है। यह वह डेटाबेस है जिसका आप आमतौर पर उपयोग करते हैं ContentProvidersऔर जो अंदर रहता है /data/data/yourpackage/databases/

किसी को लगता है कि यह एक सामान्य मामला है। हालाँकि डॉक्स स्पष्ट नहीं है कि क्या करना है: http://developer.android.com/guide/topics/data/backup.htmlइन विशिष्ट डेटाबेस के लिए कोई BackupHelperविशेष रूप से नहीं है। इसलिए मैंनेFileBackupHelper ".bb फ़ाइल" में इंगित किया , "। /databases/" में किसी भी db ऑपरेशन (जैसे कि db.insert) के चारों ओर ताले लगा दिए ContentProviders, और यहां तक ​​कि " /databases/" निर्देशिका को पहले बनाने की कोशिश की onRestore()क्योंकि यह स्थापित होने के बाद मौजूद नहीं है।

मैंने SharedPreferencesअतीत में एक अलग ऐप में सफलतापूर्वक एक समान समाधान लागू किया है। हालाँकि जब मैं एमुलेटर -२.२ में अपने नए कार्यान्वयन का परीक्षण करता हूं, तो मुझे LocalTransportलॉग से प्रदर्शन किया जा रहा बैकअप दिखाई देता है , साथ ही एक पुनर्स्थापना (और onRestore()कहा जाता है) भी किया जाता है। फिर भी, db फ़ाइल ही कभी नहीं बनाई जाती है।

ध्यान दें कि यह सब एक इंस्टालेशन के बाद है, और ऐप के पहले लॉन्च से पहले, रिस्टोर होने के बाद। इसके अलावा मेरी परीक्षण रणनीति http://developer.android.com/guide/topics/data/backup.html#Testing पर आधारित थी ।

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

मैंने कस्टम का उपयोग करने की सलाह देने वाले डेटाबेस के बारे में डॉक्स में एक उल्लेख देखा, BackupAgentलेकिन यह संबंधित नहीं लगता है:

हालाँकि, यदि आप की जरूरत है तो आप सीधे BackupAgent का विस्तार कर सकते हैं: * डेटाबेस में डेटा का बैकअप लें। यदि आपके पास एक SQLite डेटाबेस है जिसे आप तब पुनर्स्थापित करना चाहते हैं जब उपयोगकर्ता आपके एप्लिकेशन को फिर से इंस्टॉल करता है, तो आपको एक कस्टम बैकअपअर्जेंट बनाने की आवश्यकता होती है जो बैकअप ऑपरेशन के दौरान उपयुक्त डेटा पढ़ता है, फिर अपनी तालिका बनाएं और पुनर्स्थापना कार्रवाई के दौरान डेटा डालें।

कुछ स्पष्टता कृपया।

अगर मुझे वास्तव में इसे SQL स्तर तक स्वयं करने की आवश्यकता है, तो मैं निम्नलिखित विषयों के बारे में चिंतित हूं:

  • डेटाबेस और लेनदेन खोलें। मुझे नहीं पता कि मुझे अपने ऐप के वर्कफ़्लो के बाहर ऐसे एकल वर्ग से कैसे बंद करना है।

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

  • पुनर्स्थापना पर समान कैसे करें। जैसा कि मैं समझता हूं, पुनर्स्थापना बस तब हो सकती है जब उपयोगकर्ता पहले ही ऐप का उपयोग करना शुरू कर चुका है (और डेटाबेस में डेटा इनपुट कर रहा है)। इसलिए आप केवल बैक किए गए डेटा को पुनः स्थापित करने (खाली या पुराने डेटा को हटाने) के लिए नहीं मान सकते हैं। आपको किसी तरह इसमें शामिल होना होगा, जो आईडी के कारण किसी भी गैर-तुच्छ डेटाबेस के लिए असंभव है।

  • पुनर्स्थापना के बाद एप्लिकेशन को कैसे रिफ्रेश किया जाए, उपयोगकर्ता को बिना कुछ प्राप्त किए - अब - अप्राप्य बिंदु।

  • क्या मुझे यकीन है कि डेटाबेस को पहले से ही बैकअप या पुनर्स्थापना पर अपग्रेड किया गया है? अन्यथा अपेक्षित स्कीमा मेल नहीं खा सकती है।


मेरे पास एक ही मुद्दा है ...

सरल बैकअप होल डीबी का कोई तरीका नहीं है?
जिन 35

मुझे FileBackupHelper का उपयोग करके एक फ़ोल्डर का बैकअप लेने की आवश्यकता है। बचत डेटाबेस दृष्टिकोण का उपयोग करने से मुझे उस फ़ोल्डर को बचाने की अनुमति मिलेगी जिसमें बहुत सारे उप फ़ोल्डर हैं और इसके नीचे उप फाइलें हैं?
coolcool1994

क्या आपने कभी सही तरीके से यह काम किया?
DeNitE Appz

हाँ, नीचे देखें। मैंने अपने खुद के सवाल का जवाब दिया।
pjv

जवाबों:


21

एक कस्टम बनाने के लिए एक क्लीनर दृष्टिकोण होगा BackupHelper:

public class DbBackupHelper extends FileBackupHelper {

    public DbBackupHelper(Context ctx, String dbName) {
        super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath());
    }
}

और फिर इसे जोड़ें BackupAgentHelper:

public void onCreate() {
    addHelper(DATABASE, new DbBackupHelper(this, DB.FILE));
}

2
@logray: यह कोड उसी तरह का है जैसा प्रश्न में है। अनावश्यक संपादन।
लिनक्स

@Linuxios मैं सहमत हूं, हालाँकि मुझे लगता है कि बेहतर है कि लेखक को उचित रूप से केवल सही कोड पेस्ट करने के बजाए, मूल ओपी / पोस्ट को ध्यान में रखते हुए उसके ऐप से एक लिंक दिया जाए।
लॉग्रे

3
महत्वपूर्ण : (प्रलेखन) ( डेवलपर
.android.com

FileBackupHelper के लिए @yanchenko प्रलेखन में कहा गया है: "नोट: इसका उपयोग केवल छोटे कॉन्फ़िगरेशन फ़ाइलों के साथ किया जाना चाहिए, न कि बड़ी बाइनरी फ़ाइलों के साथ।" इसलिए एक डेटाबेस अक्सर एक बड़ी द्विआधारी फ़ाइल के रूप में अर्हता प्राप्त करेगा ...
इगोरगानपोलस्की

यह वास्तव में काम नहीं करता है! (जब तक मैं कुछ याद नहीं कर रहा हूँ ...)। मुद्दा यह है कि आप DBB के पूर्ण पथ में FileBackupHelper से गुजरते हैं, लेकिन FileBackupHelper पथ निर्देशिका फ़ाइलों जैसे पथ के साथ मार्ग को प्रस्तुत करता है। data / data / <your package> / files जिसके परिणामस्वरूप कुछ गलत पथ होता है जैसे data / data / <your package> / files / data / data / <your package> / database / <DB Name> जब आप चाहते हैं DB निरपेक्ष नाम और चूंकि सुपर क्लास फाइलें डायरेक्टरी प्रस्तुत करती है, इसलिए आपको फाइल डायरेक्टरी के सापेक्ष पथ बनाने की आवश्यकता होती है।
बिटक्रॉक

34

अपने सवाल पर दोबारा गौर करने के बाद, मैं यह देखने के लिए काम करने में सक्षम था कि कनेक्टबॉट यह कैसे करता है । धन्यवाद केनी और जेफरी!

यह वास्तव में जोड़ना जितना आसान है:

FileBackupHelper hosts = new FileBackupHelper(this,
    "../databases/" + HostDatabase.DB_NAME);
addHelper(HostDatabase.DB_NAME, hosts);

अपने को BackupAgentHelper

मैं जिस बिंदु को याद कर रहा था वह यह था कि आपको " ../databases/" के साथ एक सापेक्ष पथ का उपयोग करना होगा ।

फिर भी, यह कोई सही उपाय नहीं है। FileBackupHelperउदाहरण के लिए उल्लेख के लिए डॉक्स : " FileBackupHelperका उपयोग केवल छोटी कॉन्फ़िगरेशन फ़ाइलों के साथ किया जाना चाहिए, बड़ी बाइनरी फ़ाइलों के साथ नहीं। ", उत्तरार्द्ध SQLite डेटाबेस के साथ मामला है।

मैं और अधिक सुझाव प्राप्त करना चाहता हूं, जो हमसे अपेक्षित है (जो उचित समाधान है) में अंतर्दृष्टि, और यह कैसे टूट सकता है, इस पर सलाह।


1
मुझे शायद जोड़ना चाहिए, भले ही यह थोड़ा अनौपचारिक है, यह इस समय बहुत अच्छा काम कर रहा है।
pjv

6
हार्ड-कोडिंग पथ बुराई है।
सूचक नल

@pjv, तो क्या आप प्रत्येक db इंटरैक्शन को सिंक्रनाइज़ करते हैं? मैं एक ही काम कर रहा हूं और यह पता लगाने की कोशिश कर रहा हूं कि मुझे या केवल बयानों के db.open()माध्यम से या क्या सिंक्रनाइज़ करने की आवश्यकता है । db.close()insert
एनएसयूथ 25'14

22

यहाँ फ़ाइलों के रूप में बैकअप डेटाबेस के लिए अभी तक क्लीनर तरीका है। कोई हार्डकोड नहीं।

class MyBackupAgent extends BackupAgentHelper{
   private static final String DB_NAME = "my_db";

   @Override
   public void onCreate(){
      FileBackupHelper dbs = new FileBackupHelper(this, DB_NAME);
      addHelper("dbs", dbs);
   }

   @Override
   public File getFilesDir(){
      File path = getDatabasePath(DB_NAME);
      return path.getParentFile();
   }
}

ध्यान दें: यह getFilesDir को ओवरराइड करता है ताकि डेटाबेसबिर में FileBackupHelper काम करे, न कि फाइलें dir।

एक और संकेत: आप अपने सभी डीबी प्राप्त करने के लिए डेटाबेस सूची का उपयोग कर सकते हैं और इस सूची से (मूल पथ के बिना) फाइलबेकअप हेल्पर में फ़ीड कर सकते हैं। फिर सभी ऐप का DB बैकअप में सेव हो जाएगा।


@Pjv द्वारा दिए गए समाधान के साथ इसे मिलाकर पूरी तरह से काम करता है! यह बिल्कुल वैसा नहीं हो सकता जैसा कि विनिर्देशों को ध्यान में रखा गया था ... लेकिन यह काफी अच्छी तरह से काम करता है!
टॉम

1
यदि आपके पास डेटाबेस और सामान्य फ़ाइलों का बैकअप लेने के लिए बहुत अधिक उपयोग नहीं है ।
डैन हुल्मे

1
@ दान: उस स्थिति में कई एजेंटों का उपयोग करें।
pjv

@ पॉइंटर नल आपको एक से अधिक एक getFilesDir () विस्तृत कर सकता है, वास्तव में इसकी आवश्यकता क्यों है और क्यों? यह कैसे काम करता है?
पाउडर 366

7

FileBackupHelperबैकअप / रिक्वायरमेंट का उपयोग करने के लिए sqlite db कुछ गंभीर प्रश्न उठाता है:
1. क्या होता है यदि ऐप कर्सर से प्राप्त कर्सर का उपयोग करता है ContentProvider.query()और बैकअप एजेंट पूरी फ़ाइल को ओवरराइड करने की कोशिश करता है?
2. लिंक सही (कम ट्रॉफी?) परीक्षण का एक अच्छा उदाहरण है। आप ऐप को अनइंस्टॉल करते हैं, इसे फिर से इंस्टॉल करते हैं और बैकअप बहाल हो जाता है। हालाँकि जीवन क्रूर हो सकता है। लिंक पर एक नज़र डालें । आइए परिदृश्य की कल्पना करें जब कोई उपयोगकर्ता एक नया उपकरण खरीदता है। चूंकि इसके पास अपना सेट नहीं है, इसलिए बैकअप एजेंट अन्य डिवाइस के सेट का उपयोग करता है। एप्लिकेशन इंस्टॉल किया गया है और आपका बैकअप हेल्पर पुरानी फ़ाइल को वर्तमान से कम db संस्करण स्कीमा के साथ पुनर्प्राप्त करता है। डिफ़ॉल्ट कार्यान्वयन के साथ SQLiteOpenHelperकॉल onDowngrade:

public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    throw new SQLiteException("Can't downgrade database from version " +
            oldVersion + " to " + newVersion);
}

कोई फर्क नहीं पड़ता कि उपयोगकर्ता क्या करता है / वह नए डिवाइस पर आपके ऐप का उपयोग नहीं कर सकता है।

मैं सुझाव देता हूं कि ContentResolverडेटा प्राप्त करने के लिए उपयोग करें - _idबैकअप के लिए क्रमबद्ध (बिना ) और डिस्क्रिअलाइज़ के बिना -> पुनर्स्थापना के लिए डेटा डालें।

नोट: डेटा प्राप्त / सम्मिलित करना ContentResolver के माध्यम से किया जाता है और इस प्रकार cuncurrency मुद्दों से बचा जाता है। Serializing आपके backupAgent में किया जाता है। यदि आप अपना स्वयं का कर्सर करते हैं तो <-> वस्तु को क्रमबद्ध करने वाली वस्तु मैपिंग आपकी इकाई का प्रतिनिधित्व करने वाले वर्ग पर फ़ील्ड _id के Serializableसाथ लागू करने के रूप में सरल हो सकती है transient

मैं बल्क इंसर्ट यानी ContentProviderOperation उदाहरण भी इस्तेमाल करूंगा और CursorLoader.setUpdateThrottleताकि ऐप बैकअप रिस्टोर प्रक्रिया के दौरान डेटा चेंज पर लोडर को रिस्टार्ट करने के साथ अटक न जाए।

यदि आप ऐसा करते हैं, तो आप डाउनग्रेड की स्थिति में हैं, तो आप डेटा को रिस्टोर करने या रिस्टोर करने के लिए चुन सकते हैं और डाउनग्रेड संस्करण के लिए प्रासंगिक फ़ील्ड्स के साथ ContentResolver को अपडेट कर सकते हैं।

मैं मानता हूं कि विषय आसान नहीं है, डॉक्स में अच्छी तरह से समझाया नहीं गया है और कुछ प्रश्न अभी भी थोक डेटा आकार आदि जैसे हैं।

उम्मीद है की यह मदद करेगा।


आप कुछ मान्य प्रश्न दोहराते हैं। लेकिन मैं यह नहीं देखता कि डेटाबेस को क्रमबद्ध करने से समस्या हल कैसे होती है यह समसामयिक मुद्दों के साथ मदद नहीं करता है। और यदि आप डेटाबेस को डाउनग्रेड करने के लिए कोई स्क्रिप्ट नहीं लिख सकते हैं, तो आप पुराने डेटा को डिस्क्राइब करने के लिए स्क्रिप्ट नहीं लिख सकते हैं।
पीपीवी

यदि आप एक ContentResolver का उपयोग करते हैं, तो यह आपके लिए समसामयिक मुद्दों को हल करता है।
इगोरगानापोलस्की 20

@IgorGanapolsky हाँ, मुझे लगता है कि यह सच है। हालाँकि, यदि क्रमांकन काफी धीमा है और उपयोगकर्ता पहले से ही ऐप का उपयोग कर रहा है और डेटा इनपुट कर रहा है, तो यह उस डेटा के साथ विरोध कर सकता है जिसे आप पुनर्स्थापित कर रहे हैं। क्या आप इसे एटोमिक और उपयोगकर्ता द्वारा ऐप तक पहुंचने से पहले कर सकते हैं?
pjv

@pjv आप उस डेटा को सिंक्रनाइज़ करने के लिए एक ContentObserver पंजीकृत कर सकते हैं जिसे आप अधिसूचित किए जाने के लिए देख रहे हैं। इसलिए आपको संघर्षों की चिंता करने की आवश्यकता नहीं है।
इगोरगानापोलस्की

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

3

एंड्रॉइड एम के रूप में, अब एक पूर्ण-डेटा बैकअप / एप्लिकेशन के लिए उपलब्ध एपीआई बहाल है। इस नए एपीआई में ऐप मैनिफ़ेस्ट में एक्सएमएल-आधारित स्पेसिफिकेशन शामिल है जो डेवलपर को यह बताता है कि कौन सी फाइलों को सीधे अर्थेटिक तरीके से बैकअप लेना है: '' mydata.db '' नामक डेटाबेस का बैकअप लें। यह नया एपीआई डेवलपर्स के लिए उपयोग करने के लिए बहुत आसान है - आपको अलग से ट्रैक रखने या बैकअप पास का अनुरोध स्पष्ट रूप से करने की आवश्यकता नहीं है, और XML विवरण जिसमें से फ़ाइलों का बैकअप लेने का मतलब है कि आपको अक्सर कोई कोड लिखने की आवश्यकता नहीं है। बिलकुल।

(आप पुनर्स्थापना होने पर कॉलबैक प्राप्त करने के लिए एक पूर्ण-डेटा बैकअप / पुनर्स्थापना कार्रवाई में भी शामिल हो सकते हैं, उदाहरण के लिए: इस तरह से लचीला है।)

नए API का उपयोग करने के तरीके के विवरण के लिए डेवलपर.android.com पर एप्लिकेशन अनुभाग के लिए कॉन्फ़िगरिंग ऑटो बैकअप देखें ।


यह केवल एंड्रॉइड 6.0 (एपीआई 23) के लिए है, अगर उपयोगकर्ता के पास पुराने संस्करण एक है तो भी कुंजी मूल्य बैकअप लागू करना होगा।
लाइव-लव

0

एक विकल्प डेटाबेस के ऊपर एप्लिकेशन लॉजिक में इसका निर्माण करना होगा। यह वास्तव में मुझे लगता है कि इस तरह के स्तर के लिए चिल्लाती है। निश्चित नहीं है कि आप इसे पहले से कर रहे हैं, लेकिन अधिकांश लोग (Android सामग्री प्रबंधक कर्सर दृष्टिकोण के बावजूद) कुछ ORM मैपिंग - या तो कस्टम या कुछ orm- लाइट दृष्टिकोण का परिचय देंगे। और इस मामले में मैं क्या करूंगा:

  1. यह सुनिश्चित करने के लिए कि एप्लिकेशन / डेटा बैकग्राउंड में नए डेटा के साथ जोड़ा / हटा दिया गया है जब एप्लिकेशन पहले से ही शुरू हो गया है तो आपका एप्लिकेशन ठीक काम करता है
  2. कुछ जावा-> प्रोटोबुफ़ या यहाँ तक कि जावा क्रमांकन मानचित्रण बनाने के लिए और स्ट्रीम से डेटा पढ़ने के लिए अपना खुद का बैकअप हेल्पर लिखें और बस इसे डेटाबेस में जोड़ें ...।

तो इस मामले में यह db स्तर पर करने के बजाय आवेदन स्तर पर करते हैं।


समस्या यह नहीं है कि बैकअपहेल्परएजेंट में डेटाबेस से डेटा कैसे प्राप्त किया जाए या इसके विपरीत। कृपया मेरे प्रश्न के अंत में 5 गोलियों को पढ़ें।
pjv

@JarekPotiuk आपने कहा: "अधिकांश लोग (Android सामग्री प्रबंधक कर्सर दृष्टिकोण के बावजूद)"। लेकिन आपको क्या लगता है कि ज्यादातर लोग डेटाबेस एक्सेस के लिए एक ContentProvider और ContentResolver का उपयोग करने से बचेंगे?
इगोरगानापोलस्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.