in Android why we have
- Context.getSharedPreferences()
and
-Activity.getPreferences()
but we can change the model in each one between private and multiple so it will be same !! i know there is another function but what is it ?
Always useful to read the documentation first! Furthermore reading the source code really helps a lot at times.
Context.getSharedPreferences(String name, int mode)
This is the main method. What it does is it fetches the contents of preference file "name", stores and returns it via a singleton.
Activity.getPreferences(int mode)
As said, this just calls the above, but with specific name which actually is equal to:
getLocalClassName()
PreferenceManager.getDefaultSharedPreferences(Context)
This also calls Number 1 with the name: getPackageName() + "_preferences";
That said you can also supply the first two methods with ones of these modes:
MODE_PRIVATE
The default mode you should be using (also default for Number 3).
MODE_MULTI_PROCESS
Meant to be used if your application has multiple processes, where a singleton is not enough to keep the preferences up-to-date.
MODE_WORLD_READABLE Deprecated in API 17
MODE_WORLD_WRITEABLE Deprecated in API 17
Related
I am building an application and I am thinking of how to "parametrise" all the strings in the application (is it even possible) in order to allow me to change them easily without "redeploying" it again ...
meaning it will be somewhere in a file with strings (something like you have PO files in PHP when using templates and different languages) where I can manage it ..
it might be useful when I would like to use different languages :)
I am kinda struggling on this one, so I was thinking if you can give me a clue or show me where to "go" to study how this should be implemented ..
Thanks
If you want different langage in your app, create as many strings.xml files as you need. However, when you add new strings file, you have to redeploy.
To avoid that, you should call a specific API in backend which send you all the texts according to the langage of the device. For that you must manage back and front.
So if I understand your question correcly go to res - >value folder -> strings.xml - > open it and you will see something like this:
<string name="app_name">this is your app name</string>
And now every time that you want text to be "this is your app name" all you need to do is to add this line:
android:text="#string/app_name"
And when you will change the actual string in strings.xml it will also change in every place he is being used (android:text="#string/app_name")
Android has a built-in mechanism for localising assets (Strings included)
https://developer.android.com/guide/topics/resources/localization#creating-alternatives
What you are trying to do is known as 'Localisation', this can be helpful if you want to give users different language support and similar kind of stuff.
In android, this is done by putting all the strings in the Strings.xml file located in the res folder.
If you're using android studio, just press Alt + Enter on any hardcoded string and then select 'Extract string resource' from the popup, give the name of the string and Voila! you're done.
It is also a part of good coding practice, in fact you've might have noticed 'Lint warnings' in your layout files if you type any hardcoded string, and it asks you to add this string in the strings.xml file
You can create a separate String file for each language that you wanna include.
Option 1
Using the Default Built-In Mechanism
You already have answers about this or you can read the official documentation about it.
Essentially, you maintain an xml file called strings.xml which is a key-value of Strings. Each file (one per language) will be located in a values folder. E.g.: for french, you'd want values-fr/strings.xml. Each file will include all the translated strings. If a value is not found in French, then the english file will be searched instead as a fallback. If the key is not there, the app will crash (if I am not mistaken).
Pros
Included with the system
Supports many languages
Packed at compile time, always available.
Cons
Resources are "read-only" once they are compiled; you cannot change a string and save the change this way.
Option 2
Roll your own Thing.
If you need to be able to dynamically alter these strings, you'll need a few key pieces:
A way to obtain/download said strings.
A default in case step 1 fails (what if the user cannot download them?) You need defaults.
To ensure every widget that needs to display text, calls your own creation of a class that can manage said dynamic strings (i'll elaborate down below)
You need to know what to do if a String is somehow magically missing; because this is dynamic, there has to be a fallback in case the string is not found (see 2)
This has to be relatively fast (you don't want expensive lookups when constructing strings and UI elements).
Pros
You can model this the way it works best for you
You will be able to load strings as you see fit and even change them at runtime.
Cons
You have to build all this.
It's error prone, and most likely slower than the native solution.
You must ensure you don't miss strings and that you have dafults.
You must modify normal widgets (say TextView) to understand how to fetch the strings (or you must always provide them), and this is not going to be automatic, you'll either have to delegate or subclass into a YourCustomTextViewThatUnderstandsYourStringThing extends TextView (name... is just a draft ;) )
You must ensure you don't leak memory by keeping strings in memory you don't care anymore.
If you want to "persist" these downloaded languages (and you should), you have to write/use your own persisting mechanism (either by writing the files or by using some database, shared preferences is not the place for these).
You need to cache them (see above) and manage the validity of the strings (what if they become old, can they become old? when should you re-fetch them?)
etc.
As you can see it's not trivial and each app has its own world of problems to solve, but that's roughly what it means.
As for "code"... the simplest way I can think of (or rather, the bare basics) are:
Find a way to "store" the strings: e.g.:
Map<String, String> oneLanguage
So in this Map, you store the KEY (to find the value) and the VALUE:
oneLanguage.put("app_name", "My Super App")
Keep all the strings in one place in memory:
Map<String, Map<String, String>> allLanguages
so then you do:
allLanguages.put("English", oneLanguage);
Now you can add other languages:
anotherLanguage.put("app_name", "Mi Super App"); //my Spanish is top-notch
allLanguages.put("Spanish", anotherLanguage);
Now you have a place where to store (in memory) all your keys/values for each language.
When you want to retrieve Spanish, you'd have a method like:
String getString(#NonNull String locale, #NonNull String key) {
return allLanguages.get(locale).get(key);
}
And then you'd need to (either manually or via subclassing or whatever approach you find more convenient) to set these strings like:
// I mean, don't hardcode the locale... but you get the idea.
appNameTextView.setText(yourLanguageManager.getString("Spanish", "app_name"));
What approach you take for this last step, is entirely up to you.
As usual, all the above is pseudo-code, and not a complete solution to this approach. Things you want to do: ask the device what locale is using, keep track of which locale is in use (so you don't have to pass it every time), fetch these locales from your server (not pictured) :), persist these to disk, as well as save in shared preferences, the "locale" key that the user has selected, add methods to your yourLanguageManager so it can have things like:
boolean updateLocale(String locale, Map<String, String newStrings)
boolean deleteLocale(String locale)
Map<String, String> getLocale(String locale)
etc.. you get the idea.
All in all, it's just a simple data structure that can contain keys and values.
Good luck!
User can define at Data Usage screen a limite and/or a warning limit for mobile data usage. So how can I get this information by code?
Screen of Data Usage configuration of native OS.
I wanna the limit value and warning value.
I've already tried this but not work and always return NULL to both:
final Long recommendedBytes = DownloadManager.getRecommendedMaxBytesOverMobile( this.context );
final Long maximumBytes = DownloadManager.getMaxBytesOverMobile( this.context );
// recommendedBytes and maximumBytes are NULL
And TrafficStats class just have a data transferred not the limits.
After days searching and research about this problem I couldn't find a answer for that. Bellow I will lift every attempt that I did.
1. Download Manager
With this class you can start download over any network or device
state and it will handle all states e.g. network loss, device reboot,
etc...
There are two methods called getMaxBytesOverMobile and
getRecommendedMaxBytesOverMobile, they was a pretty candidate
to solve this problem at first time. But after code tests and
Download Manager implementantion research I'd found that there is
no way to get thoose values by DownloadManager.
Reason
Thoose methods call Settings.Secure.getLong with they
respective labels
Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE and
Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE in
the turn makes a call to a lazy String map inside inside a
inner class called NameValueCache.
Ok so far but none of inner classes or Settings implementation it
self use DOWNLOAD_MAX_BYTES_OVER_MOBILE or
DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE inside.
I considered the lazy map was populate by a third entity, what
actually happens, so I found the NameValueTable Settings
inner class that handle the new values to lazy map. The
putString is a protected method call by Settings.Secure
and Settings.System inner classes (calls of Secure and
System).
So I could conclude that if the OS implementantion do not put thoose String values I can't get them.
2. TrafficStats
Just a quick look on official reference I could notice that it will
not help me because this class just provide the amount of bytes and
packages that was trafficked since last device boot.
http://developer.android.com/reference/android/net/TrafficStats.html
3. NetworkPolicyManager and NetworkPolicy
As #bina posted here the both classes are hidden and could not
be use by normal apps e.g. that will be published in Google Play.
https://stackoverflow.com/a/24445424/575643
4. ConnectivityManager
In short, you just can get the NetworkInfo that not provide
much information about user preferences (really none!). Just provide
informations about network and e.g. mobile network provider.
http://developer.android.com/reference/android/net/ConnectivityManager.html
After all I assume that no way to get this information nowadays. Please if you read it and found a way post here!
Thanks for all.
PS.: Sorry by english mistakes.
Do you want to get limit value(5GB) and warnning value(2GB) in this example?
If so, you can get limitBytes and warningBytes by the following code, if you can use android.permission.MANAGE_NETWORK_POLICY and android.permission.READ_PHONE_STATE.
However, android.permission.MANAGE_NETWORK_POLICY protectionLevel is signature.
NetworkPolicyManager manager = (NetworkPolicyManager) getSystemService("netpolicy");
NetworkPolicy[] networkPolicies = manager.getNetworkPolicies();
Log.d("NetworkPolicy", "limitBytes is " + networkPolicies[0].limitBytes);
Log.d("NetworkPolicy", "warningBytes is " + networkPolicies[0].warningBytes);
(NetworkPolicyManager and NetworkPolicy classes are hidden)
In android we have files by name String. Developers define the string values that they used for naming objects in this file. This is a very useful way. Because avoid of hard coding string values(you can change them from a single file, less time to change), also useful to creating multi language application and etc. (for more info just google this).
But the question is this: whether iPhone(Monotouch) have a mechanism like this to define strings on them or developers have to define themselves mechanism for this?
In XCode, you'll find File/New File, then on the left, pick "Resource", and you'll find "Strings File".
From code, you'll be referencing the keys in your strings file with NSLocalizedString:
NSLog("%#", NSLocalizedString(#"YOUR-STRING-KEY-OR-DEFAULT-VALUE", #"Comment about what this is"));
For details on what that second param is for, What is the second parameter of NSLocalizedString()?
Put your strings in a single file. Make them global constants. Access them throughout the app. When you change these, the change will be reflected everywhere.
It's not a big deal to have persistent string references throughout your app. It can be done in any decent programming language and platform I suppose.
I just curious. There are 3 method:
1. getPreferenceManager().setSharedPreferencesName(String PrefName);
2. PreferenceManager.getDefaultSharedPreferences(Context context)
3. Context.getSharedPreferences (String name, int mode)
As I know, the third method is only used when the first method is used, right?
But with 3 method we also use addPreferencesFromResource(int resID);
so, what is the difference? When can we use one of these method?
Thanks!
Let's go one step at a time:
setSharedPreferencesName() is method that allows to set the name of the preference group for later use. This is helpful for example when using the helper class of
PreferencesActivity before loading a preferences from XML resource file by calling addPreferencesFromResource(). It is therefore not as common as the other 2 methods you mentioned above.
getDefaultSharedPreferences() uses a default name, usually stored as /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml.
It is commonly used. Note that this default is set per application.
The alternative method - getSharedPreferences() requires to indicate a specific preference (file) name and an operation mode.
As appears also in another answer about shared preferences,
getDefaultSharedPreferences() in fact uses Context.getSharedPreferences, so the result is the same, but without the flexbility to split to multiple preference files, that is offered by getSharedPreferences(). Sharing the preferences between apps using
a MODE_WORLD_READABLE operation indicator is also something possible using getSharedPreferences(), but is rarely used.
IMHO, getDefaultSharedPreferences() can be safely used without going into the confusion of multiple preference file names that are prone to typos and confusion.
If someone knows of a good reason to use getSharedPreferences() and not getDefaultSharedPreferences(), please let me know by commenting here.
getDefaultSharedPreferences() uses a default preference-file name like "com.example.something_preferences". This default is set per application, so all activities in the same app context can access it easily as in the following example:
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
if (spref.contains("email")) {
String sEmailAddr = spref.getString("email", "");
}
The preferences are usually stored at /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml
getSharedPreference is the best way because using getDefaultSharedPreferences has some flaws
Actualy getDefaultSharedPreferences doesn't work correct on some
devices when build with targer api 13
Starting app from shortcut and from menu gives me different
DefaultSharedPreferences. After removing DefaultSharedPreferences
from my code - it works perfect. I can't just say: people dont make
shrotcuts, so I had to change code
This link may also help
From the name alone, I am guessing that Shared Preferences are... shared among apps?
That is, even if my app defines and creates them, any app on android can access them. Is this correct?
(If this isn't correct, then why does the Data Storage Dev Guide emphasize Internal Storage as "Store private data"?)
If this is correct, can I modify this default behavior so that a preference is only visible from the app in which I define and create it?
If so, how do I do that?
SharedPreferences are private by default. They are shared among the components of your app.
If i'm correct you can make store it as private by calling
getSharedPreferences(yourfile, MODE_PRIVATE);
public static final int MODE_PRIVATE
Since: API Level 1
File creation mode: the default mode, where the created file can only be accessed by the calling application (or all applications sharing the same user ID).
See Also:
MODE_WORLD_READABLE
MODE_WORLD_WRITEABLE
Constant Value: 0 (0x00000000)
The getSharedPreferences in the Context class takes two arguments, String name and int mode. Mode determines if the shared preferences are private or not.
Context.getSharedPreferences