Question

I want to backup my internal files. These are created by My App: random number of files and random names. Like data1.xml, data7,xml, data13.xml, ....

So I do not have any fixed file list.

When MyBackupAgentHelper::onCreate is running before the onBackup(), I can easily provide the filenames by querying the files getApplicationContext().fileList();

public class MyBackupAgentHelper extends BackupAgentHelper 
{
  @Override
  public void onCreate() 
  {
    String[] files  = getApplicationContext().fileList();
    FileBackupHelper helper = new FileBackupHelper(this, files );
    addHelper(FILES_BACKUP_KEY, helper);    
  }
...

However, if the onRestore is ready to run after an uninstall/re-install, I cannot provide the filenames in the onCreate as this time the getApplicationContext().fileList() returns empty list - obviously.

So nothing is restored :(

Is there any way to restore all files which were backuped without specifying the filenames? Just saying, "do it all".

If not, how could I use the Data Backup in this scenario?

Thanks

Was it helpful?

Solution

I just ran into the same problem. It's frustrating because FileBackupHelper does almost exactly what we want it to do.

If you look at the code for FileBackupHelper's restoreEntity function here

https://android.googlesource.com/platform/frameworks/base.git/+/android-4.2.2_r1/core/java/android/app/backup/FileBackupHelper.java

public void restoreEntity(BackupDataInputStream data) {
    if (DEBUG) Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
    String key = data.getKey();
    if (isKeyInList(key, mFiles)) {
        File f = new File(mFilesDir, key);
        writeFile(f, data);
    }
}

...you can see that the only reason the files aren't being written is because they're not in the list that you passed to the FileBackupHelper constructor.

My first solution was to override isKeyInList to always return true. And that actually worked, but then it struck me as odd because isKeyInList has default protection and my FileBackupHelper subclass is not in the same package. It turns out this is some sort dalvik vm bug that allows this so I wouldn't want to rely on it (see Android method with default (package) visibility overriding (shouldn't work, but does - why?) )

But then I realized I could just hold on to the array of files that I passed to the FileBackupHelper constructor and then change the first element to always be the name of the file that wanted to be created. That way it would always be found in the list.

class MyFileBackupHelper extends FileBackupHelper
{
    String[] mMyFiles;
    MyFileBackupHelper(Context context, String... files)
    {
        super(context,files);
        mMyFiles = files;
    }

/*  boolean isKeyInList(String key, String[] list) 
    {       
        return true;
    }   */

    public void restoreEntity(BackupDataInputStream data) 
    {
        mMyFiles[0] = data.getKey();
        super.restoreEntity(data);
    }    
}

Of course this also relies on FileBackupHelper keeping the same implementation where it doesn't make a copy of the Files list. I'm not exactly sure why they went to so much trouble to prevent restoring arbitrary files, and maybe they'll try to thwart this solution later. But for now, I'm calling it good!

Oh yeah, one extra detail to making my solution work is that you need to make sure there's always one file in the list when you're restoring. That way there will always be an array element 0 to replace. This is what I did in my BackupAgent

public class MyBackupAgent extends BackupAgentHelper 
{   
    public void AddFileHelper(String files[])
    {
        FileBackupHelper aHelper = new MyFileBackupHelper(this,files);
        addHelper("userfiles", aHelper);        
    }

    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException
    {
        String[] anArray = GetAllUserFiles(); // I'm not including this function for brevity
        AddFileHelper(anArray);
        super.onBackup(oldState, data, newState);       
    }

    @Override
    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException
    {
        AddFileHelper(new String[] { "filename" } );
        super.onRestore(data, appVersionCode, newState);
    }
}

So you see that I don't rely on onCreate(). Instead I put the correct files in the list in onBackup and I just put one filename in the list in onRestore. Then MyFileBackupHelper replaces array element 0 in that list every time before calling the parent restoreEntity. Hopefully google will let this solution continue to work in future version of their libraries since it seems like a nice feature to have!

OTHER TIPS

EDIT: You cannot backup folders - you need to individually list files in the file helper to backup those.

I realize this question is quite old, but I was running into a similar problem (wanting to back up an arbitrary set of files from a folder), and my solution was to take all of the files, and put them into a zip file, and the have the FileBackupHelper backup the zip file. For onRestore, after the .zip file gets restored, I extract the files back. This may not be the best solution, but it seems to work for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top