In this article, we will be building a Bitcoin Tracker Project using Java/Kotlin and XML in Android. The application will display the current rates of Bitcoin in different countries using Bitcoin API. There are many free APIs available and for this project, we will be using API by Coinlayer. The API will return a JSON that we will parse according to our needs. There will be a single activity in this app.
Step-by-Step Implementation
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.
Select Java/Kotlin as the programming language.
Step 2: Adding Internet permission
To use the internet access and call the API, we need permission. Add internet permission in the AndroidManifest.xml file
<uses-permission android:name="android.permission.INTERNET"/>Step 3: Adding Retrofit Dependencies
Navigate to Gradle Scripts > build.gradle.kts (Module: app) and add the following dependencies for Retrofit and GSON.
dependencies {
implementation ("com.google.code.gson:gson:2.9.1")
implementation ("com.squareup.retrofit2:retrofit:2.9.0")
implementation ("com.squareup.retrofit2:converter-gson:2.9.0")
}
Step 4: Get API Key
You need to create a free account on Coinlayer and get an API key for this project. Click on "Get free API key" on the website. SignUp using your account information, and you will get your API key.
Step 5: Adding Bitcoin Image
Download the bitcoin image from here and add it into your project inside the app > res > drawable folder
Refer this article: How to Add Image to Drawable Folder in Android Studio?
Step 6: Create Java/Kotlin files for Http requests
Navigate to app > java > {package-name} and right click on the folder and go to New > Java Class or Kotlin Class/File, and create the 3 following files
- BitcoinResponse - Data class to parse API response
- BitcoinApiService - Retrofit interface to define API endpoints
- RetrofitInstance - Singleton object to create Retrofit instance

Step 7: Working with Data class for API response
Navigate to the BitcoinResponse file, and add the following code
package org.geeksforgeeks.bitcointracker;
import java.util.Map;
public class BitcoinResponse {
private Map<String, String> rates;
public BitcoinResponse(Map<String, String> rates) {
this.rates = rates;
}
public Map<String, String> getRates() {
return rates;
}
public void setRates(Map<String, String> rates) {
this.rates = rates;
}
}
package org.geeksforgeeks.bitcointracker
// Data class to parse API response
data class BitcoinResponse(
val rates: Map<String, String>
)
Step 8: Working with Retrofit Interface
Navigate to the BitcoinApiService file, and add the following code
package org.geeksforgeeks.bitcointracker;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface BitcoinApiService {
@GET("live")
Call<BitcoinResponse> getBitcoinPrice(
@Query("access_key") String accessKey,
@Query("TARGET") String target,
@Query("symbols") String symbols
);
}
package org.geeksforgeeks.bitcointracker
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
// Retrofit interface to define API endpoints
interface BitcoinApiService {
@GET("live")
fun getBitcoinPrice(
@Query("access_key") accessKey: String,
@Query("TARGET") target: String,
@Query("symbols") symbols: String = "BTC"
): Call<BitcoinResponse>
}
Step 9: Working with Singleton object
Navigate to the RetrofitInstance file, and add the following code
package org.geeksforgeeks.bitcointracker;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitInstance {
private static final String BASE_URL = "https://api.coinlayer.com/";
private static Retrofit retrofit;
public static BitcoinApiService getApi() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit.create(BitcoinApiService.class);
}
}
package org.geeksforgeeks.bitcointracker
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
// Singleton object to create Retrofit instance
object RetrofitInstance {
private const val BASE_URL = "https://api.coinlayer.com/"
val api: BitcoinApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(BitcoinApiService::class.java)
}
}
Step 10: Working with the layout files
The XML codes in activity_main.xml are used to build the structure of the activity as well as its styling part. It contains an ImageView at the very top of the activity to display the logo of the app. Then it contains a TextView to display the bitcoin rate in the center of the activity. At last, we have a Spinner at the bottom of the activity to display the list of currencies from which the user can choose. This is a single activity application.
For the spinner to display the list we also need to create a spinner item's XML layout as well as its item's layout for the adapter. Add the below code in app > res > layout > spinner_item.xml.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".MainActivity">
<TextView
android:id="@+id/priceLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginBottom="32dp"
android:text="Price"
android:textColor="@android:color/holo_orange_light"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/logoImage" />
<ImageView
android:id="@+id/logoImage"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"
android:src="@drawable/bitcoin_img"
app:layout_constraintBottom_toTopOf="@+id/priceLabel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Base Currency"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/currency_spinner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/priceLabel" />
<Spinner
android:id="@+id/currency_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:spinnerMode="dropdown"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:padding="10dip"
android:text="Currency"
android:textColor="@color/black"
android:textSize="30sp"
android:textStyle="bold" />
Design UI (activity_main.xml):

Step 11: Working with the MainActivity file
In the MainActivity file, we create a simple Bitcoin price tracker app. First, we set up a Spinner (dropdown) that allows users to select a currency from a predefined list. When a currency is selected, we make a network request using Retrofit to fetch the latest Bitcoin price for that currency. The network call runs in a background thread using ExecutorService to prevent blocking the main UI thread. Once the data is retrieved, we update the TextView on the main thread to display the Bitcoin price.
Below is the code for the MainActivity file. Comments are added inside the code to understand the code in more detail.
package org.geeksforgeeks.bitcointracker;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import retrofit2.Call;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private final String apiKey = "YOUR_API_KEY"; // Add your API key here
private TextView mPriceTextView;
private final BitcoinApiService apiService = RetrofitInstance.getApi();
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private final List<String> currencyArray = Arrays.asList("AUD", "BRL", "CAD", "CNY", "EUR", "GBP",
"HKD", "JPY", "PLN", "RUB", "SEK", "USD", "ZAR");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize TextView for displaying Bitcoin price
mPriceTextView = findViewById(R.id.priceLabel);
Spinner spinner = findViewById(R.id.currency_spinner);
// Set up the spinner (dropdown) with currency options
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.spinner_item, currencyArray);
adapter.setDropDownViewResource(R.layout.spinner_item);
spinner.setAdapter(adapter);
// Handle currency selection from the spinner
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
String currency = adapterView.getItemAtPosition(position).toString();
fetchBitcoinPrice(currency); // Fetch Bitcoin price for selected currency
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
// Fetch Bitcoin price from the API using a background thread
private void fetchBitcoinPrice(String currency) {
executorService.execute(() -> {
try {
// Make the network request
Call<BitcoinResponse> call = apiService.getBitcoinPrice(apiKey, currency);
Response<BitcoinResponse> response = call.execute();
if (response.isSuccessful() && response.body() != null) {
// Extract price from response
String price = response.body().getRates().get("BTC");
if (price == null) price = "N/A";
// Update UI on the main thread
final String finalPrice = price;
runOnUiThread(() -> mPriceTextView.setText(finalPrice));
} else {
runOnUiThread(() -> mPriceTextView.setText("Error"));
}
} catch (IOException e) {
Log.e("BitcoinTracker", "Error fetching data", e);
runOnUiThread(() -> mPriceTextView.setText("Error"));
}
});
}
}
package org.geeksforgeeks.bitcointracker
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import java.io.IOException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private val apiKey = "YOUR_API_KEY" // add your own api key here
private lateinit var mPriceTextView: TextView
private val apiService: BitcoinApiService by lazy {
RetrofitInstance.api
}
private val executorService: ExecutorService = Executors.newSingleThreadExecutor()
private val currencyArray = listOf("AUD", "BRL", "CAD", "CNY", "EUR", "GBP", "HKD", "JPY", "PLN", "RUB", "SEK", "USD", "ZAR")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
// Initialize TextView for displaying Bitcoin price
mPriceTextView = findViewById(R.id.priceLabel)
val spinner: Spinner = findViewById(R.id.currency_spinner)
// Set up the spinner (dropdown) with currency options
val adapter = ArrayAdapter(this, R.layout.spinner_item, currencyArray)
adapter.setDropDownViewResource(R.layout.spinner_item)
spinner.adapter = adapter
// Handle currency selection from the spinner
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View?, position: Int, id: Long) {
val currency = adapterView.getItemAtPosition(position).toString()
fetchBitcoinPrice(currency) // Fetch Bitcoin price for selected currency
}
override fun onNothingSelected(adapterView: AdapterView<*>) {}
}
}
// Fetch Bitcoin price from the API using a background thread
private fun fetchBitcoinPrice(currency: String) {
executorService.execute {
try {
// Make the network request
val response = apiService.getBitcoinPrice(apiKey, currency).execute()
if (response.isSuccessful) {
// Extract price from response
val price = response.body()?.rates?.get("BTC") ?: "N/A"
// Update UI on the main thread
runOnUiThread { mPriceTextView.text = price }
} else {
runOnUiThread { mPriceTextView.text = "Error" }
}
} catch (e: IOException) {
Log.e("BitcoinTracker", "Error fetching data", e)
runOnUiThread { mPriceTextView.text = "Error" }
}
}
}
}
Important: Make sure to replace the api key with your own api key.
Output:
Note : To access the full android application check this repository: Bitcoin Tracker