I'm struggling with storing a realm db on the sd card. The point is that I have to use DocumentFile instead of simple File object to have write access. Another words:
Uri uri = getUriInstanceToSaveDB(); // my inner method
new File(uri.getPath()).canWrite() == false
DocumentFile.fromTreeUri(getActivity(), uri).canWrite() == true
Therefore I can't just store data using RealmConfiguration.Builder() (cause it uses File object as storing mechanism). Of course, I've also tried to use simple String there instead of File object - no result.
Real doesn't support DocumentFile at this point in time, so I'm afraid you are currently out of luck unless you can find a way to map a DocumentFile to a local File reference.
Also one of the problems with DocumentFile is that it might reference a file that doesn't exist locally, which would prevent Realm from using it. So it is unclear if Realm could ever support this.
Related
I have a Realm DB file, with name "abc.realm". How to change this name to something else? Should I just replace the file name using IO operations or can I do it with migrations? Not able to find any satisfactory answer neither on the web nor on StackOverflow.
Realm stores 2 files, the realm itself and a .lock file. So if you call your realm "abc.realm", then next to this file there is also "abc.realm.lock".
The way to go about renaming your realm file is,
Make sure you find the location of both files
Rename both files with the same name but keeping the ".lock" extension on the lock file
Modify the path to the realm that you pass to the RealmConfigurationBase inheritor
Clearly before doing any of this, make sure to backup your database, just in case.
I don't know what programming language you're writing your android application in, so I'll go with a skeleton in pseudocode
private void BackupRealmFile(string realmLocation, string saveLocation)
{
// make a copy of the file and store it somewhere
}
void YourMainMethod()
{
BackupRealmFile("some/path", "your/backup/path");
IOLib.RenameFile("some/path/abc.realm", "some/path/newName.realm");
IOLib.RenameFile("some/path/abc.realm.lock", "some/path/newName.realm.lock");
var config = new RealmConfiguration("some/path/newName.realm");
// maybe some more settings on your conf
var realm = Realm.GetInstance(config);
}
I hope this helps.
So I tried to follow the tutorial on youtube about Firebase Storage, and I found this code:
val filePathAndName="product_images/"+""+timeStamp
val storageReference=FirebaseStorage.getInstance().getReference(filePathAndName)
But the code above uses Java in the tutorial, I changed it to Kotlin syntax and I tried to run the application and it worked.
After reading the documentation regarding Firebase Storage, I found:
// Create a child reference
// imagesRef now points to "images"
var imagesRef: StorageReference? = storageRef.child("images")
// Child references can also take paths
// spaceRef now points to "images/space.jpg
// imagesRef still points to "images"
var spaceRef = storageRef.child("images/space.jpg")
So what is the proper way to declare a reference? And what is the function of filePathAndName on getReference(filePathAndName)? Does it have the same functionality as a child in Kotlin syntax?
When you have an instance of FirebaseStorage you can call reference/getReference on it to get a StorageReference object to the root, or (by passing in a path string) to a specific file.
When you have a StorageReference object, you can call child(...) on it to get a reference to a location under that reference.
It's similar to how you deal with directories in many other parts of programming: you can either pass in the entire path to a file right away, or you can pass in parts of the path and build the same path that way.
So as shown in the documentation on creating references, you can get a reference to the root with:
var storageRef = storage.reference
From there, you can then get a reference to a specific file with:
var spaceRef = storageRef.child("images/space.jpg")
But you can also replace the above two lines with this single line:
var storageRef = storage.getReference("images/space.jpg")
The above approaches have the exact same result, and it makes no practical difference which one you use (as these references are lightweight objects that make no call to the network yet).
I'm trying to create a new instance of SDKNativeEngine in this way
SDKOptions sdkOptions =
SDKOptions.withAccessKeySecretAndCachePathCacheSizeAndPersistentMapPath(
accessKeyId, accessKeySecret, externalPath, cacheSizeBytes, externalPath);
// Trying to use external map folder
await SDKNativeEngine.sharedInstance.internaldispose(() async {
SDKNativeEngine sdkNativeEngine;
try {
sdkNativeEngine = SDKNativeEngine(sdkOptions);
} on InstantiationException {
// Handle exception.
print('$InstantiationException');
}
SDKNativeEngine.sharedInstance = sdkNativeEngine;
isLoaded = true;
MapDownloadService mapDownloadService = ServiceProvider.of<MapDownloadService>();
await mapDownloadService?.fetchListRegions(forceRefresh: true);
});
Where the important thing for me is to set a custom path to save the map (externalPath variable), the value is /storage/<FB39-1114(SdCard)>/Android/data//files/MyMaps, but I'm getting this error
[ERROR] SDKNativeEngine - Failed to lock cache directory. Check the log above for more details. This usually happens when the second instance of SDKNativeEngine is created with the same access key id as the existing one (for example, shared instance). The issue might be fixed if SDKNativeEngine.dispose() method is called on existing instance before the creation of the new one. Keep in mind that the instance of SDKNativeEngine might exist in a separate process.
Also the map data is not saved in the custom path, it's always saved in the internal private storage
SDK created global singleton of SDKNativeEngine which you have to dispose before creation of the new one.
The easiest way is to do something like -
await SDKNativeEngine.sharedInstance?.dispose();
before you create SDKNativeEngine.
But perhaps you don’t even need the new instance, just put your app code to info.plist and to Android’s Manifest and then only set app secret on shared instance?
Like - SDKNativeEngine.sharedInstance.setAccessKeySecret(accessKeySecret)
For storing map data in external storage -
If you open documentation for SDKOptions you may see all the options which you need.
Android API has DocumentFile class. This class has canWrite() method.
Suppose I called this method and it returned true. Also suppose this object was representing "raw" file.
Now how can I do what it said I can?
Namely, how to write "Hello world" text into that file?
Thanks.
Namely, how to write "Hello world" text into that file?
It is not necessarily a file.
To write to the document identified by that DocumentFile, call getUri() on that DocumentFile to get the Uri to the document. Pass that to openOutputStream() on a ContentResolver. Then, write to the stream, flush() the stream, and close() the stream. Basically, once you get the OutputStream, from there ordinary Java I/O takes over.
My app reads files in /proc. I am trying to test this with Robolectric 2.3.
I can create a test file in the "external storage" without problems:
ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
PrintWriter out;
out = new PrintWriter("myFile");
out.println(contents);
However if I try to write to a file in /proc it blows up with java.io.FileNotFoundException: \proc\net\netstat (Access is denied).
ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
boolean a = new File( "/proc" ).mkdirs(); //Fails
PrintWriter out;
out = new PrintWriter("/proc/myFile");
out.println(contents);
Is there any way I can cause a (specific) file to exist in /proc, for testing?
I've already answered similar questions today. Looks like today is day about promoting single class responsibility and dependency injections.
I would change your code to next first:
Write a class that will be responsible for opening (closing, other operations, keep an eye that it should be simple) file connections
Make a class that reads information from stream/file to some internal data structure
Process this data in your original class
Next I would write tests:
Check file operations class
Check that reader is passing correct file location to file operations class instance (mock in tests)
Check that original class correctly process information that is provided by reader class (reader is mocked in tests)
Hope it helps!