I'm creating an app and I wanted to get the value of an item in strings.xml but without using the R.string method.
Is this possible?
Edit:
I'll explain what the app does.
Basically, there's a word, let's call it "Rose", Rose can mean "Flower" or "First name", since it has two meanings, when the users chooses one of the two meanings, the app displays an explanation for the selected meaning.
I can't use R.string.stringName because I made a db that stores the relation between the name and the meaning and the correct explanation.
I'm sorry if it's not clear enough, I really don't know how to explain it.
The only reason why you would do that is if you are developing a library and don't have direct access to R class of the end app. In that case you should use something like this
private String getSomeString() {
try {
return getContext().getResources().getString(getContext().getResources().getIdentifier("some_string_identifier", "string", getContext().getPackageName()));
} catch (Exception e) {
// Not found, use a default
return "1234567";
}
}
If i understood you correctly, you can just simply use :
private String getStringResourceByName(String aString) {
String packageName = getPackageName();
int resId = getResources().getIdentifier(aString, "string", packageName);
return getString(resId);
}
To get string by it's name, and not R.string
Related
I have declared a string in my strings.xml file , and using it in my activity as R.string.compose_title. (setting it as title i.e. setTitle(R.id.compose_title)). Now in some case I want to edit the string and then use it to set the title . How can I do this ?
P.S. I need to change value of a single string only , So declaring a new strings.xml for each case(which are variable depending upon the user) using localization seems to be a lil inefficient .
One thing what you have to understand here is that, when you provide a data as a Resource, it can't be modified during run time. For example, the drawables what you have in your drawable folder can't be modified at run time. To be precise, the "res" folder can't be modified programatically.
This applies to Strings.xml also, i.e "Values" folder. If at all you want a String which has to be modified at runtime, create a separate class and have your strings placed in this Class and access during run time. This is the best solution what I have found.
example howto:
how? by changing one variable reference to other reference
usage:
setRColor(pl.mylib.R.class,"endColor",pl.myapp.R.color.startColor);
// override app_name in lib R class
setRString(pl.mylib.R.class,"app_name",pl.myapp.R.string.app_name);
base methods:
public static void setRColor(Class rClass, String rFieldName, Object newValue) {
setR(rClass, "color", rFieldName, newValue);
}
public static void setRString(Class rClass, String rFieldName, Object newValue) {
setR(rClass, "string", rFieldName, newValue);
}
// AsciiStrings.STRING_DOLAR = "$";
public static void setR(Class rClass, String innerClassName, String rFieldName, Object newValue) {
setStatic(rClass.getName() + AsciiStrings.STRING_DOLAR + innerClassName, rFieldName, newValue);
}
helper methods :
public static boolean setStatic(String aClassName, String staticFieldName, Object toSet) {
try {
return setStatic(Class.forName(aClassName), staticFieldName, toSet);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}
}
public static boolean setStatic(Class<?> aClass, String staticFieldName, Object toSet) {
try {
Field declaredField = aClass.getDeclaredField(staticFieldName);
declaredField.setAccessible(true);
declaredField.set(null, toSet);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
#bradenV2 My app is supporting many languages , so I wanted to take a
string from my strings.xml that's currently in use and change that ,
and then use that one – atuljangra Mar 12 '12 at 22:04
ps the above solution is good for example when u want to inject some data in already compiled lib/jar. But if u want localize strings just make folder under res per LANG CODE like values-CC where cc is lang code (values-de,values-cs) etc
then u have 2 choices:
"build in" system dependent language selection - based on device selected lang
via create resources for configuration - you decide which lang show
like this:
configuration = new Configuration(resources.getConfiguration());
configuration.setLocale(targetLocale);
String localized = Context.createConfigurationContext(configuration)
.getResources()
.getString(resourceId);
I don't think you can programmatically customize the R class as it is built by ADT automatically.
I had a situation like this, where one of my strings.xml values had some dynamic piece of it. I set up the strings.xml with a "replacement text" (something like %%REPLACEMENT_EMAIL%%), and when I wanted to use that string programatically, I retrieved the string value of the resource, and replaced instances of that replacement text with the dynamic value (e.g. input by the user).
To be honest, my app has not been localized yet, but I'm still attempting to follow best practices w.r.t. not hardcoding any strings.
Use SharedPreferences instead of a Java class. It will give you more versatility if you decide to take values from the outside (web). Filling Java class in runtime can be useless offline. In case of SharedPreferences you have to ensure they are loaded only once, during app's first start, and then updated only by manual request, as previous import will be used.
myActivity.getSharedPreferences("com.example.imported",0)
.edit()
.putString("The news",getTheNews())
.apply();
Maybe you want to "modify" the string.xml so when it is required by the activity again it uses the new value, for example to keep a new dynamic title after screen rotation.
First, you can't modify the resource. It's already compiled. You can't modify the R class (what for?) all it's atributes are "final".
So, for the example above you can use onSaveInstanceState() and onRestoreInstanceState() for those properties you wanna keep on display.
According to my knowledge, you can't change resource value(R class value) while app running. why don't try to store on shared preference? I recommend you to use shared preference
I used below method to get the key-value pairs from the API and storing it in HashMap globally. If the key value is not found in HashMap then I will search that key in strings.xml file. It will achieve the purpose of dynamically changing the value of key.
public String getAppropriateLangText(String key) {
String value = "";
try {
HashMap<String, String> HashMapLanguageData HashMapLanguageData = gv.getHashMapLanguageData();
value = HashMapLanguageData.get(key);//Fetching the value of key from API
if (value == null || value.length() == 0) { //If Key value not found, search in strings.xml file
String packageName = getPackageName();
int resId = getResources().getIdentifier(key, "string", packageName);
value = getString(resId);
}
} catch (Exception e) {
value = "";
}
return value;
}
I've got a database of playerdata that has some pre-existing fields from previous versions of the program. Example out-dated document:
{
"playername": "foo"
}
but a player document generated under the new version would look like this:
{
"playername": "bar",
"playercurrency": 20
}
the issue is that if I try to query playercurrency on foo I get a NullPointerException because playercurrency doesn't exist for foo. I want to add the playercurrency field to foo without disturbing any other data that could be stored in foo. I've tried some code using $exists Example:
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playername", "")));
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playercurrency", 20)));
My thought is that it updates only playercurrency because it doesn't exist and it would leave playername alone becuase it exists. I might be using exists horribly wrong, and if so please do let me know because this is one of my first MongoDB projects and I would like to learn as much as I possibly can.
Do you have to do this with java? Whenever I add a new field that I want to be required I just use the command line to migrate all existing documents. This will loop through all players that don't have a playercurrency and set it to 0 (change to whatever default you want):
db.players.find({playercurrency:null}).forEach(function(player) {
player.playercurrency = 0; // or whatever default value
db.players.save(player);
});
This will result in you having the following documents:
{
"playername" : "foo",
"playercurrency" : 0
}
{
"playername" : "bar",
"playercurrency" : 20
}
So I know that it is normally frowned upon on answering your own question, but nobody really posted what I ended up doing I would like to take this time to thank #Mark Watson for answering and ultimately guiding me to finding my answer.
Since checking if a certain field is null doesn't work in the MongoDB Java Driver I needed to find a different way to know when something is primed for an update. So after a little bit of research I stumbled upon this question which helped me come up with this code:
private static void updateValue(final String name, final Object defaultValue, final UUID key) {
if (!exists(name, key)) {
FindIterable iterable = players.find(new Document("_id", key));
iterable.forEach(new Block<Document>() {
#Override
public void apply(Document document) {
players.updateOne(new Document("_id", key), new Document("$set", new Document(name, defaultValue)));
}
});
}
}
private static boolean exists(String name, UUID key) {
Document query = new Document(name, new Document("$exists", true)).append("_id", key);
return players.count(query) == 1;
}
Obviously this is a little specialized to what I wanted to do, but with little revisions it can be easliy changed to work with anything you might need. Make sure to replace players with your Collection object.
I want to add a functionality in my App, where a user can make buttons to launch apps on the device. Now, to set this up the user will enter the Intent Action they want to invoke. If user enters "ACTION_MAIN" as a string value, is it possible to process it as Intent.ACTION_MAIN in java ?
I know using a map can be one solution but maintaining an exhaustive list of all available intents can be cumbersome. Is their any other solution to this ? Can string value reference a variable ?
Lets say the user defined action as a string value is stored in userInput:
String userInput = "ACTION_MAIN";
You can get the corresponding value of Intent.<ACTION_SOMETHING> using reflection as follows:
try {
String action = (String) Intent.class.getDeclaredField(userInput).get(String.class);
// use the action value here..
} catch (Exception e) {
// no such action possible, maybe mistyped the action name
e.printStackTrace();
}
Example:
String action = (String) Intent.class.getDeclaredField("ACTION_MAIN").get(String.class);
returns:
"android.intent.action.MAIN"
I'm sure there's a better way to do this but I'm rather new to programming altogether so I apologize in advance for my noobiness.
Here's my problem:
I have an ArrayList filled with the name parameters of my strings in strings.xml, what I'm attempting to do is fill a TextView with .setText() utilizing a resource ID that is dynamically created from a part of my array. For example...
ArrayList<String> options = new ArrayList<String>();
options.add("bacon");
options.add("ham");
//R.id.option1 is in my layout and R.string.bacon is in my strings.xml
TextView option1 = (TextView)findViewById(R.id.option1);
option1.setText(R.string.(options.get(0)));
This isn't my complete code obviously. It's just a example faced by the same problem.
Any ideas?
Thanks in advance!
As an idea, instead of a String array of names, you could have an int array of resource ids:
ArrayList<Integer> options = new ArrayList<Integer>();
options.add(R.string.bacon);
options.add(R.string.ham);
//R.id.option1 is in my layout and R.string.bacon is in my strings.xml
TextView option1 = (TextView)findViewById(R.id.option1);
option1.setText(options.get(0));
It sounds like you want to look-up the resource id by name so you can use it in calls that expect the integer id (e.g. in findViewById()):
Resources.getIdentifier()
public int getIdentifier (String name, String defType, String defPackage)
Since: API Level 1
Return a resource identifier for the given resource name. A fully qualified resource name is of the form "package:type/entry". The first two components (package and type) are optional if defType and defPackage, respectively, are specified here.
Note: use of this function is discouraged. It is much more efficient to retrieve resources by identifier than by name.
Examples:
String name = "bacon";
int id = resources.getIdentifier(name, "string", "com.package");
if (id == 0) {
Log.e(TAG, "Lookup id for resource '"+name+"' failed";
// graceful error handling code here
}
or
String fullyQualifiedResourceName = "com.package:string/bacon";
int id = resources.getIdentifier(title, null, null);
if (id == 0) {
Log.e(TAG, "Lookup id for resource '"+fullyQualifiedResourceName+"' failed";
// graceful error handling code here
}
User submits a CSV file which is consumed by a program. Values which are used throughout the program come from the CSV, natually if values are missed it is a problem. Below is my solution.
Ip on top
private List<String> currentFieldName = new ArrayList<String>();
As part of the method:
try {
setCurrentFieldName("Trim Space");
p.setTrimSpace(currentLineArray[dc.getTRIM_POSITION()].equals("yes") ? true : false);
setCurrentFieldName("Ignore Case");
p.setIgnoreCase(currentLineArray[dc.getIGNORE_CASE_POSITION()].equals("yes") ? true : false);
} catch (NullPointerException e) {
throw new InputSpreadsheetValueUnassignedException("\"Type\" field not set: " + currentFieldName);
}
And the method which keeps track of a current field being looked at:
private void setCurrentFieldName(String fieldName) {
currentFieldName.clear();
currentFieldName.add(fieldName);
}
The idea there is that if user fails to submit value and i will end up getting null, before throwing an exception, i will know what value was not assigned.
So, this being said, specific questions:
Is what i have shown below an acceptable solution?
Can you suggest something more elegant?
First thing that comes to my mind is that using an ArrayList to represent the name of a single field is superfluous.
Why not just define a private String currentFieldName; and inside your try { } do currentFieldName = "Trim Space" etc?
Also,
p.setTrimSpace(currentLineArray[index].equals("yes") ? true : false);
can just as well be expressed as
p.setTrimSpace(currentLineArray[index].equals("yes"));
If your code goes through many columns, you could definitely make it more elegant. If not, your time might be better spent on other parts of your project.
The answer to whether or not your solution is acceptable depends on the requirements, and a test suite would be the ideal party to provide the yes or the no.