Set variable for R.drawable - android

At the moment I set a marker image for google maps on android like this:
.icon(BitmapDescriptorFactory.fromResource(R.drawable.mon1))
Where mon1 is the name of the corresponding to a image called mon1.png in drawable folder.
How can I do it like this:
String imagename="blablaimage";
.icon(BitmapDescriptorFactory.fromResource(R.drawable.imagename))

It is not possible to do what you suggested.
Instead, a possible workaround might be to use the following function:
public int getDrawableId(String name){
try {
Field fld = R.drawable.class.getField(name);
return fld.getInt(null);
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
and use like:
String imagename="blablaimage";
.icon(BitmapDescriptorFactory.fromResource(getDrawableId(imagename)));

If you click over R.drawable.mon1, you'll find an int declared with the name mon1 in R.java class. Everything resides in R class is basically an int. That said, you can't declare variable imagename as String to begin with. It must be int.
Everything generates in R.java class is auto generated by Android itself. Once you put some resources in appropriate directory, R.java generates corresponding resource int within so that it can be invoked from Java-end.
Bottom line, if you have an image called blablaimage somewhere in your drawable, you can (at best) do this,
int imagename= R.drawable.blablaimage;
.icon(BitmapDescriptorFactory.fromResource(imagename))

Another possibility using Resources.getIdentifier:
.icon(BitmapDescriptorFactory.fromResource(
context.getResources().getIdentifier(imagename, "drawable", "com.mypackage.myapp");
));

Related

Can I modify a Strings.xml file programmatically in Android? [duplicate]

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;
}

How to get my images in my /res folder dynamically

I am trying to get images out of my /res folder dynamically and I am just confused on the next part. I looked around StackOverflow and saw this example which is what I needed to start off with:
String fName = "android.resource://j.l.library11/drawable/" + itemName;
I thought though that since its in my /res folder it would be:
String fName = "android.resource://j.l.library11/drawable/res/" + itemName;
Which 1 of these 2 would be correct?
Also, I am just confused on what my next few steps would be to get to the point where I can set my ImageView (iView) with the image from my /res folder (itemName). The only thing I can think of off the top of my head is:
File file = new File(fName);
and then get the hash code
int itemHashCode = file.HashCode()
and then use that as
iView.setImageResource(itemHashCode).
Would that work or does anyone know the correct solution to this?
Images placed in res/drawable are automatically compiled by AAPT to integer mappings inside of your R.java class. You can set the image on an ImageView using:
myImageView.setImageResource(R.drawable.nameOfYourImage);
EDIT: I'm not clear on why you'd want to do what you're doing, but setting the resource of an ImageView with the hashcode of your image will cause a ResourceNotFoundException.
EDIT: If you're trying to be able to set the image dynamically based on an association with some data from a database, then take advantage of the fact that you have compiled drawables by saving the int of of your R.drawable.imagename in a new integer column in your DB. Then you can simply set the image like setImageResource(intFromDB). If you aren't setting up the DB in code and, therefore, don't have access to the compiled R.drawable, an alternative is something like this:
Resources res = getResources();
String mDrawableName = "image_name";
int resourceId = res.getIdentifier(mDrawableName , "drawable", getPackageName());
Drawable drawable = res.getDrawable(resourceId);
icon.setImageDrawable(drawable );
Or even shorter, this may work:
int id = getResources().getIdentifier("mypackagename:drawable/imageName", null, null);
imageView.setImageResource(id);
I would go with reflection:
Field[] fields = R.drawable.class.getFields();
for(Field field:fields){
try {
imageView.setImageResource(field.getInt(null));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Can you call a string resource with a string?

I have a method that returns one of about 20 possible strings from an EditText. Each of these strings has a corresponding response to be printed in a TextView from strings.xml. Is there a way to call a string from strings.xml using something like context.getResources().getString(R.strings."stringFromMethod")? Is there another way to call a string from a large list like that?
The only methods I can think of is converting each string to an int, and use that to find a string in a string array, or a switch statement. Both of which involve a huge amount if-else if statements to convert the string to an int, and would take just enough steps to change if any strings were added or taken away that I'd be more likely to miss one and have fun bug hunting. Any ideas to do this cleanly?
Edit: Forgot to add, another method I tried was using was to get the resourceID from
int ID = context.getResources().getIdentifier("stringFromMethod", "String", context.getPackageName())
and taking that integer and putting it in
context.getResources().getString(ID)
That doesn't appear to be working either.
No, you can't. The getString() requires the resource id in integer format, so you can't append a string to it.
You can, however, try this:
String packageName = context.getPackageName();
int resId = context.getResources().getIdentifier("stringFromMethod", "string", packageName);
if (resId == 0) {
throw new IllegalException("Unknown string resource!"; // can't find the string resource!
}
string stringVal = context.getString(resId);
The above statements will return string value of resource R.string.stringFromMethod.
You need to use reflection (pretty ugly but only solution) load the R class, and get the relevant field by you string and get the value of it.
this is what I used to do in these kind of situations, I will made a Array like
int[] stringIds = { R.string.firstCase,
R.string.secondCase, R.string.thridCase,
R.string.fourthCase,... };
int caseFromServer=getCaseofServerResponse();
here caseFromServer varies from 0 to wahtever
and then simply
context.getResources().getString(stringIds[caseFromServer]);

How to easily iterate over all strings within the "strings.xml" resource file?

I created an application that uses the TTS engine to send feedback to the user. With the aim to improve the performance, I used the synthesizeToFile and addSpeech methods, but strings of text to be synthesized are inside the strings.xml file, so I have to invoke these methods for each string that is spoken by the TTS engine.
Since the TTS engine uses only strings whose name begins with tts_, is it possible to easily iterate over all strings that begin with tts_ within the strings.xml file?
You can get all the strings in strings.xml via reflection, and filter out only the ones you need, like so:
for (Field field : R.string.class.getDeclaredFields())
{
if (Modifier.isStatic(field.getModifiers()) && !Modifier.isPrivate(field.getModifiers()) && field.getType().equals(int.class))
{
try
{
if (field.getName().startsWith("tts_"))
{
int id = field.getInt(null);
// do something here...
}
} catch (IllegalArgumentException e)
{
// ignore
} catch (IllegalAccessException e)
{
// ignore
}
}
}
You can give them all (while defining) the resource name as "prefix"+(1..n). And in the code use,
int resid=<constant>;
for(i=1;resid!=0;i++){
resid = this.getResources().getIdentifier("prefix"+i, "strings", this.getPackageName());
}
You could put these TTS strings into a TypedArray.
you can use this code:
String[] strings = getResources().getAssets().list("string");
for (int i = 0; i < strings.length; i++) {
Log.d("aaa ", strings[i]);
}
to iterate through other resources like fonts,... just replace string with folder name.
In all my projects, i just observed that the value of strings in R.java starts with 0x7f050000 and it counts upwards, like 0x7f050001, 0x7f050002, 0x7f050003,....
You could just ++ them :D
Hope it helps :)

How do I get the resource id of an image if I know its name? [duplicate]

This question already has answers here:
Android, getting resource ID from string?
(14 answers)
Closed 2 years ago.
How do I get the resource id of an image if I know its name (in Android)?
With something like this:
String mDrawableName = "myappicon";
int resID = getResources().getIdentifier(mDrawableName , "drawable", getPackageName());
You can also try this:
try {
Class res = R.drawable.class;
Field field = res.getField("drawableName");
int drawableId = field.getInt(null);
}
catch (Exception e) {
Log.e("MyTag", "Failure to get drawable id.", e);
}
I have copied this source codes from below URL. Based on tests done in this page, it is 5 times faster than getIdentifier(). I also found it more handy and easy to use. Hope it helps you as well.
Link: Dynamically Retrieving Resources in Android
Example for a public system resource:
// this will get id for android.R.drawable.ic_dialog_alert
int id = Resources.getSystem().getIdentifier("ic_dialog_alert", "drawable", "android");
Another way is to refer the documentation for android.R.drawable class.
You can use this function to get a Resource ID:
public static int getResourseId(Context context, String pVariableName, String pResourcename, String pPackageName) throws RuntimeException {
try {
return context.getResources().getIdentifier(pVariableName, pResourcename, pPackageName);
} catch (Exception e) {
throw new RuntimeException("Error getting Resource ID.", e)
}
}
So if you want to get a Drawable Resource ID, you can call the method like this:
getResourseId(MyActivity.this, "myIcon", "drawable", getPackageName());
(or from a fragment):
getResourseId(getActivity(), "myIcon", "drawable", getActivity().getPackageName());
For a String Resource ID you can call it like this:
getResourseId(getActivity(), "myAppName", "string", getActivity().getPackageName());
etc...
Careful: It throws a RuntimeException if it fails to find the Resource ID. Be sure to recover properly in production.
Read this
One other scenario which I encountered.
String imageName ="Hello"
and then when it is passed into
getIdentifier function as first argument, it will pass the name with string null termination and will always return zero.
Pass this
imageName.substring(0, imageName.length()-1)

Categories

Resources