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).
Related
I am going through the Google Codelabs Android basics for Kotlin WorkManager. I've seen the code written one way, then later on see it a different way, and was wondering if there was a difference at all between these?
// Add WorkRequest to save the image to the filesystem
val save = OneTimeWorkRequest.Builder(SaveImageToFileWorker::class.java).build()
// Add WorkRequest to save the image to the filesystem
val save = OneTimeWorkRequestBuilder<SaveImageToFileWorker>()
.build()
Do these do the same thing?
OneTimeWorkRequestBuilder<T>() is just a function that creates and returns an object of type OneTimeWorkRequest.Builder and there are no differences between them.
You can check the OneTimeWorkRequestBuilder function signuature here.
I'm an old Java fan and trying to understand Kotlin basics. Can someone tell me what is the difference between these codes:
private val _users = mutableListOf<User>()
val users: List<User>
get() = _users
VS
var _users: mutableListOf<User>()
private set
As far as understand, upper code provides set _users only in that class and get it publicly which seems pretty same with the code below but in Google docs they say it's backing property which i don't get what it is.
Both examples are really totally different. You need to understand the difference between:
val MutableList
and:
var List
First makes possible to modify the contents of a list, but you can't replace the list object itself. Second, you can replace the list object, but you cannot modify its contents. This isn't really specific to Kotlin, it is the same in Java. val (or making a setter private) is like final field and List is like wrapping a list with Collections.unmodifiableList() - they're different things.
In your first example, neither the external nor internal code can replace the list, but internal code can modify its contents - external can't. In second example both internal and external code can modify contents of the list, but only internal code can replace the list entirely.
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.
I am able to upload a corresponding image through the call:
var uploadTask = firebase_ref.putStream(stream)
I want to add metadata to the uploaded image, so I want to do this inside the putStream call:
var uploadTask = firebase_ref.putStream(stream, metadata)
Now the issue is I am able to import StorageMetadata with this import:
import com.google.firebase.storage.*
I am able to create a StorageMetadata object like:
var metadata = StorageMetadata()
I go to adjust a simple name parameter for the metadata as:
metadata.name = "something"
ERROR:
val cannot be reassigned
I have looked at this reference:
https://firebase.google.com/docs/storage/android/upload-files#kotlin+ktx_5
They suggest doing:
var metadata = storageMetadata {
contentType = "image/jpg"
}
ERROR:
unresolved reference storageMetadata
What is the best way to adjust a simple StorageMetadata and pass it into putStream?
The Kotlin+KTX sample it's showing depends on adding the Cloud Storage for Firebase KTX library to your dependencies (that's what the "KTX" is telling you). After you do that, you will have the storageMetadata builder available in your code as shown in the documentation. If you want to use that, be sure to follow the documentation a linked here. You will add a dependency that looks like this:
// See maven.google.com for the latest versions
// This library transitively includes the firebase-storage library
implementation 'com.google.firebase:firebase-storage-ktx:$VERSION'
If you don't want to use the KTX library, you can work with the metadata object using the StorageMetadata.Builder object as shown in the Java sample. StorageMetadata objects are immutable (notice there are no setters in that class), so you can't create one and just modify it - you have to build one using the provided builder.
I have a data class called Contact which has a companion object property 'allContacts: List' which returns contacts after parsing them from a JSON file.
Relevant code:
val allContacts: List<Contact>
get() {
val json = JSONObject(File("app/src/main/res/data/contacts.json").readText()).getJSONArray("contacts")
val contacts = mutableListOf<Contact>()
...
I do indeed have a contacts.json in res/data package. (data package created manually).
Here's the proof:
Why is this happening? Is the contacts.json file not included in the final .apk?
I have tried logging the current path of the app using
Log.i('.MainActivity', System.getProperty('user.dir'))
But always get . in Logcat.
EDIT: I decompiled the apk in Android Studio and found no traces of contacts.json
Your file doesn't exist in the same project directory you expect it to.
You have to create a resource directory raw and paste your file in there.
Then, you can reference your file as R.raw.contacts wherever you need to reference the file.
Reading the file is another story.
I found it best to create a separate top-level extension function for reading and returning the file contents
fun Activity.readFile(fileID: Int): String {
val inputStream = this.resources.openRawResources(fileID)
return inputStream.use{it.readText()} // Returns entirety of file contents as string.
}