অ্যান্ড্রয়েড ব্যাকআপ পরিষেবার সাথে কী-মানের জোড়া ব্যাক আপ করুন

অ্যান্ড্রয়েড ব্যাকআপ পরিষেবা ক্লাউড স্টোরেজ ব্যাকআপ প্রদান করে এবং আপনার অ্যান্ড্রয়েড অ্যাপে মূল-মূল্যের ডেটা পুনরুদ্ধার করে। একটি মূল-মান ব্যাকআপ অপারেশন চলাকালীন, অ্যাপের ব্যাকআপ ডেটা ডিভাইসের ব্যাকআপ পরিবহনে পাঠানো হয়। ডিভাইসটি যদি ডিফল্ট Google ব্যাকআপ ট্রান্সপোর্ট ব্যবহার করে, তাহলে ডেটা সংরক্ষণের জন্য Android ব্যাকআপ পরিষেবাতে পাঠানো হয়।

আপনার অ্যাপের ব্যবহারকারী প্রতি 5MB ডেটা সীমাবদ্ধ। ব্যাকআপ ডেটা সংরক্ষণের জন্য কোন চার্জ নেই।

অ্যান্ড্রয়েডের ব্যাকআপ বিকল্পগুলির একটি ওভারভিউ এবং কোন ডেটা আপনার ব্যাক আপ এবং পুনরুদ্ধার করা উচিত সে সম্পর্কে নির্দেশিকা জন্য, ডেটা ব্যাকআপ ওভারভিউ দেখুন৷

কী-মান ব্যাকআপ প্রয়োগ করুন

আপনার অ্যাপ ডেটা ব্যাক আপ করতে, আপনাকে একটি ব্যাকআপ এজেন্ট প্রয়োগ করতে হবে৷ আপনার ব্যাকআপ এজেন্টকে ব্যাকআপ ম্যানেজার দ্বারা ব্যাকআপ এবং পুনরুদ্ধার উভয় সময়েই ডাকা হয়।

একটি ব্যাকআপ এজেন্ট বাস্তবায়ন করতে, আপনাকে অবশ্যই:

  1. android:backupAgent অ্যাট্রিবিউট সহ আপনার ম্যানিফেস্ট ফাইলে আপনার ব্যাকআপ এজেন্ট ঘোষণা করুন।

  2. নিম্নলিখিতগুলির মধ্যে একটি করে একটি ব্যাকআপ এজেন্টকে সংজ্ঞায়িত করুন:

    • BackupAgent প্রসারিত করা

      BackupAgent ক্লাস কেন্দ্রীয় ইন্টারফেস প্রদান করে যা আপনার অ্যাপ ব্যাকআপ ম্যানেজারের সাথে যোগাযোগ করতে ব্যবহার করে। আপনি যদি এই ক্লাসটি সরাসরি প্রসারিত করেন, তাহলে আপনাকে অবশ্যই ব্যাকআপ পরিচালনা করতে এবং আপনার ডেটার জন্য অপারেশন পুনরুদ্ধার করতে onBackup() এবং onRestore() ওভাররাইড করতে হবে।

    • BackupAgentHelper প্রসারিত করা

      BackupAgentHelper ক্লাস BackupAgent ক্লাসের চারপাশে একটি সুবিধাজনক মোড়ক প্রদান করে, আপনার লেখার জন্য প্রয়োজনীয় কোডের পরিমাণ কমিয়ে দেয়। আপনার BackupAgentHelper এ, আপনাকে অবশ্যই এক বা একাধিক সাহায্যকারী বস্তু ব্যবহার করতে হবে, যা স্বয়ংক্রিয়ভাবে ব্যাক আপ করে এবং নির্দিষ্ট ধরণের ডেটা পুনরুদ্ধার করে, যাতে আপনাকে onBackup() এবং onRestore() প্রয়োগ করতে হবে না। আপনার অ্যাপের ব্যাকআপগুলির উপর আপনার সম্পূর্ণ নিয়ন্ত্রণের প্রয়োজন না হলে, আমরা আপনার অ্যাপের ব্যাকআপগুলি পরিচালনা করতে BackupAgentHelper ব্যবহার করার পরামর্শ দিই।

      অ্যান্ড্রয়েড বর্তমানে ব্যাকআপ সাহায্যকারী সরবরাহ করে যেগুলি SharedPreferences এবং অভ্যন্তরীণ স্টোরেজ থেকে সম্পূর্ণ ফাইলগুলি ব্যাক আপ এবং পুনরুদ্ধার করবে৷

আপনার ম্যানিফেস্টে ব্যাকআপ এজেন্ট ঘোষণা করুন

একবার আপনি আপনার ব্যাকআপ এজেন্টের জন্য ক্লাসের নাম ঠিক করে নিলে, <application> ট্যাগে android:backupAgent অ্যাট্রিবিউট ব্যবহার করে আপনার ম্যানিফেস্টে এটি ঘোষণা করুন।

যেমন:

<manifest ... >
    ...
    <application android:label="MyApplication"
                 android:backupAgent="MyBackupAgent">
        <meta-data android:name="com.google.android.backup.api_key"
            android:value="unused" />
        <activity ... >
            ...
        </activity>
    </application>
</manifest>

পুরানো ডিভাইসগুলিকে সমর্থন করার জন্য, আমরা আপনার Android ম্যানিফেস্ট ফাইলে API কী <meta-data> যোগ করার পরামর্শ দিই। অ্যান্ড্রয়েড ব্যাকআপ পরিষেবার আর কোনও পরিষেবা কী প্রয়োজন নেই, তবে কিছু পুরানো ডিভাইস এখনও ব্যাক আপ করার সময় একটি কী পরীক্ষা করতে পারে৷ android:name com.google.android.backup.api_key তে এবং android:value কে unused এ সেট করুন।

android:restoreAnyVersion বৈশিষ্ট্যটি ব্যাকআপ ডেটা তৈরি করা সংস্করণের তুলনায় বর্তমান অ্যাপ সংস্করণ নির্বিশেষে অ্যাপ ডেটা পুনরুদ্ধার করতে চান কিনা তা নির্দেশ করতে একটি বুলিয়ান মান নেয়। ডিফল্ট মান false । আরও তথ্যের জন্য ডেটা পুনরুদ্ধার সংস্করণ দেখুন।

BackupAgentHelper প্রসারিত করুন

আপনি যদি SharedPreferences বা অভ্যন্তরীণ স্টোরেজ থেকে সম্পূর্ণ ফাইল ব্যাক আপ করতে চান তাহলে BackupAgentHelper ব্যবহার করে আপনার ব্যাকআপ এজেন্ট তৈরি করা উচিত। BackupAgentHelper এর সাথে আপনার ব্যাকআপ এজেন্ট তৈরি করতে BackupAgent প্রসারিত করার চেয়ে অনেক কম কোডের প্রয়োজন, কারণ আপনাকে onBackup() এবং onRestore() প্রয়োগ করতে হবে না।

আপনার BackupAgentHelper বাস্তবায়নে এক বা একাধিক ব্যাকআপ সাহায্যকারী ব্যবহার করতে হবে। একটি ব্যাকআপ হেল্পার হল একটি বিশেষ উপাদান যা BackupAgentHelper একটি নির্দিষ্ট ধরণের ডেটার জন্য ব্যাকআপ এবং ক্রিয়াকলাপগুলি পুনরুদ্ধার করতে আহ্বান করে৷ অ্যান্ড্রয়েড ফ্রেমওয়ার্ক বর্তমানে দুটি ভিন্ন সহায়ক প্রদান করে:

  • SharedPreferencesBackupHelper SharedPreferences ফাইল ব্যাক আপ করতে।
  • অভ্যন্তরীণ সঞ্চয়স্থান থেকে ফাইল ব্যাক আপ করতে FileBackupHelper .

আপনি আপনার BackupAgentHelper এ একাধিক সাহায্যকারী অন্তর্ভুক্ত করতে পারেন, কিন্তু প্রতিটি ডেটা টাইপের জন্য শুধুমাত্র একজন সাহায্যকারী প্রয়োজন। অর্থাৎ, যদি আপনার একাধিক SharedPreferences ফাইল থাকে, তাহলে আপনার শুধুমাত্র একটি SharedPreferencesBackupHelper প্রয়োজন।

প্রতিটি সাহায্যকারীর জন্য আপনি আপনার BackupAgentHelper এ যোগ করতে চান, আপনাকে আপনার onCreate() পদ্ধতির সময় নিম্নলিখিতগুলি করতে হবে:

  1. পছন্দসই সাহায্যকারী শ্রেণীর একটি উদাহরণ তাত্ক্ষণিক করুন। ক্লাস কনস্ট্রাক্টরে, আপনি যে ফাইলটি ব্যাক আপ করতে চান তা অবশ্যই নির্দিষ্ট করতে হবে।
  2. আপনার BackupAgentHelper এ হেল্পার যোগ করতে addHelper() কল করুন।

নিম্নলিখিত বিভাগগুলি উপলব্ধ সাহায্যকারীদের প্রত্যেকটি ব্যবহার করে কীভাবে একটি ব্যাকআপ এজেন্ট তৈরি করতে হয় তা বর্ণনা করে৷

SharedPreferences ব্যাক আপ করুন

আপনি যখন একটি SharedPreferencesBackupHelper ইনস্ট্যান্টিশিয়েট করেন, তখন আপনাকে অবশ্যই এক বা একাধিক SharedPreferences ফাইলের নাম অন্তর্ভুক্ত করতে হবে।

উদাহরণ স্বরূপ, user_preferences নামের একটি SharedPreferences ফাইল ব্যাক আপ করার জন্য, BackupAgentHelper ব্যবহার করে একটি সম্পূর্ণ ব্যাকআপ এজেন্ট দেখতে এইরকম:

কোটলিন

// The name of the SharedPreferences file
const val PREFS = "user_preferences"

// A key to uniquely identify the set of backup data
const val PREFS_BACKUP_KEY = "prefs"

class MyPrefsBackupAgent : BackupAgentHelper() {
    override fun onCreate() {
        // Allocate a helper and add it to the backup agent
        SharedPreferencesBackupHelper(this, PREFS).also {
            addHelper(PREFS_BACKUP_KEY, it)
        }
    }
}

জাভা

public class MyPrefsBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper =
                new SharedPreferencesBackupHelper(this, PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

SharedPreferencesBackupHelper একটি SharedPreferences ফাইল ব্যাক আপ এবং পুনরুদ্ধার করার জন্য প্রয়োজনীয় সমস্ত কোড অন্তর্ভুক্ত করে।

যখন ব্যাকআপ ম্যানেজার onBackup() এবং onRestore() কল করে, তখন BackupAgentHelper আপনার ব্যাকআপ সাহায্যকারীদেরকে আপনার নির্দিষ্ট ফাইলগুলির ব্যাক আপ এবং পুনরুদ্ধার করার জন্য কল করে।

অন্যান্য ফাইল ব্যাক আপ

যখন আপনি একটি FileBackupHelper ইনস্ট্যান্টিয়েট করেন, তখন আপনাকে অবশ্যই আপনার অ্যাপের অভ্যন্তরীণ সঞ্চয়স্থানে সংরক্ষিত এক বা একাধিক ফাইলের নাম অন্তর্ভুক্ত করতে হবে, যেমন getFilesDir() দ্বারা নির্দিষ্ট করা হয়েছে, যেটি একই অবস্থান যেখানে openFileOutput() ফাইলগুলি লেখে।

উদাহরণস্বরূপ, scores এবং stats নামের দুটি ফাইলের ব্যাক আপ করতে, BackupAgentHelper ব্যবহার করে একটি ব্যাকআপ এজেন্ট এইরকম দেখায়:

কোটলিন

// The name of the file
const val TOP_SCORES = "scores"
const val PLAYER_STATS = "stats"
// A key to uniquely identify the set of backup data
const val FILES_BACKUP_KEY = "myfiles"

class MyFileBackupAgent : BackupAgentHelper() {
    override fun onCreate() {
        // Allocate a helper and add it to the backup agent
        FileBackupHelper(this, TOP_SCORES, PLAYER_STATS).also {
            addHelper(FILES_BACKUP_KEY, it)
        }
    }
}

জাভা

public class MyFileBackupAgent extends BackupAgentHelper {
    // The name of the file
    static final String TOP_SCORES = "scores";
    static final String PLAYER_STATS = "stats";

    // A key to uniquely identify the set of backup data
    static final String FILES_BACKUP_KEY = "myfiles";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        FileBackupHelper helper = new FileBackupHelper(this,
                TOP_SCORES, PLAYER_STATS);
        addHelper(FILES_BACKUP_KEY, helper);
    }
}

FileBackupHelper আপনার অ্যাপের অভ্যন্তরীণ সঞ্চয়স্থানে সংরক্ষিত ফাইলগুলির ব্যাক আপ এবং পুনরুদ্ধার করার জন্য প্রয়োজনীয় সমস্ত কোড অন্তর্ভুক্ত করে৷

যাইহোক, অভ্যন্তরীণ সঞ্চয়স্থানে ফাইল পড়া এবং লেখা থ্রেড-নিরাপদ নয় । আপনার ব্যাকআপ এজেন্ট আপনার ক্রিয়াকলাপগুলির সাথে একই সময়ে আপনার ফাইলগুলি পড়তে বা লিখছে না তা নিশ্চিত করার জন্য, আপনি প্রতিবার পড়া বা লেখার সময় আপনাকে অবশ্যই সিঙ্ক্রোনাইজড বিবৃতি ব্যবহার করতে হবে। উদাহরণ স্বরূপ, যেকোন কার্যকলাপে যেখানে আপনি ফাইলটি পড়েন এবং লেখেন, আপনার সিঙ্ক্রোনাইজড বিবৃতিগুলির জন্য অন্তর্নিহিত লক হিসাবে ব্যবহার করার জন্য একটি বস্তুর প্রয়োজন:

কোটলিন

// Object for intrinsic lock
companion object {
    val sDataLock = Any()
}

জাভা

// Object for intrinsic lock
static final Object sDataLock = new Object();

তারপর প্রতিবার যখন আপনি ফাইলগুলি পড়বেন বা লিখবেন তখন এই লক দিয়ে একটি সিঙ্ক্রোনাইজড স্টেটমেন্ট তৈরি করুন৷ উদাহরণস্বরূপ, একটি ফাইলে একটি গেমের সর্বশেষ স্কোর লেখার জন্য এখানে একটি সিঙ্ক্রোনাইজড বিবৃতি রয়েছে:

কোটলিন

try {
    synchronized(MyActivity.sDataLock) {
        val dataFile = File(filesDir, TOP_SCORES)
        RandomAccessFile(dataFile, "rw").apply {
            writeInt(score)
        }
    }
} catch (e: IOException) {
    Log.e(TAG, "Unable to write to file")
}

জাভা

try {
    synchronized (MyActivity.sDataLock) {
        File dataFile = new File(getFilesDir(), TOP_SCORES);
        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
        raFile.writeInt(score);
    }
} catch (IOException e) {
    Log.e(TAG, "Unable to write to file");
}

আপনার পঠিত বিবৃতি একই লক দিয়ে সিঙ্ক্রোনাইজ করা উচিত।

তারপর, আপনার BackupAgentHelper এ, আপনাকে অবশ্যই onBackup() এবং onRestore() ওভাররাইড করতে হবে ব্যাকআপ সিঙ্ক্রোনাইজ করতে এবং একই অভ্যন্তরীণ লক দিয়ে ক্রিয়াকলাপগুলি পুনরুদ্ধার করতে। উদাহরণস্বরূপ, উপরের থেকে MyFileBackupAgent উদাহরণের নিম্নলিখিত পদ্ধতিগুলির প্রয়োজন:

কোটলিন

@Throws(IOException::class)
override fun onBackup(
        oldState: ParcelFileDescriptor,
        data: BackupDataOutput,
        newState: ParcelFileDescriptor
) {
    // Hold the lock while the FileBackupHelper performs back up
    synchronized(MyActivity.sDataLock) {
        super.onBackup(oldState, data, newState)
    }
}

@Throws(IOException::class)
override fun onRestore(
        data: BackupDataInput,
        appVersionCode: Int,
        newState: ParcelFileDescriptor
) {
    // Hold the lock while the FileBackupHelper restores the file
    synchronized(MyActivity.sDataLock) {
        super.onRestore(data, appVersionCode, newState)
    }
}

জাভা

@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
          ParcelFileDescriptor newState) throws IOException {
    // Hold the lock while the FileBackupHelper performs back up
    synchronized (MyActivity.sDataLock) {
        super.onBackup(oldState, data, newState);
    }
}

@Override
public void onRestore(BackupDataInput data, int appVersionCode,
        ParcelFileDescriptor newState) throws IOException {
    // Hold the lock while the FileBackupHelper restores the file
    synchronized (MyActivity.sDataLock) {
        super.onRestore(data, appVersionCode, newState);
    }
}

BackupAgent প্রসারিত করুন

বেশিরভাগ অ্যাপের সরাসরি BackupAgent ক্লাস প্রসারিত করার দরকার নেই, কিন্তু এর পরিবর্তে বিল্ট-ইন হেল্পার ক্লাসের সুবিধা নিতে BackupAgentHelper প্রসারিত করা উচিত যা স্বয়ংক্রিয়ভাবে আপনার ফাইলগুলির ব্যাক আপ এবং পুনরুদ্ধার করে। যাইহোক, আপনি নিম্নলিখিতগুলি করতে সরাসরি BackupAgent প্রসারিত করতে পারেন:

  • আপনার তথ্য বিন্যাস সংস্করণ. উদাহরণস্বরূপ, আপনি যে বিন্যাসে আপনার অ্যাপের ডেটা লেখেন সেটি সংশোধন করার প্রয়োজনীয়তা অনুমান করলে, আপনি একটি ব্যাকআপ এজেন্ট তৈরি করতে পারেন যাতে একটি পুনরুদ্ধার অপারেশন চলাকালীন আপনার অ্যাপের সংস্করণটি ক্রস-চেক করা যায় এবং ডিভাইসে সংস্করণটি হলে প্রয়োজনীয় কোনো সামঞ্জস্যপূর্ণ কাজ সম্পাদন করতে পারেন। ব্যাকআপ ডেটার চেয়ে আলাদা। আরও তথ্যের জন্য, ডেটা পুনরুদ্ধার সংস্করণ দেখুন।
  • ব্যাক আপ করার জন্য ডেটার অংশগুলি নির্দিষ্ট করুন৷ একটি সম্পূর্ণ ফাইল ব্যাক আপ করার পরিবর্তে, আপনি ব্যাক আপ করার জন্য ডেটার অংশগুলি এবং কীভাবে প্রতিটি অংশ ডিভাইসে পুনরুদ্ধার করা হয় তা নির্দিষ্ট করতে পারেন৷ এটি আপনাকে বিভিন্ন সংস্করণ পরিচালনা করতেও সহায়তা করতে পারে, কারণ আপনি সম্পূর্ণ ফাইলের পরিবর্তে অনন্য সত্তা হিসাবে আপনার ডেটা পড়তে এবং লিখতে পারেন৷
  • একটি ডাটাবেসে ডেটা ব্যাক আপ করুন। আপনার যদি একটি SQLite ডাটাবেস থাকে যা ব্যবহারকারী আপনার অ্যাপ পুনরায় ইনস্টল করার সময় আপনি পুনরুদ্ধার করতে চান, তাহলে আপনাকে একটি কাস্টম BackupAgent তৈরি করতে হবে যা ব্যাকআপ অপারেশনের সময় উপযুক্ত ডেটা পড়ে, তারপর আপনার টেবিল তৈরি করুন এবং একটি পুনরুদ্ধার অপারেশন চলাকালীন ডেটা সন্নিবেশ করুন৷

আপনার যদি উপরের কোনো কাজ করার প্রয়োজন না হয় এবং SharedPreferences বা অভ্যন্তরীণ সঞ্চয়স্থান থেকে সম্পূর্ণ ফাইলের ব্যাকআপ নিতে চান, তাহলে Extending BackupAgentHelper দেখুন।

প্রয়োজনীয় পদ্ধতি

যখন আপনি একটি BackupAgent তৈরি করেন, আপনাকে অবশ্যই নিম্নলিখিত কলব্যাক পদ্ধতিগুলি প্রয়োগ করতে হবে:

onBackup()
আপনি একটি ব্যাকআপ অনুরোধ করার পরে ব্যাকআপ ম্যানেজার এই পদ্ধতিটিকে কল করে৷ এই পদ্ধতিতে, আপনি ডিভাইস থেকে আপনার অ্যাপের ডেটা পড়েন এবং ব্যাকআপ ম্যানেজারে যে ডেটা ব্যাক আপ করতে চান তা পাস করেন, যেমন ব্যাক আপ সম্পাদন করুন
onRestore()

ব্যাকআপ ম্যানেজার একটি পুনরুদ্ধার অপারেশন চলাকালীন এই পদ্ধতিটিকে কল করে। এই পদ্ধতিটি আপনার ব্যাকআপ ডেটা সরবরাহ করে, যা আপনার অ্যাপটি তার পূর্বের অবস্থা পুনরুদ্ধার করতে ব্যবহার করতে পারে, যেমনটি পুনরুদ্ধার সম্পাদন করুন এ বর্ণিত।

ব্যবহারকারী যখন আপনার অ্যাপ পুনরায় ইনস্টল করেন তখন সিস্টেমটি যেকোনো ব্যাকআপ ডেটা পুনরুদ্ধার করতে এই পদ্ধতিটিকে কল করে, কিন্তু আপনার অ্যাপটি একটি পুনরুদ্ধারের অনুরোধও করতে পারে।

একটি ব্যাক আপ সঞ্চালন

একটি ব্যাকআপ অনুরোধের ফলে আপনার onBackup() পদ্ধতিতে অবিলম্বে কল আসে না। পরিবর্তে, ব্যাকআপ ম্যানেজার একটি উপযুক্ত সময়ের জন্য অপেক্ষা করে, তারপরে শেষ ব্যাকআপ সঞ্চালিত হওয়ার পর থেকে ব্যাকআপের অনুরোধ করা সমস্ত অ্যাপগুলির জন্য একটি ব্যাকআপ সঞ্চালন করে৷ এটি সেই পয়েন্ট যেখানে আপনাকে অবশ্যই ব্যাকআপ ম্যানেজারকে আপনার অ্যাপ ডেটা প্রদান করতে হবে যাতে এটি ক্লাউড স্টোরেজে সংরক্ষণ করা যায়।

শুধুমাত্র ব্যাকআপ ম্যানেজার আপনার ব্যাকআপ এজেন্টের onBackup() পদ্ধতিতে কল করতে পারেন। প্রতিবার যখন আপনার অ্যাপের ডেটা পরিবর্তিত হয় এবং আপনি একটি ব্যাকআপ করতে চান, আপনাকে অবশ্যই dataChanged() কল করে একটি ব্যাকআপ অপারেশনের অনুরোধ করতে হবে। আরও তথ্যের জন্য একটি ব্যাকআপের অনুরোধ দেখুন।

টিপ : আপনার অ্যাপ ডেভেলপ করার সময়, আপনি bmgr টুলের সাহায্যে ব্যাকআপ ম্যানেজার থেকে একটি তাৎক্ষণিক ব্যাকআপ অপারেশন শুরু করতে পারেন।

যখন ব্যাকআপ ম্যানেজার আপনার onBackup() পদ্ধতিতে কল করে, তখন এটি তিনটি প্যারামিটার পাস করে:

oldState
একটি খোলা, শুধুমাত্র পঠনযোগ্য ParcelFileDescriptor যা আপনার অ্যাপের দেওয়া শেষ ব্যাকআপ অবস্থার দিকে নির্দেশ করে। এটি ক্লাউড স্টোরেজ থেকে নেওয়া ব্যাকআপ ডেটা নয়, তবে সর্বশেষবার onBackup() কল করার সময় ব্যাকআপ নেওয়া ডেটার একটি স্থানীয় উপস্থাপনা, যেমন newState বা onRestore() দ্বারা সংজ্ঞায়িত করা হয়েছে। onRestore() পরবর্তী বিভাগে কভার করা হয়েছে। যেহেতু onBackup() আপনাকে ক্লাউড স্টোরেজে বিদ্যমান ব্যাকআপ ডেটা পড়ার অনুমতি দেয় না, আপনি শেষ ব্যাকআপের পর থেকে আপনার ডেটা পরিবর্তিত হয়েছে কিনা তা নির্ধারণ করতে এই স্থানীয় উপস্থাপনা ব্যবহার করতে পারেন।
data
একটি BackupDataOutput অবজেক্ট, যা আপনি ব্যাকআপ ম্যানেজারের কাছে আপনার ব্যাকআপ ডেটা সরবরাহ করতে ব্যবহার করেন।
newState
একটি খোলা, পড়া/লেখা ParcelFileDescriptor একটি ফাইলের দিকে নির্দেশ করে যেখানে আপনাকে অবশ্যই ডেটার একটি উপস্থাপনা লিখতে হবে যা আপনি data বিতরণ করেছেন৷ একটি উপস্থাপনা আপনার ফাইলের জন্য সর্বশেষ-সংশোধিত টাইমস্ট্যাম্পের মতো সহজ হতে পারে। পরের বার যখন ব্যাকআপ ম্যানেজার আপনার onBackup() পদ্ধতিতে কল করবে তখন এই বস্তুটি oldState হিসাবে ফেরত দেওয়া হবে। আপনি যদি আপনার ব্যাকআপ ডেটা newState এ না লেখেন, তাহলে পরের বার Backup Manager onBackup() কল করলে oldState একটি খালি ফাইলের দিকে নির্দেশ করবে।

এই পরামিতিগুলি ব্যবহার করে, নিম্নলিখিতগুলি করতে আপনার onBackup() পদ্ধতিটি প্রয়োগ করুন:

  1. আপনার বর্তমান ডেটার সাথে oldState তুলনা করে শেষ ব্যাকআপ থেকে আপনার ডেটা পরিবর্তিত হয়েছে কিনা তা পরীক্ষা করুন৷ আপনি oldState কীভাবে ডেটা পড়েন তা নির্ভর করে আপনি কীভাবে এটি newState লিখেছেন (ধাপ 3 দেখুন)। একটি ফাইলের অবস্থা রেকর্ড করার সবচেয়ে সহজ উপায় হল এর শেষ-সংশোধিত টাইমস্ট্যাম্পের সাথে। উদাহরণস্বরূপ, এখানে আপনি কিভাবে oldState থেকে একটি টাইমস্ট্যাম্প পড়তে এবং তুলনা করতে পারেন:

    কোটলিন

    val instream = FileInputStream(oldState.fileDescriptor)
    val dataInputStream = DataInputStream(instream)
    try {
       // Get the last modified timestamp from the state file and data file
       val stateModified = dataInputStream.readLong()
       val fileModified: Long = dataFile.lastModified()
       if (stateModified != fileModified) {
           // The file has been modified, so do a backup
           // Or the time on the device changed, so be safe and do a backup
       } else {
           // Don't back up because the file hasn't changed
           return
       }
    } catch (e: IOException) {
       // Unable to read state file... be safe and do a backup
    }

    জাভা

    // Get the oldState input stream
    FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    DataInputStream in = new DataInputStream(instream);
    
    try {
       // Get the last modified timestamp from the state file and data file
       long stateModified = in.readLong();
       long fileModified = dataFile.lastModified();
    
       if (stateModified != fileModified) {
           // The file has been modified, so do a backup
           // Or the time on the device changed, so be safe and do a backup
       } else {
           // Don't back up because the file hasn't changed
           return;
       }
    } catch (IOException e) {
       // Unable to read state file... be safe and do a backup
    }

    যদি কিছুই পরিবর্তিত না হয় এবং আপনাকে ব্যাক আপ করার প্রয়োজন না হয়, তাহলে ধাপ 3 এ যান।

  2. oldState এর তুলনায় যদি আপনার ডেটা পরিবর্তিত হয়ে থাকে, তাহলে ক্লাউড স্টোরেজে ব্যাক আপ করতে বর্তমান ডেটা data লিখুন।

    আপনাকে BackupDataOutput এ একটি সত্তা হিসাবে ডেটার প্রতিটি অংশ লিখতে হবে। একটি সত্তা হল একটি সমতল বাইনারি ডেটা রেকর্ড যা একটি অনন্য কী স্ট্রিং দ্বারা চিহ্নিত করা হয়। সুতরাং, আপনি যে ডেটা সেটটি ব্যাক আপ করেন তা ধারণাগতভাবে কী-মান জোড়ার একটি সেট।

    আপনার ব্যাকআপ ডেটা সেটে একটি সত্তা যোগ করতে, আপনাকে অবশ্যই:

    1. আপনি যে ডেটা লিখতে চলেছেন এবং ডেটা আকারের জন্য একটি অনন্য স্ট্রিং কী পাস করে writeEntityHeader() কল করুন।

    2. writeEntityData() কল করুন, একটি বাইট বাফার পাস করে যাতে আপনার ডেটা এবং বাফার থেকে লেখার জন্য বাইটের সংখ্যা থাকে, যা writeEntityHeader() এ পাস করা আকারের সাথে মেলে।

    উদাহরণস্বরূপ, নিম্নলিখিত কোডটি একটি বাইট স্ট্রীমে কিছু ডেটা সমতল করে এবং এটিকে একটি একক সত্তায় লেখে:

    কোটলিন

    val buffer: ByteArray = ByteArrayOutputStream().run {
       DataOutputStream(this).apply {
           writeInt(playerName)
           writeInt(playerScore)
       }
       toByteArray()
    }
    val len: Int = buffer.size
    data.apply {
       writeEntityHeader(TOPSCORE_BACKUP_KEY, len)
       writeEntityData(buffer, len)
    }

    জাভা

    // Create buffer stream and data output stream for our data
    ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    DataOutputStream outWriter = new DataOutputStream(bufStream);
    // Write structured data
    outWriter.writeUTF(playerName);
    outWriter.writeInt(playerScore);
    // Send the data to the Backup Manager via the BackupDataOutput
    byte[] buffer = bufStream.toByteArray();
    int len = buffer.length;
    data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    data.writeEntityData(buffer, len);

    আপনি ব্যাক আপ করতে চান এমন প্রতিটি ডেটার জন্য এটি সম্পাদন করুন। আপনি কীভাবে আপনার ডেটা সত্তায় ভাগ করবেন তা আপনার উপর নির্ভর করে। আপনি এমনকি শুধুমাত্র একটি সত্তা ব্যবহার করতে পারেন.

  3. আপনি ব্যাকআপ করুন বা না করুন (ধাপে 2), newState ParcelFileDescriptor এ বর্তমান ডেটার একটি উপস্থাপনা লিখুন। ব্যাকআপ ম্যানেজার বর্তমানে ব্যাক আপ করা ডেটার উপস্থাপনা হিসাবে এই বস্তুটিকে স্থানীয়ভাবে ধরে রাখে। পরের বার যখন এটি onBackup() কল করে তখন এটি আপনার কাছে এটিকে oldState হিসাবে ফিরিয়ে দেয় যাতে আপনি নির্ধারণ করতে পারেন যে অন্য একটি ব্যাকআপ প্রয়োজনীয় কিনা, যেমন ধাপ 1 এ পরিচালিত হয়েছে। আপনি যদি এই ফাইলটিতে বর্তমান ডেটার অবস্থা না লেখেন, তাহলে oldState হবে পরবর্তী কলব্যাকের সময় খালি।

    নিম্নলিখিত উদাহরণটি ফাইলের সর্বশেষ-সংশোধিত টাইমস্ট্যাম্প ব্যবহার করে newState স্টেটে বর্তমান ডেটার একটি উপস্থাপনা সংরক্ষণ করে:

    কোটলিন

    val modified = dataFile.lastModified()
    FileOutputStream(newState.fileDescriptor).also {
       DataOutputStream(it).apply {
           writeLong(modified)
       }
    }

    জাভা

    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    DataOutputStream out = new DataOutputStream(outstream);
    
    long modified = dataFile.lastModified();
    out.writeLong(modified);

একটি পুনরুদ্ধার সঞ্চালন

যখন আপনার অ্যাপ ডেটা পুনরুদ্ধার করার সময় হয়, তখন ব্যাকআপ ম্যানেজার আপনার ব্যাকআপ এজেন্টের onRestore() পদ্ধতিতে কল করে৷ যখন এটি এই পদ্ধতিতে কল করে, তখন ব্যাকআপ ম্যানেজার আপনার ব্যাকআপ ডেটা সরবরাহ করে যাতে আপনি এটিকে ডিভাইসে পুনরুদ্ধার করতে পারেন।

শুধুমাত্র ব্যাকআপ ম্যানেজার onRestore() কল করতে পারে, যা স্বয়ংক্রিয়ভাবে ঘটে যখন সিস্টেম আপনার অ্যাপ ইনস্টল করে এবং বিদ্যমান ব্যাকআপ ডেটা খুঁজে পায়।

যখন ব্যাকআপ ম্যানেজার আপনার onRestore() পদ্ধতিতে কল করে, তখন এটি তিনটি পরামিতি পাস করে:

data
একটি BackupDataInput অবজেক্ট, যা আপনাকে আপনার ব্যাকআপ ডেটা পড়তে দেয়।
appVersionCode
একটি পূর্ণসংখ্যা যা আপনার অ্যাপের android:versionCode ম্যানিফেস্ট অ্যাট্রিবিউটের মানকে উপস্থাপন করে, যেমনটি এই ডেটা ব্যাক আপ করার সময় ছিল৷ আপনি বর্তমান অ্যাপ সংস্করণ ক্রস-চেক করতে এবং ডেটা বিন্যাসটি সামঞ্জস্যপূর্ণ কিনা তা নির্ধারণ করতে এটি ব্যবহার করতে পারেন। ডেটা পুনরুদ্ধার করার বিভিন্ন সংস্করণ পরিচালনা করতে এটি ব্যবহার করার বিষয়ে আরও তথ্যের জন্য, ডেটা পুনরুদ্ধার সংস্করণ দেখুন দেখুন।
newState
একটি খোলা, পড়া/লিখুন ParcelFileDescriptor একটি ফাইলের দিকে নির্দেশ করে যেখানে আপনাকে অবশ্যই চূড়ান্ত ব্যাকআপ স্থিতি লিখতে হবে যা data দিয়ে দেওয়া হয়েছিল। পরের বার যখন onBackup() কল করা হয় তখন এই অবজেক্টটি oldState হিসাবে ফিরে আসে। মনে রাখবেন যে আপনাকে অবশ্যই onBackup() কলব্যাকে একই newState অবজেক্ট লিখতে হবে—এছাড়াও এখানে এটি করা নিশ্চিত করে যে onBackup() কে দেওয়া oldState অবজেক্টটি বৈধ এমনকি ডিভাইসটি পুনরুদ্ধার করার পরে প্রথমবার onBackup() কল করার পরেও।

আপনার onRestore() এর বাস্তবায়নে, আপনাকে ডেটা সেটের সমস্ত সত্তার মাধ্যমে পুনরাবৃত্তি করতে data readNextHeader() কল করতে হবে। পাওয়া প্রতিটি সত্তার জন্য, নিম্নলিখিতগুলি করুন:

  1. getKey() দিয়ে সত্তা কী পান।
  2. আপনার BackupAgent ক্লাসের মধ্যে স্ট্যাটিক চূড়ান্ত স্ট্রিং হিসাবে ঘোষণা করা উচিত ছিল এমন পরিচিত কী মানগুলির একটি তালিকার সাথে সত্তা কী তুলনা করুন। যখন কীটি আপনার পরিচিত কী স্ট্রিংগুলির একটির সাথে মেলে, সত্তা ডেটা বের করতে এবং ডিভাইসে সংরক্ষণ করতে একটি বিবৃতিতে প্রবেশ করুন:

    1. getDataSize() দিয়ে সত্তা ডেটার আকার পান এবং সেই আকারের একটি বাইট অ্যারে তৈরি করুন।
    2. readEntityData() কল করুন এবং এটিকে বাইট অ্যারে পাস করুন, যেখানে ডেটা যাবে এবং স্টার্ট অফসেট এবং পড়ার আকার নির্দিষ্ট করুন।
    3. আপনার বাইট অ্যারে এখন পূর্ণ। ডেটা পড়ুন এবং আপনার পছন্দ মতো ডিভাইসে লিখুন।
  3. আপনি ডিভাইসে আপনার ডেটা পড়ার এবং লেখার পরে, newState প্যারামিটারে আপনার ডেটার অবস্থা লিখুন যেমন আপনি onBackup() সময় করেন।

উদাহরণস্বরূপ, পূর্ববর্তী বিভাগে উদাহরণ দ্বারা ব্যাক আপ করা ডেটা কীভাবে আপনি পুনরুদ্ধার করতে পারেন তা এখানে:

কোটলিন

@Throws(IOException::class)
override fun onRestore(data: BackupDataInput, appVersionCode: Int,
                       newState: ParcelFileDescriptor) {
    with(data) {
        // There should be only one entity, but the safest
        // way to consume it is using a while loop
        while (readNextHeader()) {
            when(key) {
                TOPSCORE_BACKUP_KEY -> {
                    val dataBuf = ByteArray(dataSize).also {
                        readEntityData(it, 0, dataSize)
                    }
                    ByteArrayInputStream(dataBuf).also {
                        DataInputStream(it).apply {
                            // Read the player name and score from the backup data
                            playerName = readUTF()
                            playerScore = readInt()
                        }
                        // Record the score on the device (to a file or something)
                        recordScore(playerName, playerScore)
                    }
                }
                else -> skipEntityData()
            }
        }
    }

    // Finally, write to the state blob (newState) that describes the restored data
    FileOutputStream(newState.fileDescriptor).also {
        DataOutputStream(it).apply {
            writeUTF(playerName)
            writeInt(mPlayerScore)
        }
    }
}

জাভা

@Override
public void onRestore(BackupDataInput data, int appVersionCode,
                      ParcelFileDescriptor newState) throws IOException {
    // There should be only one entity, but the safest
    // way to consume it is using a while loop
    while (data.readNextHeader()) {
        String key = data.getKey();
        int dataSize = data.getDataSize();

        // If the key is ours (for saving top score). Note this key was used when
        // we wrote the backup entity header
        if (TOPSCORE_BACKUP_KEY.equals(key)) {
            // Create an input stream for the BackupDataInput
            byte[] dataBuf = new byte[dataSize];
            data.readEntityData(dataBuf, 0, dataSize);
            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
            DataInputStream in = new DataInputStream(baStream);

            // Read the player name and score from the backup data
            playerName = in.readUTF();
            playerScore = in.readInt();

            // Record the score on the device (to a file or something)
            recordScore(playerName, playerScore);
        } else {
            // We don't know this entity key. Skip it. (Shouldn't happen.)
            data.skipEntityData();
        }
    }

    // Finally, write to the state blob (newState) that describes the restored data
    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    DataOutputStream out = new DataOutputStream(outstream);
    out.writeUTF(playerName);
    out.writeInt(mPlayerScore);
}

এই উদাহরণে, onRestore() এ পাস করা appVersionCode প্যারামিটার ব্যবহার করা হয় না। যাইহোক, আপনি এটি ব্যবহার করতে চাইতে পারেন যদি আপনি একটি ব্যাকআপ সম্পাদন করতে বেছে নেন যখন অ্যাপটির ব্যবহারকারীর সংস্করণটি আসলে পিছিয়ে যায় (উদাহরণস্বরূপ, ব্যবহারকারী আপনার অ্যাপের সংস্করণ 1.5 থেকে 1.0 এ চলে গেছে)। আরও তথ্যের জন্য, পরবর্তী বিভাগটি দেখুন।

পুনরুদ্ধার ডেটা সংস্করণ পরীক্ষা করুন

যখন ব্যাকআপ ম্যানেজার ক্লাউড সঞ্চয়স্থানে আপনার ডেটা সংরক্ষণ করে, তখন এটি স্বয়ংক্রিয়ভাবে আপনার অ্যাপের সংস্করণ অন্তর্ভুক্ত করে, যেমন আপনার ম্যানিফেস্ট ফাইলের android:versionCode বৈশিষ্ট্য দ্বারা সংজ্ঞায়িত করা হয়েছে। ব্যাকআপ ম্যানেজার আপনার ডেটা পুনরুদ্ধার করতে আপনার ব্যাকআপ এজেন্টকে কল করার আগে, এটি ইনস্টল করা অ্যাপের android:versionCode দেখে এবং পুনরুদ্ধার ডেটা সেটে রেকর্ড করা মানের সাথে তুলনা করে। যদি পুনরুদ্ধার ডেটা সেটে রেকর্ড করা সংস্করণটি ডিভাইসের অ্যাপ সংস্করণের চেয়ে নতুন হয়, তাহলে ব্যবহারকারী তাদের অ্যাপটি ডাউনগ্রেড করেছেন। এই ক্ষেত্রে, ব্যাকআপ ম্যানেজার আপনার অ্যাপের জন্য পুনরুদ্ধার অপারেশন বাতিল করবে এবং আপনার onRestore() পদ্ধতিতে কল করবে না, কারণ পুনরুদ্ধার সেটটি পুরানো সংস্করণের জন্য অর্থহীন বলে মনে করা হয়।

আপনি android:restoreAnyVersion অ্যাট্রিবিউট দিয়ে এই আচরণটিকে ওভাররাইড করতে পারেন। পুনরুদ্ধার সেট সংস্করণ নির্বিশেষে আপনি অ্যাপটি পুনরুদ্ধার করতে চান তা নির্দেশ করতে এই বৈশিষ্ট্যটিকে true সেট করুন৷ ডিফল্ট মান false । আপনি যদি এটি true সেট করেন তবে ব্যাকআপ ম্যানেজার android:versionCode উপেক্ষা করবে এবং সমস্ত ক্ষেত্রে আপনার onRestore() পদ্ধতিতে কল করবে। এটি করার মাধ্যমে, আপনি আপনার onRestore() পদ্ধতিতে সংস্করণের পার্থক্যটি ম্যানুয়ালি পরীক্ষা করতে পারেন এবং সংস্করণগুলি না মিললে ডেটা সামঞ্জস্যপূর্ণ করার জন্য প্রয়োজনীয় যেকোনো পদক্ষেপ নিতে পারেন।

একটি পুনরুদ্ধার ক্রিয়াকলাপের সময় আপনাকে বিভিন্ন সংস্করণ পরিচালনা করতে সহায়তা করার জন্য, onRestore() পদ্ধতিটি আপনাকে appVersionCode প্যারামিটার হিসাবে পুনরুদ্ধার ডেটা সেটের সাথে অন্তর্ভুক্ত সংস্করণ কোড পাস করে। তারপর আপনি PackageInfo.versionCode ফিল্ডের সাথে বর্তমান অ্যাপের সংস্করণ কোড জিজ্ঞাসা করতে পারেন। যেমন:

কোটলিন

val info: PackageInfo? = try {
    packageManager.getPackageInfo(packageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
    null
}

val version: Int = info?.versionCode ?: 0

জাভা

PackageInfo info;
try {
    String name = getPackageName();
    info = getPackageManager().getPackageInfo(name, 0);
} catch (NameNotFoundException nnfe) {
    info = null;
}

int version;
if (info != null) {
    version = info.versionCode;
}

তারপরে PackageInfo থেকে অর্জিত version onRestore() এ পাস করা appVersionCode এর সাথে তুলনা করুন।

একটি ব্যাকআপ অনুরোধ

আপনি যে কোনো সময় dataChanged() কল করে একটি ব্যাকআপ অপারেশনের অনুরোধ করতে পারেন। এই পদ্ধতিটি ব্যাকআপ ম্যানেজারকে অবহিত করে যে আপনি আপনার ব্যাকআপ এজেন্ট ব্যবহার করে আপনার ডেটা ব্যাক আপ করতে চান৷ ব্যাকআপ ম্যানেজার তখন ভবিষ্যতে আপনার ব্যাকআপ এজেন্টের onBackup() পদ্ধতিতে কল করবে। সাধারণত, প্রতিবার আপনার ডেটা পরিবর্তন করার সময় আপনার একটি ব্যাকআপের অনুরোধ করা উচিত (যেমন যখন ব্যবহারকারী একটি অ্যাপ পছন্দ পরিবর্তন করে যা আপনি ব্যাক আপ করতে চান)। ব্যাকআপ ম্যানেজার আপনার এজেন্টের কাছ থেকে একটি ব্যাকআপের অনুরোধ করার আগে আপনি যদি dataChanged() বেশ কয়েকবার কল করেন, তবে আপনার এজেন্ট এখনও onBackup() এ মাত্র একটি কল পাবেন।

একটি পুনরুদ্ধার অনুরোধ

আপনার অ্যাপের স্বাভাবিক জীবন চলাকালীন, আপনাকে পুনরুদ্ধার অপারেশনের অনুরোধ করার দরকার নেই। সিস্টেম স্বয়ংক্রিয়ভাবে ব্যাকআপ ডেটা পরীক্ষা করে এবং যখন আপনার অ্যাপ ইনস্টল করা হয় তখন পুনরুদ্ধার করে।

স্বতঃ ব্যাকআপে স্থানান্তর করুন৷

আপনি ম্যানিফেস্ট ফাইলের <application> উপাদানে android:fullBackupOnly true সেট করে আপনার অ্যাপটিকে সম্পূর্ণ-ডেটা ব্যাকআপে রূপান্তর করতে পারেন। Android 5.1 (API লেভেল 22) বা তার নিচের একটি ডিভাইসে চলার সময়, আপনার অ্যাপ ম্যানিফেস্টে এই মানটিকে উপেক্ষা করে এবং কী-মান ব্যাকআপ করা চালিয়ে যায়। Android 6.0 (API লেভেল 23) বা উচ্চতর ডিভাইসে চললে, আপনার অ্যাপ কী-মান ব্যাকআপের পরিবর্তে অটো ব্যাকআপ করে।

ব্যবহারকারীর গোপনীয়তা

Google-এ, ব্যবহারকারীরা আমাদের উপর যে আস্থা রাখে এবং ব্যবহারকারীদের গোপনীয়তা রক্ষা করার জন্য আমাদের দায়িত্ব সম্পর্কে আমরা গভীরভাবে সচেতন। ব্যাকআপ প্রদান এবং বৈশিষ্ট্য পুনরুদ্ধার করার জন্য Google নিরাপদে Google সার্ভারে এবং থেকে ব্যাকআপ ডেটা প্রেরণ করে। Google এই ডেটাকে Google-এর গোপনীয়তা নীতি অনুসারে ব্যক্তিগত তথ্য হিসাবে বিবেচনা করে৷

এছাড়াও, ব্যবহারকারীরা অ্যান্ড্রয়েড সিস্টেমের ব্যাকআপ সেটিংসের মাধ্যমে ডেটা ব্যাকআপ কার্যকারিতা অক্ষম করতে পারেন। যখন একজন ব্যবহারকারী ব্যাকআপ অক্ষম করে, তখন Android ব্যাকআপ পরিষেবা সমস্ত সংরক্ষিত ব্যাকআপ ডেটা মুছে ফেলে৷ একজন ব্যবহারকারী ডিভাইসে ব্যাকআপ পুনরায় সক্ষম করতে পারেন, তবে Android ব্যাকআপ পরিষেবা পূর্বে মুছে ফেলা ডেটা পুনরুদ্ধার করবে না।