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.
Related
I will try to be as clear and precise as possible in my situation.
Currently developing an Android application with Koltin based on the MVVM pattern, I'm facing a problem that questions my architecture.
My application consists in retrieving the different orders of a user, each order having itself a list of products.
I had imagined setting up a "CommandController" which is actually a singleton.
object CommandController : ICommandController {
override var m_commandRepository: ICommandRepository = CommandRepository()
override var m_commandList: MutableList<Command> = mutableListOf<Command>()
override var m_currentCommand: Command? = null
override var m_currentProduct : Produit? = null
override var m_currentProductIndex : Int = first_index
}
The purpose of this singleton is to act as an intermediary between my viewModels and my repository in order to store the commands received and the currently active command (only 1 active command at a time).
class CommandListViewModel : ViewModel() {
fun fetchCommandList(refreshStrategy: CommandRefreshStrategy){
viewModelScope.launch {
mProgressBar.postValue(true)
mErrorStatus.postValue(null)
try {
mCommandList.postValue(CommandController.getCommandsList(refreshStrategy)) //USE CONTROLLER HERE
mCommandActive.postValue(CommandController.getCurrentCommand()) //USE CONTROLLER HERE
}
catch (e: Exception) {
//this is generic exception handling
//so inform user that something went wrong
mErrorStatus.postValue(ApiResponseError.DEFAULT)
}
finally {
mProgressBar.postValue(false)
}
}
}
}
Note that no element has a reference to the singleton, kotlin initializing it when it is first needed
If I click on the active command in the list, I display its details
I chose to do this to avoid having to remake queries every time I need to get the list of commands, no matter the fragment / activity, even if for the moment I only use it in 1 place.
So my layers are as follows:
A problem I wasn't aware of is annoying.
Indeed, if I change the permissions granted by the application and I come back in the application, the last activity launched is recreated at the last visited fragment.
The problem is that my singleton comes back to its initial state and so my active command is null because the process was killed by the system after the change of permissions.
So I would like to know if there is a way to persist/recover the state of my singleton when I come back into the application.
I've already tried to transfer my singleton to a class inherited from Application, but that doesn't solve the problem of the killed process.
I've read a lot of articles/subjects about shared preferences but I have a lot of problems with it:
The controller is supposed to be a purely business element, except shared preferences need the context
I don't want the current command and the list of commands to remain if the user kills the application himself ( is there a way to differentiate between the death of the process by the system and by the user ??).
Android will kill off OS processes for all kinds of reasons. If you want your data to survive this then you must store it in a persistent store. One of the following:
Store it in a file
Store it in SharedPreferences
Store it in an SQLite database
Store it in the cloud on some server where you can retrieve it later
Let's say we have the stock of items stored in the JSON txt file. To access the data we load JSON file using a stringBuilder class, then populate StokItems into:
List<StockItem> stock;
like this:
stock.clear();
Gson gson = new Gson();
stock = gson.fromJson(stringBuilder.toString(), new TypeToken<List<StockItem>>() {
}.getType());
as we would like to take advantage of the LiveData in Android we introduced:
MutableLiveData<List<StockItem>> stockLiveData = new MutableLiveData<>();
To make it working we have to post data into it:
public LiveData<List<StockItem>> getLiveStockList() {
stockLiveData.postValue(stock);
return stockLiveData;
}
So here is the question, if the line:
stockLiveData.postValue(stock);
consumes memory for creating another copy of
List<StockItem> stock
and if so, could be it's a good idea to keep "original data" inside the
stockLiveData
variable only to reduce the memory impact? (If is it possible ...)
No need to use global variable to hold temporary data. either you can use local variable or directly post to LiveData.
public LiveData<List<StockItem>> getLiveStockList() {
return stockLiveData;
}
And then either
List stock = gson.fromJson(stringBuilder.toString(), new TypeToken<List<StockItem>>() { }.getType());
stockLiveData.postValue(stock);
or
stockLiveData.postValue(gson.fromJson(stringBuilder.toString(), new TypeToken<List<StockItem>>() { }.getType()))
You can also access the list inside LiveData like below:
stockLiveData.getValue();
Which return the original list data.
There are couple of things about your code I want to point out here:
You do not necessarily need to call postValue in your getter function. As far as there are observers observing from your getter function, you can post value from anywhere.
Even if you use mutable live data that does not necessarily mean that you're allocating memory for or creating a copy of List. When you set or post value on your Mutable Live Data, you're basically referencing the existing list on to value in your Mutable Live Data.
can you help me out?
For my current context in an app I'm trying to manage a - parsed from json - object through multiple Realms. Due to my requirements I'm bound to use a Realm for my raw converted POJOs, a Realm for an app-session instance and a Realm for a subobject related session (since I'm managing Object copies per session).
The question: How do I properly manage (managed or unmanaged) RealmObjects while copying them from one Realm to another?
Heres my current code:
Realm.getInstance(RealmManager.sessionsConfig)?.also{ sessionsRealm ->
try{
sessionsRealm.executeTransaction{
// Make a clean setup
realm.deleteAll()
val copyRootObject = sessionsRealm.copyToRealm(originalRootObject)
// Ignore flat hierarchy if only one place with one campaign is provided
if(copyRootObject.place?.children?.size!! == 0){
copyRootObject.campaign?.apply {
parameters = copyRootObject.parameters
dynamicfields = copyRootObject.dynamic_fields
survey_topics = copyRootObject.survey_topics
}
copyRootObject.apply {
place?.campaigns = RealmList()
place?.campaigns?.add(copyRootObject.campaign)
}
}
}
}catch(e: Exception){
e.printStackTrace()
}finally {
realm.close()
openStartFragment()
}
}
During the process of opening my main activity which displays the POJOs contents I'm trying to copy the original whole RealmObject from my raw Realm to my "instances" Realm. While this is happening I'm also trying to move some subobjects in my copied objects into a different field because the REST API I'm using is a bit broken.
Problem is though, the shown code doesn't seem to work. While I'm able to find the copied object, the reassigned subobjects are not being moved to the specified fields.
Anybody have an idea what I'm doing wrong?
I'm getting the following error when using the encrypted SQLCipher database in my Android app, but only off and on:
net.sqlcipher.database.SQLiteException: not an error
at net.sqlcipher.database.SQLiteDatabase.dbopen(Native Method)
at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1950)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:900)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:947)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:195)
at com.android.storage.DatabaseHelper.getReadable(DatabaseHelper.java:99)
...
I've got the proper files in the assets/ and libs/ folders because the database works fine most of the time. However, every once in awhile I'll see this error. I've seen this twice now on my phone and it's always been after resuming the app after hours of inactivity (I check for user's oauth token in db if it gets cleared from memory).
I call "SQLiteDatabase.loadLibs(this)" only from the Application::onCreate() method so my hunch is that this isn't getting called on a resume and is throwing the error. Does this sound possible? If so, where should I call loadLibs? A user could enter the app in any activity and I access the db if the token isn't in memory. I see my options as either calling loadLibs on each Activity::onCreate or calling it each time I attempt to open the db. Would it cause any harm or performance issues if I called it multiple times like this?
You might consider moving the SQLiteDatabase.loadLibs(this); to your application subclass of net.sqlcipher.database.SQLiteOpenHelper. You can then pass the static instance of your Application subclass as its argument. Something like the following might be an example:
public class SchemaManager extends net.sqlcipher.database.SQLiteOpenHelper {
private static SchemaManager instance;
public static synchronized SchemaManager getInstance() {
if(instance == null) {
SQLiteDatabase.loadLibs(YourApplication.getInstance());
instance = new SchemaManager(…)
}
return instance;
}
}
With regard to the exception that was provided, the Java routine calls into a JNI layer that calls sqlite3_open_v2, setting the soft heap limit and setting the busy timeout. I would suggest adding logging locally to verify you are passing a valid path and a non null passphrase when attempting to acquire the SQLiteDatabase instance when you get a crash. Calling SQLiteDatabase.loadLibs(this); multiple times shouldn't cause a noticeable performance impact, much of what occurs are calls to System.loadLibrary(…) which get mapped into Runtime.getRuntime().loadLibrary(…), once a dynamic library has been loaded, subsequent calls are ignored.
I am currently developing a mobile application using the latest version of Flash Builder and I need to create a Global ArrayCollection to store information in that is pulled from a local DB. I can pull back the data from the DB fine however I cannot seem to access the Global variable when I try. I have the follng .as file called "Model.as" which is located in a folder called valueObjects and that file contains the following code:
package valueObjects
{
import flash.data.SQLConnection;
import mx.collections.ArrayCollection;
public class Model
{
public var ids:ArrayCollection = new ArrayCollection();
public function Model()
{
}
}
}
Now I want to start populating this ArrayCollection with the info from the database so i import the class into the Default Package mxml doc which will be loaded up first when the app starts by using:
import valueObjects.Model;
Then in a private function I try to access the ids ArrayCollection and populate it however I get the following error:
-1120: Access of undefined property ids.
-Access of undefined property ids
Can anyone please help with this?? Thanks
Have you created an instance of your Model class?
In the classes you want to access it, you should do something like this:
var myModel : Model = new Model();
To share the model instance between classes, you're going to have to do slightly more work. Either by passing around a reference to the same object, or using an alternate method such as creating a Singleton. Many Flex frameworks, such as Cairngorm or RobotLegs, use Singletons if you need an example.
Or easiest way is make array static.
public static var ids:ArrayCollection = new ArrayCollection();
but for this case is Singleton way better.