A Better Approach to Format Currency Input in Android EditText

Dec 07, 2025 · Programming · 13 views · 7.8

Keywords: Android | CurrencyFormatting | EditText | TextWatcher

Abstract: This article addresses common issues in formatting currency input for Android applications, particularly when users manipulate the cursor. Based on a high-scoring Stack Overflow answer, it proposes an improved solution using TextWatcher to dynamically handle input and avoid formatting errors. Key concepts include TextWatcher implementation, input sanitization, currency formatting, and preventing format anomalies from cursor positions. Through code examples and in-depth analysis, it helps developers optimize user interface experiences.

Problem Description

In Android development, formatting currency input is a common requirement, especially in EditText components. A typical scenario involves users entering amounts starting from an initial value like $0.00, incrementally with key presses—e.g., pressing 1 changes to $0.01, 4 to $0.14, 8 to $1.48, and backspace returns to $0.14. However, when users manually move the cursor, existing code often faces formatting issues: the decimal point does not reappear after deletion, input before the decimal displays incorrectly like $02.00, or deleting the currency symbol inadvertently removes digits.

Analysis of Existing Code Defects

Based on the Q&A data, the original code uses the onTextChanged method of TextWatcher with regular expression matching for currency format. This approach has limitations: regular expressions fail to flexibly handle user cursor manipulations, leading to formatting failures. Specifically, when users intervene with input, the code may ignore deletions of decimal points or currency symbols, causing display errors. Additionally, using Float for currency processing can result in precision loss, particularly with large numbers.

Improved Solution: Dynamic Handling with TextWatcher

The best answer proposes an enhanced method centered on dynamically cleaning and formatting input in the onTextChanged event. Steps include: first removing the TextWatcher to avoid recursive calls, then sanitizing the input string by removing currency symbols and decimal points, converting the cleaned string to a numeric value, dividing by 100 to handle cents, and finally formatting using NumberFormat.getCurrencyInstance() and setting it back to the EditText. This method bypasses the rigidity of regular expressions and effectively manages cursor operations.

Code Implementation Example

Below is a rewritten Java code example based on core concepts:

private String currentFormattedText = ""; @Override public void onTextChanged(CharSequence inputSequence, int startIndex, int beforeCount, int count) { String inputString = inputSequence.toString(); if (!inputString.equals(currentFormattedText)) { editText.removeTextChangedListener(this); String cleanedString = inputString.replaceAll("[\$,.]", ""); double numericValue = Double.parseDouble(cleanedString); String formattedCurrency = NumberFormat.getCurrencyInstance().format(numericValue / 100.0); currentFormattedText = formattedCurrency; editText.setText(formattedCurrency); editText.setSelection(formattedCurrency.length()); editText.addTextChangedListener(this); } }

In Kotlin, a similar implementation uses extension functions and string operations for conciseness. This approach compares current text with formatted text to avoid unnecessary updates, enhancing efficiency.

Supplementary Reference: MoneyTextWatcher Class

Other answers provide a MoneyTextWatcher class that encapsulates similar logic, using WeakReference to prevent memory leaks and handling in afterTextChanged for robustness. For example:

public class MoneyTextWatcher implements TextWatcher { private final WeakReference<EditText> editTextRef; public MoneyTextWatcher(EditText editText) { editTextRef = new WeakReference<>(editText); } @Override public void afterTextChanged(Editable editable) { EditText editText = editTextRef.get(); if (editText == null || editable.toString().isEmpty()) return; editText.removeTextChangedListener(this); String cleaned = editable.toString().replaceAll("[\$,.]", ""); BigDecimal value = new BigDecimal(cleaned).divide(new BigDecimal(100), 2, BigDecimal.ROUND_FLOOR); String formatted = NumberFormat.getCurrencyInstance().format(value); editText.setText(formatted); editText.setSelection(formatted.length()); editText.addTextChangedListener(this); } }

This supplements the use of BigDecimal for precision, suitable for financial applications.

Conclusion and Best Practices

In summary, an improved currency input formatting method should prioritize dynamic cleaning and NumberFormat over regular expression constraints. Key points include: removing and re-adding listeners in TextWatcher to prevent infinite loops, handling user cursor interventions, and using appropriate numeric types like BigDecimal for accuracy. This enhances user experience and code maintainability, applicable to currency input scenarios in Android app development.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.