How do I format EditText for currency input in Android?

The following Android code snippet shows you how to customize the input value format of an EditText component for accepting currency number. To format the input value we will create a text watcher class called MoneyTextWatcher, this class implements of the android.text.TextWatcher interface. To apply this text watcher class we call the the addTextChangedListener() method of the EditText object and pass an instance of MoneyTextWatcher.

package org.kodejava.android;

import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

import java.math.BigDecimal;

public class MainActivity extends AppCompatActivity {
    private EditText editText;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText = findViewById(R.id.editText);
        editText.addTextChangedListener(new MoneyTextWatcher(editText));

        textView = findViewById(R.id.textView);
    }

    public void doGetValue(View view) {
        BigDecimal value = MoneyTextWatcher.parseCurrencyValue(editText.getText().toString());
        textView.setText(String.valueOf(value));
    }
}

When the EditText input is changed the afterTextChanged() method of the text watcher will be called. In this method we’ll take the input text and format the input value with currency symbol and a number, this is done by the NumberFormat.getCurrencyInstance() object. The static helper method parseCurrencyValue() will get the number part of the EditText by removing the currency symbol and return the input number.

package org.kodejava.android;

import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;

import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Objects;

public class MoneyTextWatcher implements TextWatcher {
    public static final NumberFormat numberFormat = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
    private final WeakReference<EditText> editTextWeakReference;

    public MoneyTextWatcher(EditText editText) {
        editTextWeakReference = new WeakReference<>(editText);
        numberFormat.setMaximumFractionDigits(0);
        numberFormat.setRoundingMode(RoundingMode.FLOOR);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }

    @Override
    public void afterTextChanged(Editable s) {
        EditText editText = editTextWeakReference.get();
        if (editText == null || editText.getText().toString().equals("")) {
            return;
        }
        editText.removeTextChangedListener(this);

        BigDecimal parsed = parseCurrencyValue(editText.getText().toString());
        String formatted = numberFormat.format(parsed);

        editText.setText(formatted);
        editText.setSelection(formatted.length());
        editText.addTextChangedListener(this);
    }

    public static BigDecimal parseCurrencyValue(String value) {
        try {
            String replaceRegex = String.format("[%s,.\\s]", Objects.requireNonNull(numberFormat.getCurrency()).getDisplayName());
            String currencyValue = value.replaceAll(replaceRegex, "");
            return new BigDecimal(currencyValue);
        } catch (Exception e) {
            Log.e("MyApp", e.getMessage(), e);
        }
        return BigDecimal.ZERO;
    }
}

The following animation is the result of our code snippet above.

Currency Format EditText Demo

Currency Format EditText Demo

How do I get Android Device ID or IMEI?

The following code snippets shows you how to get a Device ID of an Android phone. To be able to read the Device ID you need to update the AndroidManifest.xml file and add the READ_PHONE_STATE permission.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.kodejava.android">

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    ...
    ...
</manifest>
package org.kodejava.android;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity {

    private static final int PERMISSIONS_READ_PHONE_STATE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, PERMISSIONS_READ_PHONE_STATE);
        }

        String deviceId = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
        } else {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (telephonyManager.getImei() != null) {
                deviceId = telephonyManager.getImei();
            } else if (telephonyManager.getMeid() != null) {
                deviceId = telephonyManager.getMeid();
            }
        }

        Log.d("MyApp", "Device ID: " + deviceId);
    }
}

How do I print to a Bluetooth thermal printer in Android?

In this example we are going to create a simple Android application to print texts to a Bluetooth thermal printer. We’ll be using the Android library for ESC/POS Thermal Printer to develop this example.

We begin by creating an Android project with an Empty Activity. After the project is created we need to edit the app/build.gradle to add the required dependencies and the repository from which it will be downloaded.

...
...

dependencies {
    ...
    ...
    implementation 'com.github.dantsu:escpos-thermalprinter-android:2.0.11'
}

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

Next, add the permission to access Bluetooth in the AndriodManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.kodejava.android">

    <uses-permission android:name="android.permission.BLUETOOTH" />

    ...
    ...
</manifest>

Let’s now jump to the code snippet that will actually print our store receipt to the printer. The steps are quite simple.

After added the uses-permission in the AndroidManigest.xml we also need to check permission in the application, you’ll do it like this.

if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH}, MainActivity.PERMISSION_BLUETOOTH);
}

Open the connection to Bluetooth printer by calling the selectFirstPaired() method of the BluetoothPrintersConnections class. This will give us an instance of BluetoothConnection. If the connection is good we create an instance of EscPosPrinter by passing some parameters like the connection, printer dpi, width in millimeter and the printer’s number of character per line.

BluetoothConnection connection = BluetoothPrintersConnections.selectFirstPaired();
EscPosPrinter printer = new EscPosPrinter(connection, 203, 48f, 32);

The next step is to prepare the text to be printed and called the printFormattedText() of the printer object and pass the text to be printed.

String text = "[C]Hello World!\n";
printer.printFormattedText(text);

Here is the full code snippet for our application.

package org.kodejava.android;

import android.Manifest;
import android.content.pm.PackageManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.dantsu.escposprinter.EscPosPrinter;
import com.dantsu.escposprinter.connection.bluetooth.BluetoothConnection;
import com.dantsu.escposprinter.connection.bluetooth.BluetoothPrintersConnections;
import com.dantsu.escposprinter.textparser.PrinterTextParserImg;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    public static final int PERMISSION_BLUETOOTH = 1;

    private final Locale locale = new Locale("id", "ID");
    private final DateFormat df = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss a", locale);
    private final NumberFormat nf = NumberFormat.getCurrencyInstance(locale);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void doPrint(View view) {
        try {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH}, MainActivity.PERMISSION_BLUETOOTH);
            } else {
                BluetoothConnection connection = BluetoothPrintersConnections.selectFirstPaired();
                if (connection != null) {
                    EscPosPrinter printer = new EscPosPrinter(connection, 203, 48f, 32);
                    final String text = "[C]<img>" + PrinterTextParserImg.bitmapToHexadecimalString(printer,
                            this.getApplicationContext().getResources().getDrawableForDensity(R.drawable.logo,
                                    DisplayMetrics.DENSITY_LOW, getTheme())) + "</img>\n" +
                            "[L]\n" +
                            "[L]" + df.format(new Date()) + "\n" +
                            "[C]================================\n" +
                            "[L]<b>Effective Java</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(25000) + "\n" +
                            "[L]<b>Headfirst Android Development</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(45000) + "\n" +
                            "[L]<b>The Martian</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(20000) + "\n" +
                            "[C]--------------------------------\n" +
                            "[L]TOTAL[R]" + nf.format(90000) + "\n" +
                            "[L]DISCOUNT 15%[R]" + nf.format(13500) + "\n" +
                            "[L]TAX 10%[R]" + nf.format(7650) + "\n" +
                            "[L]<b>GRAND TOTAL[R]" + nf.format(84150) + "</b>\n" +
                            "[C]--------------------------------\n" +
                            "[C]<barcode type='ean13' height='10'>202105160005</barcode>\n" +
                            "[C]--------------------------------\n" +
                            "[C]Thanks For Shopping\n" +
                            "[C]https://kodejava.org\n" +
                            "[L]\n" +
                            "[L]<qrcode>https://kodejava.org</qrcode>\n";

                    printer.printFormattedText(text);
                } else {
                    Toast.makeText(this, "No printer was connected!", Toast.LENGTH_SHORT).show();
                }
            }
        } catch (Exception e) {
            Log.e("APP", "Can't print", e);
        }
    }
}

The following image is the result of our code snippet printed on 48mm thermal printer.

Android Bluetooth Thermal Printer

Android Bluetooth Thermal Printer

You can find the complete source code in the following repository Android Bluetooth Thermal Printer Example. For more information on formatted text syntax guideline you can visit the project documentation website.

How do I read MySQL data from Android using JDBC?

This example show you how to connect and read data from MySQL database directly from Android. The following steps and code snippet will show you how to do it.

Add the MySQL JDBC driver into your project dependencies. Open the app/build.gradle file and add the dependency.

...
...

dependencies {
    ...
    ...
    implementation 'mysql:mysql-connector-java:5.1.49'
}

If you want to connect to MariaDB you can change the JDBC driver dependency using 'org.mariadb.jdbc:mariadb-java-client:1.8.0', also update the JDBC url in the code snippet by replacing mysql with mariadb.

Next, add internet permission to our application in AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.kodejava.android">

    <uses-permission android:name="android.permission.INTERNET" />

    ...
    ...

</manifest>

Let’s connect, read data from the database and display the information on the screen. In the code snippet we create an AsyncTask to read the information from the database. In the doInBackground() method we open a connection to the database, create a PreparedStatement, execute a query, get a ResultSet and read the information from it. We pack the data into a Map and return it.

After the doInBackground() method finish its execution the onPostExecute() method will be called. In this method we take the result, the Map returned by the doInBackground() method, and set the values into the TextView compoments for display.

package org.kodejava.android;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
    private static final String URL = "jdbc:mysql://192.168.0.107:3306/kodejava";
    private static final String USER = "kodejava";
    private static final String PASSWORD = "kodejava";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new InfoAsyncTask().execute();
    }

    @SuppressLint("StaticFieldLeak")
    public class InfoAsyncTask extends AsyncTask<Void, Void, Map<String, String>> {
        @Override
        protected Map<String, String> doInBackground(Void... voids) {
            Map<String, String> info = new HashMap<>();

            try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {
                String sql = "SELECT name, address, phone_number FROM school_info LIMIT 1";
                PreparedStatement statement = connection.prepareStatement(sql);
                ResultSet resultSet = statement.executeQuery();
                if (resultSet.next()) {
                    info.put("name", resultSet.getString("name"));
                    info.put("address", resultSet.getString("address"));
                    info.put("phone_number", resultSet.getString("phone_number"));
                }                
            } catch (Exception e) {
                Log.e("InfoAsyncTask", "Error reading school information", e);
            }

            return info;
        }

        @Override
        protected void onPostExecute(Map<String, String> result) {
            if (!result.isEmpty()) {
                TextView textViewName = findViewById(R.id.textViewName);
                TextView textViewAddress = findViewById(R.id.textViewAddress);
                TextView textViewPhoneNumber = findViewById(R.id.textViewPhone);

                textViewName.setText(result.get("name"));
                textViewAddress.setText(result.get("address"));
                textViewPhoneNumber.setText(result.get("phone_number"));
            }
        }
    }
}
  • Finally here is the screenshot of our Android application.
Android - MySQL JDBC

Android – MySQL JDBC

The complete source code can be accesses in our GitHub repository here: android-mysql-example.