I tried to convert int to curency format and everything worked as I expected
example 1000 --> Rp1.000
but on certain devices the results are not what I expected
i.e. 1000 --> Rp1.000,00
So the question is how to remove the last 2 extra nolls if the device displays them.
my current code:
public static String toUang(String DigitUang) {
return NumberFormat.getCurrencyInstance(new Locale("in", "ID")).format(Double.parseDouble(DigitUang));
}
The best solution here would probably be to fix your locale settings and handle the presentation there. That being said, you also could probably handle this using a regex replacement:
public static String toUang(String DigitUang) {
return NumberFormat.getCurrencyInstance(new Locale("in", "ID"))
.format(Double.parseDouble(DigitUang))
.replaceAll("[,.]00$", "");
}
Related
I have a large Android codebase and I am writing a custom lint rule that checks whether the values of certain attributes fall within a given range.
For example, I have this component:
<MyCustomComponent
my:animation_factor="0.7"
...>
</MyCustomComponent>
and I want to write a lint rule that alerts developers that values of my:animation_factor >= 1 should be used with caution.
I followed the instructions at http://tools.android.com/tips/lint-custom-rules and managed to retrieve the value of my:animation_factor using this code:
import com.android.tools.lint.detector.api.*;
public class XmlInterpolatorFactorTooHighDetector {
....
#Override
public Collection<String> getApplicableElements() {
return ImmutableList.of("MyCustomComponent");
}
#Override
public void visitElement(XmlContext context, Element element) {
String factor = element.getAttribute("my:animation_factor");
...
if (value.startsWith("#dimen/")) {
// How do I resolve #dimen/xyz to 1.85?
} else {
String value = Float.parseFloat(factor);
}
}
}
This code works fine when attributes such as my:animation_factor have literal values (e.g. 0.7).
However, when the attribute value is a resources (e.g. #dimen/standard_anim_factor) then element.getAttribute(...) returns the string value of the attribute instead of the actual resolved value.
For example, when I have a MyCustomComponent that looks like this:
<MyCustomComponent
my:animation_factor="#dimen/standard_anim_factory"
...>
</MyCustomComponent>
and #dimen/standard_anim_factor is defined elsewhere:
<dimen name="standard_anim_factor">1.85</dimen>
then the string factor becomes "#dimen/standard_anim_factor" instead of "1.85".
Is there a way to resolve "#dimen/standard_anim_factor" to the actual value of resource (i.e. "1.85") while processing the MyCustomComponent element?
The general problem with the resolution of values is, that they depend on the Android runtime context you are in. There might be several values folders with different concrete values for your key #dimen/standard_anim_factory, so just that you are aware of.
Nevertheless, AFAIK there exist two options:
Perform a two phase detection:
Phase 1: Scan your resources
Scan for your attribute and put it in a list (instead of evaluating it immediately)
Scan your dimension values and put them in a list as well
Phase 2:
override Detector.afterProjectCheck and resolve your attributes by iterating over the two lists filled within phase 1
usually the LintUtils class [1] is a perfect spot for that stuff but unfortunately there is no method which resolves dimensions values. However, there is a method called getStyleAttributes which demonstrates how to resolve resource values. So you could write your own convenient method to resolve dimension values:
private int resolveDimensionValue(String name, Context context){
LintClient client = context.getDriver().getClient();
LintProject project = context.getDriver().getProject();
AbstractResourceRepository resources = client.getProjectResources(project, true);
return Integer.valueOf(resources.getResourceItem(ResourceType.DIMEN, name).get(0).getResourceValue(false).getValue());
}
Note: I haven't tested the above code yet. So please see it as theoretical advice :-)
https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java
Just one more slight advice for your custom Lint rule code, since you are only interested in the attribute:
Instead of doing something like this in visitElement:
String factor = element.getAttribute("my:animation_factor");
...you may want to do something like this:
#Override
public Collection<String> getApplicableAttributes() {
return ImmutableList.of("my:animation_factor");
}
#Override
void visitAttribute(#NonNull XmlContext context, #NonNull Attr attribute){
...
}
But it's just a matter of preference :-)
I believe you're looking looking for getResources().getDimension().
Source: http://developer.android.com/reference/android/content/res/Resources.html#getDimension%28int%29
Assuming xml node after parsing your data, try the following
Element element = null; //It is your root node.
NamedNodeMap attrib = (NamedNodeMap) element;
int numAttrs = attrib.getLength ();
for (int i = 0; i < numAttrs; i++) {
Attr attr = (Attr) attrib.item (i);
String attrName = attr.getNodeName ();
String attrValue = attr.getNodeValue ();
System.out.println ("Found attribute: " + attrName + " with value: " + attrValue);
}
I'm using the speech recognizer to get a voice input from the user, it returns an array of 5 strings which I pass to this method
public int analyzeTag(ArrayList<String> voiceResults,Editor editor, Context context){
for (String match : voiceResults) {
Log.d(TAG, match);
if (match.equalsIgnoreCase(context.getResources().getString(R.string.first_tag))){
editor.append(context.getResources().getString(R.string.first_tag));
return 1;
}
else if (match.equalsIgnoreCase(context.getResources().getString(R.string.second_tag))){
editor.append(context.getResources().getString(R.string.second_tag));
return 1;
}
//etc....(huge list of tags)
//Some tags might also have acceptable variations, example:
else if (match.equalsIgnoreCase("img") || match.equalsIgnoreCase("image")
{
editor.append("img"); //the string to append is always taken from the first variation
}
}
return 0;
}
This method compares the results with a list of tags, the tag list will be pretty big with hundreds of tags so I would like to find the most efficient way to do this operation.
I need help with:
1.Is my way of comparing results the most efficient? Is there a better way? (from the user experience perspective, I don't want users waiting a long time to get a result).
The voice input will be a big part of my app so this method will be called quite often
2.I have a long list of tags, obviously the if(), elseIf() route is gonna be quite repetitive, is there a way to iterate this? Considering the fact that some tags might have variations (even more than 1)and that the variation 1 ("img") will be the same for everyone, but other variations will be locale/language sensitive example: "image" for english users "immagini" for italian users etc.
Text appended to the editor will be always taken from the first variation
How about puting tags in a StringArray and then iterate though the array ?
String[] tags = context.getResources().getStringArray(R.array.tags);
for (String match : voiceResults) {
for (int index = 0; index < tags.length; index++ ) {
if (match.equalsIgnoreCase(tags[index]) {
editor.append(tags[index]);
}
}
}
Here's the doc on StringArray
I've seen many people do similar to this in order to get the last word of a String:
String test = "This is a sentence";
String lastWord = test.substring(test.lastIndexOf(" ")+1);
I would like to do similar but get the last few words after the last int, it can't be hard coded as the number could be anything and the amount of words after the last int could also be unlimited. I'm wondering whether there is a simple way to do this as I want to avoid using Patterns and Matchers again due to using them earlier on in this method to receive a similar effect.
Thanks in advance.
I would like to get the last few words after the last int.... as the number could be anything and the amount of words after the last int could also be unlimited.
Here's a possible suggestion. Using Array#split
String str = "This is 1 and 2 and 3 some more words .... foo bar baz";
String[] parts = str.split("\\d+(?!.*\\d)\\s+");
And now parts[1] holds all words after the last number in the string.
some more words .... foo bar baz
What about this one:
String test = "a string with a large number 1312398741 and some words";
String[] parts = test.split();
for (int i = 1; i < parts.length; i++)
{
try
{
Integer.parseInt(parts[i])
}
catch (Exception e)
{
// this part is not a number, so lets go on...
continue;
}
// when parsing succeeds, the number was reached and continue has
// not been called. Everything behind 'i' is what you are looking for
// DO YOUR STUFF with parts[i+1] to parts[parts.length] here
}
What does the Android OS use to format Dates and Times in notifications?
I assumed it used DateUtils.formatSameDayTime, but it does not exactly do that. The logic appears the same, but the format is not exactly the same. For instance, a notification will show me "2013-08-06" (based on my System Settings) when formatSameDayTime returns "8/6/13".
Edit:
Here's my current solution. But is it the best?
public static final CharSequence formatSameDayTimeCustom(Context context, long then) {
if (DateUtils.isToday(then)) {
return DateFormat.getTimeFormat(context).format(new Date(then));
}
else {
final String format = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT);
return new SimpleDateFormat(format).format(new Date(then));
}
}
I've faced a problem with quantity strings (plurals).
The manual says, I may provide quantity strings that are specific for each localization, and there are several common cases: "zero", "one", "two", "few", "many", and "other". I don't know if all possible cases for all languages in the world were covered; anyway, it is more than enough for Russian that I'm trying to make a localization for.
In Russian, numbers from 2 to 4 should be treated like "few" (the rule is actually more complex but I only need numbers below ten).
However, when I request a quantity string for 2, the system takes the "other" string. It doesn't take neither "two" string nor "few" one (I have provided them in my resources). If I removed the "other" string, I get the exception:
android.content.res.Resources$NotFoundException:
Plural resource ID #0x7f080000 quantity=2 item=other
I tried this both on emulator (Android 2.1) and on a real device (Android 2.3), the behaviour is the same wrong in both cases. Obviously, there is a mistake somewhere—the system does not recognize locale-specific quantities for my language. Could it be that Android has some bug here?
I believe this is currently broken in Android.
http://code.google.com/p/android/issues/detail?id=8287
Specifically, the following code in PluralRules.java shows that most languages only use the one or other strings, but Czech will use the few string:
static final PluralRules ruleForLocale(Locale locale) {
String lang = locale.getLanguage();
if ("cs".equals(lang)) {
if (cs == null) cs = new cs();
return cs;
}
else {
if (en == null) en = new en();
return en;
}
}
private static PluralRules cs;
private static class cs extends PluralRules {
int quantityForNumber(int n) {
if (n == 1) {
return QUANTITY_ONE;
}
else if (n >= 2 && n <= 4) {
return QUANTITY_FEW;
}
else {
return QUANTITY_OTHER;
}
}
}
private static PluralRules en;
private static class en extends PluralRules {
int quantityForNumber(int n) {
if (n == 1) {
return QUANTITY_ONE;
}
else {
return QUANTITY_OTHER;
}
}
}
Thanks to Brigham who has pointed to the issue where the problem is explained; that explanation first rised more questions but now they seem to be solved. Indeed, the quantity strings don't work properly (at least prior to API 11, which is Android 3.x), so you have to use an alternative.
The solution for APIs prior to version 11 is mentioned in the comment 15 that contains a link to the project for alternative handling of quantity strings. That project is a program that simply does what the system was supposed to do. It can be converted to a library easily, so you just add it to your project, import the class and go.
Define your plurals strings in values-ru/strings.xml not in values/strings.xml
set your mobile device language as Russian (from setting->Language&input->Language->select Russian)
If your language is not Russian it will take plurals strings from values/strings.xml