Xamarin Forms Sharedpreferences cross - sharedpreferences

I'd like to know what is the best solution to manipulate application settings in a cross-platform way.
In iOS we can change the settings outside the app in the settings screen, but we don't have that in windows phone and android.
So, my idea is to create a normal page/screen inside the app that shows all my application settings and have an interface with Save() and Get() methods that I can implement specific per device using DependencyServices.
Is this the right way to do it?

The Application subclass has a static Properties dictionary which can be used to store data. This can be accessed from anywhere in your Xamarin.Forms code using Application.Current.Properties.
Application.Current.Properties ["id"] = someClass.ID;
if (Application.Current.Properties.ContainsKey("id"))
{
var id = Application.Current.Properties ["id"] as int;
// do something with id
}
The Properties dictionary is saved to the device automatically. Data added to the dictionary will be available when the application returns from the background or even after it is restarted. Xamarin.Forms 1.4 introduced an additional method on the Application class - SavePropertiesAsync() - which can be called to proactively persist the Properties dictionary. This is to allow you to save properties after important updates rather than risk them not getting serialized out due to a crash or being killed by the OS.
https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/app-lifecycle/
Xamarin.Forms plugin which uses the native settings management.
Android: SharedPreferences
iOS: NSUserDefaults
Windows Phone: IsolatedStorageSettings
Windows Store / Windows Phone RT: ApplicationDataContainer
https://github.com/jamesmontemagno/Xamarin.Plugins/tree/master/Settings

I tried using the Application.Current.Properties Dictionary and had implementation problems.
A solution that worked with very little effort was James Montemagno's Xam.Plugin.Settings NuGet. GitHub Installing the NuGet automagically creates a Helpers folder with Settings.cs. To create a persisted setting you do:
private const string QuestionTableSizeKey = "QuestionTableSizeKey";
private static readonly long QuestionTableSizeDefault = 0;
and
public static long QuestionTableSize
{
get
{
return AppSettings.GetValueOrDefault<long>(QuestionTableSizeKey, QuestionTableSizeDefault);
}
set
{
AppSettings.AddOrUpdateValue<long>(QuestionTableSizeKey, value);
}
}
Access and setting in the app then looks like:
namespace XXX
{
class XXX
{
public XXX()
{
long myLong = 495;
...
Helpers.Settings.QuestionTableSize = myLong;
...
long oldsz = Helpers.Settings.QuestionTableSize;
}
}
}

Related

Asp.net Boilerplate - Implement setting manager with database

I've been building an asp.net core website, using the asp.net boilerplate template. As of now, I've been storing all of the settings in the appsettings.json file. As the application gets bigger, I'm thinking I should start storing some settings via ABP's SettingProvider and ISettingStore.
My question is, does anyone have, or know of, a sample application that show's how to implement ISettingStore and storing the settings in the database?
The only post I could find so far is this, but the link hikalkan supplies is broken.
Thanks for any help,
Joe
ABP stores settings on memory with default values. When you insert a new setting value into database, then it reads from database and overrides the default value. So basically when database has no settings then it means all the settings are on default values. Setting values are stored in AbpSettings table.
To start using settings mechanism. Create your own SettingProvider inherited from SettingProvider. Initialize it in your module (eg:
ModuleZeroSampleProjectApplicationModule).
As SettingProvider is automatically registed to dependency injection; You can inject ISettingManager wherever you want.
public class MySettingProvider : SettingProvider
{
public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
{
return new[]
{
new SettingDefinition(
"SmtpServerAddress",
"127.0.0.1"
),
new SettingDefinition(
"PassiveUsersCanNotLogin",
"true",
scopes: SettingScopes.Application | SettingScopes.Tenant
),
new SettingDefinition(
"SiteColorPreference",
"red",
scopes: SettingScopes.User,
isVisibleToClients: true
)
};
}
}
In application services and controllers you don't need to inject ISettingManager
(because there's already property injected) and you can directly use SettingManager property. Forexample :
//Getting a boolean value (async call)
var value1 = await SettingManager.GetSettingValueAsync<bool>("PassiveUsersCanNotLogin");
And for the other classes (like Domain Services) can inject ISettingManager
public class UserEmailer : ITransientDependency
{
private readonly ISettingManager _settingManager;
public UserEmailer(ISettingManager settingManager)
{
_settingManager = settingManager;
}
[UnitOfWork]
public virtual async Task TestMethod()
{
var settingValue = _settingManager.GetSettingValueForUser("SmtpServerAddress", tenantAdmin.TenantId, tenantAdmin.Id);
}
}
Note: To modify a setting you can use these methods in SettingManager ChangeSettingForApplicationAsync, ChangeSettingForTenantAsync and ChangeSettingForUserAsync

Azure MobileService in BackgroundTask

My question is pretty simple : Can we use MobileServices in BackgroundTasks? (WP 8.1 XAML)
I have an universal app connected to a MobileService from Azure and I wanted to let the BackgroundTask synchronize the data of my remote database.
So, is this possible?
public sealed class BackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
//Connect to mobile service and add data
deferral.Complete();
}
}
I can't add a reference to my WP project, so how can I get the App.MobileServiceClient?
My BackgroundTask project is a Windows runtime component.
EDIT:
I've added the reference to Windows Azure Mobile Service by managing nuGet Packages and I can now declare a mobileService but when I want to instanciate it I've got the following error :
BACKGROUNDTASKHOST.EXE' has exited with code 1 (0x1).
So this is what my code looks like now :
public sealed class BackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
Microsoft.WindowsAzure.MobileServices.MobileServiceClient lolServiceMobileClient =
new Microsoft.WindowsAzure.MobileServices.MobileServiceClient(
"https://myservicemobile.azure-mobile.net/",
"myKey");
deferral.Complete();
}
}
And this is the reference I've added :
Edit 2
I'm stills searching for solution and I'm now wondering, could it be because I exceed the amount of memory the background task is allowed to use?
I'm not an expert on background tasks, but you can indeed use the Mobile Services SDK there. Just make sure that the background task doesn't interfere with the app, by using an app setting to lock between the two processes.

Change application.conf runtime?

I want to set the database connection at run time for my Play project. I know that I can set a property run time with the following code:
#OnApplicationStart public class Bootstrap extends Job
{
#Override public void doJob()
{
// now set the values in the properties file
Play.configuration.setProperty("db.driver", dbDriver);
Play.configuration.setProperty("db.url", dbUrl);
Play.configuration.setProperty("db.user", dbUsername);
Play.configuration.setProperty("db.pass", dbPassword);
}
}
But when executing the code above the file is not actually changed, I think just in memory.
How can I set the database properties and force Play! to use this properties in order to connect to the right database onApplicationStart?
Thanks!
UPDATE 2012-01-29
Solution is possible via a plugin. In this plugin I have to override onConfigurationRead() and apply the properties to the configuration file at that moment. I will try to post some code as soon as I have time for this.
By the time you change the properties, the DB plugin is already initialized. You need to write a plugin and overwrite the onConfigurationRead() method, then put your new settings there. Paly's dbplugin will init later on.
I faced with the necessity of programmatically obtaining values from aws secret manager in runtime before using that values in play framework configuration. You can override initial default values from application.conf and add new.
Work for play framework v2.7.3
import com.typesafe.config.ConfigValueFactory;
import play.api.Configuration;
import play.api.inject.guice.GuiceApplicationBuilder;
import play.api.inject.guice.GuiceApplicationLoader;
public class ExtendedGuiceApplicationLoader extends GuiceApplicationLoader {
#Override
public GuiceApplicationBuilder builder(Context context) {
Configuration configuration = new Configuration(
context.initialConfiguration().underlying()
.withValue("db.default.username",
ConfigValueFactory.fromAnyRef("aws.secret.db.username"))
.withValue("db.default.password",
ConfigValueFactory.fromAnyRef("aws.secret.db.password"))
);
return super.builder(
new Context(context.environment(),
configuration,
context.lifecycle(),
context.devContext())
);
}
}
DonĀ“t forget add this string to application.conf
play.application.loader="youpackage.ExtendedGuiceApplicationLoader"
Are you sure this is what you really intend to do?
Play offers the possibility to add different configurations in your application.conf
for example you could have:
db.url=mydefaulturl
%uat.db.url=uaturl
%prod.db.url=produrl
%prod1.db.url=prod1url
And then start the app with play start --%uat or play start --%prod

Does WP7 save variables on close?

When my app closes will the values i have set still be there when I re open it?
Or is there a way to save them somewhere?
No they won't,
When you jump-out from the application, application will go to a state called TombStoned, it is your responsibility to store and retrieve useful page elements.
In order to do this, you need to store information on the following event on your page:
public override void OnNavigatedFrom(...)
{
State["XXX"] = txtName.Text; // save your data on page state (keep it low in size!)
}
the same way you need to retrieve your data on the following event
public override void OnNavigatedTo(...)
{
txtName.Text = State["XXX"]; // read your data from page state
// also check if state has any entry with this key
}
If you need to store application level data, you need to do it in your App.xaml.cs in the following events:
public override void OnDeactivated(...)
{
// Store in IsolatedStorageSettings
}
public override void OnActivated(...)
{
// Read from IsolatedStorageSettings
}
For more details about Tombstoning read the following article:
http://www.scottlogic.co.uk/blog/colin/2011/05/a-simple-windows-phone-7-mvvm-tombstoning-example/
When you app closes, all data information is lost unless you save it somewhere. For transient data, like page state things (e.g. textboxes, checkbox etc..), you can use PhoneApplicationPage.State. If you need to store data permanently so that it's there the next time the user launches the app, you should store it in Isolated Storage. You can learn more about tombstoning and when you should store states in this MSDN page.
There is also a helper library on CodePlex called Tombstone Helper which will make it easier to store data during tombstoning.

Eclipse: Within a plug-in, how to access another plug-ins preference store?

I have an Eclipse plug-in with a checkbox in the plug-in's preference page.
This checkbox is used for enabling and disabling an editor, which is being launched from this plug-in.
However, the problem is, I would also like to be able to enable and disable this 'editor-launch' from another plug-in, by having actions which change the value of the checkbox in the above mentioned preference page.
Here's the problem, how do I access that local preference store from another plug-in?
I've tried things like..
View myView = (View) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("ViewID");
But this 'myView' always seems to be null.. And also, what would I do with the view since it's the Plug-in I want.
Platform.getBundle('bundleName')...
Same here, want the Plugin, not the bundle corresponding to is.
No matter what I try nothing seems to work.
Does anyone have any ideas?
There are two ways of doing this:
Please refer to http://www.vogella.com/tutorials/EclipsePreferences/article.html#preferences_pluginaccess
Using .getPluginPreferences(). For example, there is a plugin class "com.xxx.TestPlugin" which extends org.eclipse.ui.plugin.AbstractUIPlugin.Plugin, in order to get access to the preferences of TestPlugin. The plugin code could be below:
public class TestPlugin extends AbstractUIPlugin {
private static TestPlugin plugin;
public static final String PREF_TEST = "test_preference";
/**
* The constructor.
*/
public TestPlugin() {
plugin = this;
}
/**
* This method is called upon plug-in activation
*/
public void start(BundleContext context) throws Exception {
super.start(context);
}
/**
* This method is called when the plug-in is stopped
*/
public void stop(BundleContext context) throws Exception {
super.stop(context);
plugin = null;
}
/**
* Returns the shared instance.
*/
public static TestPlugin getDefault() {
return plugin;
}
}
To access the preference of TestPlugin, the code could be:
TestPlugin.getDefault().getPluginPreferences().getDefaultBoolean(TestPlugin.PREF_TEST);
Or have a look at this answer: Writing Eclipse plugin to modify Editor Preferences
This thread recommend the use of a Service tracker:
ServiceTracker tracker = new ServiceTracker(ToolkitPlugin.getDefault().getBundle().getBundleContext(),
IProxyService.class.getName(), null);
tracker.open();
proxyService = (IProxyService) tracker.getService();
proxyService.addProxyChangeListener(this);
This may work.
Prefs stores are found per plugin. This is one way to get a prefs store for the plugin whose activator class is ActivatorA.
IPreferenceStore store = ActivatorA.getDefault().getPreferenceStore();
If you want another plugin to refer to the same store, perhaps you could expose some api on ActivatorA for it to get there, e.g.
public IPreferenceStore getSharedPrefs() {
return ActivatorA.getDefault().getPreferenceStore();
}
The second plugin would find the shared store by doing this
IPreferenceStore sharedPrefs = ActivatorA.getSharedPrefs();
Good luck.