How to Create Android Currency Converter Using Apilayer from Scratch

In this episode on how to create android currency converter app using Apilayer from scratch, we are going to explore different options that will help us build a successful android currency converter app.

Android currency converter app is a great productive / utility app that informs mostly travelers and tourist the exchange rate between their local currency and the currency they will use when they traveled.

To fetch the currency rates between different currencies we are going to use Apilayer currency API. Apilayer has both free API and paid API. There are other free currency converter API but there are also limited in the amount of supported currencies.

The currency converter app also includes a travel expense features. This feature gives the users opportunity to estimate and plan their travel within budgeted amount.

If you are excited to learn how an application like this is develop, you can continue reading. Beside Android currency converter app, there are many apps we have created from scratch to help android learners build their own app.

Please note that the complete app source code is not free. you can follow and complete the tutorial by copying code pasted here. But if you need to completed project folder, then go to the end of this page to see more information about payment.

To get more insight on how the app works, we have uploaded a demo app in Google Play. You can download it and check it out. If you have any suggestions or idea on how the app can be improve, we will really appreciate it.

What we will learn from android in building this App

Although this is not a complete list, but we will like to highlight that in the course of creating currency converter app from scratch, we are going to cover / use the following android and third-party APIs.

  1. Network call – Retrofit2
  2. Local storage –  Room database and SharedPreference
  3. Adapter Pattern
  4. LiveData and ViewModel
  5. Compound View
  6. Custom Themes

Currency Converter App Features

  1. Show 4 or less currency rates at once
  2. Supports up to 170 currencies in the world
  3. Switch currencies up and down
  4. Currency graph rate
  5. Currency alert – Notify user when there is a change in currency of interest
  6. Notification
  7. Settings
  8. Travel expenses
  9. Multiple theme support
  10. Share and more

Hand Sketch of the android app

Android Currency Converter App Screenshots

Android Currency Converter Video Demo

Scope of this episode

Before we go down to coding, I have attached the image of the project folder structure. As can be seen in the image, each feature / page in the app is separated by its own folder.

The code sample we will go through here we focus on the core feature of the app which is currency converter.

If you need the complete source code, I will suggest you scroll down to see how to download the source code with its accompanying PDF complete tutorial guide.

1. Create a new android project

  • Open Android Studio
  • Go to file menu
  • Select  new
  • Enter project name
  • Enter activity name
  • Keep other default settings
  • Click on finish button to create a new android project

2. Add Library Dependencies in build.gradle file

For the dependencies, we will use several android third party libraries to make our work much easier and saves time.

The dependency section of build.gradle is well commented. The comments give us an idea of what each or group of libraries do.

Open build.gradle file and paste the content below.

dependencies {
    //support libraries
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
    implementation 'androidx.cardview:cardview:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    //circular image and currency picker
    implementation 'com.github.midorikocak:currency-picker-android:1.1.9'
    implementation 'de.hdodenhof:circleimageview:2.2.0'

    //Preference
    implementation 'com.fxn769:stash:1.3.2'

    //Room persistence data
    implementation "android.arch.persistence.room:rxjava2:1.1.1"
    implementation 'androidx.room:room-common:2.1.0-alpha03'
    implementation 'androidx.room:room-runtime:2.1.0-alpha03'
    annotationProcessor "androidx.room:room-compiler:2.1.0-alpha03"
    implementation 'android.arch.lifecycle:livedata:1.1.1'

    //Network call - Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'
    implementation "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0"

    //logging Networking call
    implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'

    //Reactive
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.4'

    //Work
    implementation "android.arch.work:work-runtime:1.0.0-beta01"
    implementation "android.arch.work:work-firebase:1.0.0-alpha11"

    //fast Adapter
    implementation 'com.mikepenz:fastadapter:3.3.1'

    //Animation Transition
    implementation 'com.github.Binary-Finery:Bungee:master-SNAPSHOT'

    //Graphing
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'

    //Date library
    implementation 'joda-time:joda-time:2.10.1'

    //debug db
    debugImplementation 'com.amitshekhar.android:debug-db:1.0.3'

    //Runtime permission
    implementation 'com.karumi:dexter:5.0.0'

    //View binding
    api "com.jakewharton:butterknife:$butterKnifeVersion"
    annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
}

3. Update strings.xml

Open res folder > strings.xml and add the code below to it.

<resources>
    <string name="app_name">Smart Currency Converter</string>
    <string name="number_of_currencies">Number of Currencies</string>
    <string name="customize_colours">CUSTOMIZE COLORS</string>
    <string name="enable_night_mode">ENABLE NIGHT MODE</string>
    <string name="enable_push_notifications">ENABLE PUSH NOTIFICATIONS</string>
    <string name="invite_friends">INVITE FRIENDS</string>
    <string name="share"> SHARE</string>
    <string name="more_apps">MORE APPS</string>
    <string name="rate">RATE</string>
    <string name="contact_us">CONTACT US</string>
    <string name="search">Search</string>
    <string name="monthly_graph">Monthly Graph</string>
    <string name="select_currency_alert_type">Select Currency Alert Type</string>
    <string name="notify_me_when_my_set_rate_is_greater_or_less_than_the_current_rate">Notify me when my set rate is greater or less than the current rate</string>
    <string name="notify_me_on_a_particular_set_date_and_time_in_the_future">Notify me on a particular set date and time in the future</string>
    <string name="trip_name">Trip name</string>
    <string name="trip_budget">Trip budget</string>
</resources>

4. Update styles.xml

Open res folder > styles.xml and add the code below to it

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="colorText">@color/colorTextSecondary</item>
        <item name="iconOne">@drawable/ic_system_update_blue_700_36dp</item>
        <item name="iconTwo">@drawable/ic_share_blue_700_36dp</item>
    </style>

    <style name="darkTheme" parent="Theme.AppCompat">
        <item name="colorPrimary">#33343B</item>
        <item name="colorPrimaryDark">#252529</item>
        <item name="android:windowBackground">@color/colorTextSecondary</item>
        <item name="colorAccent">@color/colorWhite</item>
        <item name="colorText">#ffffff</item>
        <item name="iconOne">@drawable/ic_system_update_grey_300_36dp</item>
        <item name="iconTwo">@drawable/ic_share_grey_300_36dp</item>
    </style>

</resources>

5. Update colors.xml

Open res folder > colors.xml and add the code below to it.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorGrey">#e1e1e1</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBlack">#000000</color>
    <color name="colorDark">#333333</color>
    <color name="colorLightGrey">#D3D3D3</color>
    <color name="colorTextSecondary">#666666</color>
    <color name="colorDivider">#C0C0C0</color>
    <color name="colorBackground">#6498C2</color>
    <color name="graphBackground">#d69090</color>
    <color name="graphLineColor">#c85656</color>
</resources>

6. Update attrs.xml

Open the res folder > attrs.xml and add the code below to it.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="DarkNightTheme">
        <attr name="primaryTextColor" format="color"/>
        <attr name="colorTextSecondary" format="color"/>
        <attr name="dividerColor" format="color"/>
        <attr name="backgroundCardColor" format="color"/>
        <attr name="colorText" format="color"/>
        <attr name="iconOne" format="integer"/>
        <attr name="iconTwo" format="integer"/>
    </declare-styleable>
</resources>

7. Create Custom Application Class

In the root project directory, right click.

Go to New > Java Class > enter  your class name. I will use CustomApp but feel free to use any name of your choice.

Open the created CustomApp.java file and add the code below to it.

import android.app.Application;

import com.fxn.stash.Stash;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class CustomApp extends Application {

    private static final String TAG = CustomApp.class.getSimpleName();

    private Gson gson;
    private GsonBuilder gsonBuilder;


    @Override
    public void onCreate() {
        super.onCreate();
        Stash.init(this);

        gsonBuilder = new GsonBuilder();
        gson = gsonBuilder.create();
    }

    public Gson getGson() {
        return gson;
    }
}

8. Create the Splash Page

The first page in the app is a splash or intro page which waits for 2 seconds before it loads the main currency page. I used SplashActivity for the default activity page when I created my android project.

Open SplashActivity.java file and add the code below.

public class SplashActivity extends AppCompatActivity {
    
    private static final String TAG = SplashActivity.class.getSimpleName();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        setContentView(R.layout.activity_splash);

        ActionBar actionBar = getSupportActionBar();
        if(null != actionBar){
            actionBar.hide();
        }

        Handler handler = new Handler();
        handler.postDelayed(() -> {
            Intent intent = new Intent(SplashActivity.this, CurrencyActivity.class);
            startActivity(intent);
            Bungee.slideLeft(SplashActivity.this);
            finish();
        }, Constants.SPLASH_TIME);
    }
}

The layout file of the above activity will contain one ImageView and two Textviews. Open the activity_splash.xml file and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/colorBackground"
    tools:context=".SplashActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:orientation="vertical"
        android:gravity="center"
        android:padding="20dp"
        tools:ignore="UseCompoundDrawables">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/currency_logo"
            android:contentDescription="@string/app_name"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Smart Currency Converter"
            android:textColor="@color/colorWhite"
            android:textAllCaps="true"
            android:layout_marginTop="10dp"
            android:textSize="15sp"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            android:layout_marginTop="4dp"
            android:textColor="@color/colorDivider"
            android:text="From Inducesmile.com"/>

    </LinearLayout>

</FrameLayout>

9. Create CurrencyActivity Page

The SplashActivity page will load the CurrencyPage which is the core page of the app.

Create a new package under main project package. I will name it currencypage. Right click on the package, go to New menu > Android > Empty Activity and click ok.

In the open activity dialog box, name your activity CurrencyActivity.java or any name of your choice. Leave other options and click the finish button.

I decided to use LinearLayout for the grid part of the UI. The issue with it is that it contains much code when compared with ConstraitLayout.

Let first create the layout file to get a better understand of what we planned to achieve.

Go to res > layout > activity_currency.xml and add the following code snippet to it.

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".currencypage.CurrencyActivity">

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/wrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimaryDark"
        android:clickable="false"
        android:orientation="vertical">

        <com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView
            android:id="@+id/first_currecncy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView>

        <com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView
            android:id="@+id/second_currecncy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView>

        <com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView
            android:id="@+id/third_currecncy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView>

        <com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView
            android:id="@+id/fourth_currecncy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </com.inducesmile.smartcurrencyconverter.customview.CurrencyBoxView>

    </androidx.appcompat.widget.LinearLayoutCompat>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentTop="true"
            android:layout_above="@+id/bottom_layout"
            android:orientation="vertical">

            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal">

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="1dp"
                    android:layout_marginRight="1dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!--Inner wrapper for buttons-->
                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/seven_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="7"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/four_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="4"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/one_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="1"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/point_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="."
                            android:textSize="30sp" />

                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.appcompat.widget.LinearLayoutCompat>

                <!--vertical divider -->
                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="1dp"
                    android:layout_height="match_parent"
                    android:background="@color/colorDivider" />

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="1dp"
                    android:layout_marginRight="1dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!--Inner wrapper for buttons-->
                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/eight_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="8"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/five_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="5"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />


                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/two_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="2"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/zero_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="0"
                            android:textSize="30sp" />


                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.appcompat.widget.LinearLayoutCompat>

                <!--vertical divider -->
                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="1dp"
                    android:layout_height="match_parent"
                    android:background="@color/colorDivider" />

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="1dp"
                    android:layout_marginRight="1dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!--Inner wrapper for buttons-->
                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/nine_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="9"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />


                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/six_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="6"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/three_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="3"
                            android:textSize="30sp" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="@color/colorDivider" />


                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/del_btn"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_marginBottom="1dp"
                            android:layout_weight="1"
                            android:fontFamily="@font/roboto_light"
                            android:gravity="center"
                            android:text="DEL"
                            android:textSize="30sp" />

                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.appcompat.widget.LinearLayoutCompat>

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!--Inner wrapper for buttons-->
                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:background="#C0C0C0"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:id="@+id/layout_rotate"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:gravity="center"
                            android:orientation="vertical">

                            <androidx.appcompat.widget.AppCompatImageView
                                android:id="@+id/switch_layout"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:contentDescription="@string/app_name"
                                app:srcCompat="@drawable/ic_autorenew_grey_600_48dp" />

                        </androidx.appcompat.widget.LinearLayoutCompat>

                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:id="@+id/layout_number_select"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:gravity="center"
                            android:orientation="vertical">

                            <androidx.appcompat.widget.AppCompatImageView
                                android:id="@+id/switch_menu"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:contentDescription="@string/app_name"
                                app:srcCompat="@drawable/ic_menu_grey_600_48dp" />

                        </androidx.appcompat.widget.LinearLayoutCompat>

                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:id="@+id/layout_graph"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:gravity="center"
                            android:orientation="vertical">

                            <androidx.appcompat.widget.AppCompatImageView
                                android:id="@+id/currency_graph"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:contentDescription="@string/app_name"
                                app:srcCompat="@drawable/ic_show_chart_grey_600_48dp" />

                        </androidx.appcompat.widget.LinearLayoutCompat>

                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:id="@+id/btn_notification"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:gravity="center"
                            android:orientation="vertical">

                            <androidx.appcompat.widget.AppCompatImageView
                                android:id="@+id/currency_notification"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:contentDescription="@string/app_name"
                                app:srcCompat="@drawable/ic_notifications_active_grey_600_48dp" />

                        </androidx.appcompat.widget.LinearLayoutCompat>


                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:id="@+id/btn_more_menu"
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:gravity="center"
                            android:orientation="vertical">

                            <androidx.appcompat.widget.AppCompatImageView
                                android:id="@+id/currency_settings"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:contentDescription="@string/app_name"
                                app:srcCompat="@drawable/ic_more_horiz_grey_600_48dp" />

                        </androidx.appcompat.widget.LinearLayoutCompat>


                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.appcompat.widget.LinearLayoutCompat>

            </androidx.appcompat.widget.LinearLayoutCompat>

        </androidx.appcompat.widget.LinearLayoutCompat>

        <androidx.appcompat.widget.LinearLayoutCompat
            android:id="@+id/bottom_layout"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_alignParentBottom="true"
            android:gravity="center"
            android:background="@color/colorBackground"
            android:orientation="vertical">

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/travel_expenses"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Travel Expenses"
                android:textColor="@color/colorWhite"
                android:drawablePadding="4dp"
                android:textSize="15sp"
                android:fontFamily="@font/roboto_light"
                android:drawableTop="@drawable/ic_local_airport_blue_900_24dp"/>

        </androidx.appcompat.widget.LinearLayoutCompat>

    </RelativeLayout>


</androidx.appcompat.widget.LinearLayoutCompat>

If everything works well for you then you will see a UI similar to the image below.

Now open the CurrencyActivity.java and paste the code snippet below in the class.

public class CurrencyActivity extends AppCompatActivity implements IMenuSwitch, CurrencyBoxView.OnWrapperClickListener{

    private static final String TAG = CurrencyActivity.class.getSimpleName();

    @BindView(R.id.zero_btn)
    AppCompatTextView buttonZero;

    @BindView(R.id.one_btn)
    AppCompatTextView buttonOne;

    @BindView(R.id.two_btn)
    AppCompatTextView buttonTwo;

    @BindView(R.id.three_btn)
    AppCompatTextView buttonThree;

    @BindView(R.id.four_btn)
    AppCompatTextView buttonFour;

    @BindView(R.id.five_btn)
    AppCompatTextView buttonFive;

    @BindView(R.id.six_btn)
    AppCompatTextView buttonSix;

    @BindView(R.id.seven_btn)
    AppCompatTextView buttonSeven;

    @BindView(R.id.eight_btn)
    AppCompatTextView buttonEight;

    @BindView(R.id.nine_btn)
    AppCompatTextView buttonNine;

    @BindView(R.id.point_btn)
    AppCompatTextView buttonDot;

    @BindView(R.id.del_btn)
    AppCompatTextView buttonDel;


    @BindView(R.id.switch_layout)
    AppCompatImageView switchLayout;

    @BindView(R.id.switch_menu)
    AppCompatImageView switchMenu;

    @BindView(R.id.currency_graph)
    AppCompatImageView currencyGraph;

    @BindView(R.id.currency_notification)
    AppCompatImageView currencyNotification;

    @BindView(R.id.currency_settings)
    AppCompatImageView currencySettings;

    @BindView(R.id.travel_expenses)
    AppCompatTextView travelExpenses;


    @BindView(R.id.first_currecncy)
    CurrencyBoxView firstCurrency;

    @BindView(R.id.second_currecncy)
    CurrencyBoxView secondCurrency;

    @BindView(R.id.third_currecncy)
    CurrencyBoxView thirdCurrency;

    @BindView(R.id.fourth_currecncy)
    CurrencyBoxView fourthCurrency;


    private String firstValue = "1";

    private CustomMenuDialog customMenuDialog;

    private CurrencyViewModel currencyViewModel;

    private AppApiHelper appApiHelper;

    private CurrencyViewHelper currencyViewHelper;

    private int indexSelected;

    private Gson gson;

    private StoreHelper storeHelper;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        boolean newNightMode = LocalStore.getIsNightMode();
        setTheme(newNightMode ? R.style.darkTheme : R.style.AppTheme);
        Log.d(TAG, "Status Mode " + newNightMode);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_currency);

        ButterKnife.bind(this);

        ActionBar actionBar = getSupportActionBar();
        if(null != actionBar){
            actionBar.hide();
        }

        Dexter.withActivity(this)
                .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        if(!report.areAllPermissionsGranted()){
                            Toast.makeText(CurrencyActivity.this, "You need to grant all permission to use this app features", Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(List<com.karumi.dexter.listener.PermissionRequest> permissions, PermissionToken token) {

                    }
                })
                .check();

        gson = ((CustomApp)getApplication()).getGson();
        appApiHelper = new AppApiHelper();
        currencyViewModel = new CurrencyViewModel(appApiHelper);
        currencyViewHelper = new CurrencyViewHelper(this);
        storeHelper = new StoreHelper();

        // set initial number of currencies to show if not is set yet
        int currencyShowing = LocalStore.getNumOfCurrenciesDisplay();
        if(currencyShowing < 2){
            //starting app for the first time
            LocalStore.setNumOfCurrenciesDisplay(2);
        }
        initStartCurrencies(currencyShowing);

        customMenuDialog = new CustomMenuDialog(CurrencyActivity.this);
        customMenuDialog.setOnIMenuSwitch(this);

        //attach interface method
        firstCurrency.setOnWrapperClickListener(this);
        secondCurrency.setOnWrapperClickListener(this);
        thirdCurrency.setOnWrapperClickListener(this);
        fourthCurrency.setOnWrapperClickListener(this);

        //detect change in currency
        observeCurrencyValueChange();
    }


    @OnClick(R.id.point_btn)
    public void clickPoint(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.one_btn)
    public void clickOne(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.two_btn)
    public void clickTwo(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.three_btn)
    public void clickThree(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.four_btn)
    public void clickFour(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.five_btn)
    public void clickFive(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.six_btn)
    public void clickSix(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.seven_btn)
    public void clickSeven(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.eight_btn)
    public void clickEight(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.nine_btn)
    public void clickNine(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.zero_btn)
    public void clickZero(View view) {
        changeValueOfFirstCurrency(view);
    }

    @OnClick(R.id.del_btn)
    public void clickDel(View view) {
        deleteLastText(view);
    }


    private void changeValueOfFirstCurrency(View view){
        AppCompatTextView buttonClicked = (AppCompatTextView)view;

        if(firstValue.equals("0")){
            firstValue = "";
        }

        firstValue += buttonClicked.getText().toString();
        firstCurrency.setCurrencyAmount(firstValue);


        if(!firstValue.endsWith(".")){
            makeCurrencyApiLayerCall();
        }
    }


    private void deleteLastText(View view){
        String formattedInput = "";

        if(firstValue.length() > 1){
            formattedInput = firstValue.substring(0, firstValue.length() - 1);
            firstValue = formattedInput;
        }else{
            firstValue = "0";
        }

        firstCurrency.setCurrencyAmount(firstValue);

        makeCurrencyApiLayerCall();
    }


    @OnClick(R.id.switch_layout)
    public void switchCurrencyRowVertically(){
        Toast.makeText(CurrencyActivity.this, "Vertical switch has occurred", Toast.LENGTH_SHORT).show();
    }


    @OnClick(R.id.currency_graph)
    public void showCurrencyGraph(View view){
        saveOpenCurrencyData();
        Intent graphIntent = new Intent(CurrencyActivity.this, CurrencyGraphActivity.class);
        startActivity(graphIntent);
        Bungee.slideLeft(CurrencyActivity.this);
        finish();
    }


    //Action menu button events
    @OnClick(R.id.currency_settings)
    public void onShowSettings(View view){
        Intent settingsIntent = new Intent(CurrencyActivity.this, SettingsActivity.class);
        startActivity(settingsIntent);
        Bungee.slideLeft(CurrencyActivity.this);
        finish();
    }


    @OnClick(R.id.currency_notification)
    public void onCurrencyChangeNotification(View view){
        saveOpenCurrencyData();
        NotificationDialog notificationDialog = new NotificationDialog(CurrencyActivity.this);
        notificationDialog.selectCurrencyAlertType();
    }


    @OnClick(R.id.travel_expenses)
    public void onTravelExpenses(View view){
        saveOpenCurrencyData();
        Intent settingsIntent = new Intent(CurrencyActivity.this, TravelExpensesActivity.class);
        startActivity(settingsIntent);
        Bungee.slideLeft(CurrencyActivity.this);
        finish();
    }


    @OnClick(R.id.switch_menu)
    public void onMenuSwitch(View view){
        customMenuDialog.selectMenuOptions();
    }


    @Override
    public void onSwitchMenuClick(int position) {
        initStartCurrencies(position);
        LocalStore.setNumOfCurrenciesDisplay(position);
    }


    private void openCloseCurrencyBox(CurrencyBoxView currencyBoxView){
        if(!isCurrencyBoxClosed(currencyBoxView)){
            showCurrencyBox(currencyBoxView);
        }
    }


    private void closeCurrencyBox(CurrencyBoxView currencyBoxView){
        if(isCurrencyBoxClosed(currencyBoxView)){
            hideCurrencyBox(currencyBoxView);
        }
    }


    private void showCurrencyBox(CurrencyBoxView currencyBoxView){
        currencyBoxView.setVisibility(View.VISIBLE);
    }


    private void hideCurrencyBox(CurrencyBoxView currencyBoxView){
        currencyBoxView.setVisibility(View.GONE);
    }


    private boolean isCurrencyBoxClosed(CurrencyBoxView currencyBoxView){
        return currencyBoxView.getVisibility() != View.GONE;
    }


    private void initStartCurrencies(int position){
        if(position == 2){
            closeCurrencyBox(thirdCurrency);
            closeCurrencyBox(fourthCurrency);

            int newHeight = (int)CommonUtils.convertDpToPixel(100, CurrencyActivity.this);
            firstCurrency.setNewHieght(newHeight);
            secondCurrency.setNewHieght(newHeight);
        }
        if(position == 3){
            openCloseCurrencyBox(thirdCurrency);
            closeCurrencyBox(fourthCurrency);

            int newHeight = (int)CommonUtils.convertDpToPixel(90, CurrencyActivity.this);
            firstCurrency.setNewHieght(newHeight);
            secondCurrency.setNewHieght(newHeight);
            thirdCurrency.setNewHieght(newHeight);
        }
        if(position == 4){
            openCloseCurrencyBox(thirdCurrency);
            openCloseCurrencyBox(fourthCurrency);

            int newHeight = (int)CommonUtils.convertDpToPixel(80, CurrencyActivity.this);
            firstCurrency.setNewHieght(newHeight);
            secondCurrency.setNewHieght(newHeight);
            thirdCurrency.setNewHieght(newHeight);
            fourthCurrency.setNewHieght(newHeight);
        }
    }


    @Override
    public void onWrapperClicked(CurrencyBoxView view) {
        int clickPosition = 0;
        if(view.equals(firstCurrency)){
            clickPosition = 1;
        }
        if(view.equals(secondCurrency)){
            clickPosition = 2;
        }
        if(view.equals(thirdCurrency)){
            clickPosition = 3;
        }
        if(view.equals(fourthCurrency)){
            clickPosition = 4;
        }

        //save state
        saveState();

        Intent currencyIntent = new Intent(CurrencyActivity.this, ListCurrencyActivity.class);
        currencyIntent.putExtra(Constants.CLICK_POSITION, clickPosition);
        startActivity(currencyIntent);
        Bungee.slideLeft(CurrencyActivity.this);
    }


    //Save current currency states
    private void saveState(){
        List<CurrencyModel> showingMoney = currencyViewHelper.getListOfOpenCurrencies(firstCurrency, secondCurrency, thirdCurrency, fourthCurrency);
        CommonUtils.convertListObjectToString(gson, showingMoney);
    }


    @Override
    protected void onStart() {
        super.onStart();

        Bundle bundle = getIntent().getExtras();
        gson = ((CustomApp)getApplication()).getGson();
        indexSelected = IntentBundle.returnIntValue(getIntent().getExtras(), Constants.CLICK_POSITION);
        String stringOfObject = IntentBundle.returnStringValue(bundle, Constants.OBJECT_STORE);

        if(!stringOfObject.equals("")){

            CurrencyAdapter currencyAdapter = CommonUtils.convertObjectToString(gson, stringOfObject);

            int flag = currencyAdapter.getMoneyFlag();
            String code = currencyAdapter.getMoneyCode();
            String name = currencyAdapter.getMoneyName();
            //float amount = 0

            Log.d(TAG, "Country Code " + code);

            //data from state storage
            String modelString = LocalStore.getStoredState();
            List<CurrencyModel> showingMoney = gson.fromJson(modelString, new TypeToken<List<CurrencyModel>>(){}.getType());

            if(indexSelected == 1){
                //todo not yet implemented
                float storedAmount = showingMoney.get(0).getAmount();
                CurrencyModel replaceModel = new CurrencyModel(flag, name, code, storedAmount);
                Objects.requireNonNull(showingMoney).set(0, replaceModel);
                displayCurrenciesFromStateStore(showingMoney);
                //make api call
                makeCurrencyApiLayerCall();

            }else{
                CurrencyModel replaceModel = new CurrencyModel(flag, name, code, 0);
                Objects.requireNonNull(showingMoney).set(indexSelected - 1, replaceModel);
                currencyViewModel.updateCurrencyRates().setValue(showingMoney);
                //make api call
                singleCurrencyApiCall(showingMoney, code, indexSelected);
            }
        }else{
            if(!LocalStore.getStoredState().equals("")){
                // Load currencies from storage
                List<CurrencyModel> currModels = storeHelper.loadModelsOnAppLoad(gson);
                displayCurrenciesFromStateStore(currModels);

                float storedAmount = currModels.get(0).getAmount();
                firstValue = "";
                firstValue = CommonUtils.removeTailingZero(storedAmount);
                Log.d(TAG, "Current value of first value " + firstValue + " From state " + currModels.get(0).getAmount());
            }else{
                Log.d(TAG, "On start error");
            }
        }
    }


    // Observe currency changes
    private void observeCurrencyValueChange(){
        currencyViewModel.updateCurrencyRates().observe(this, new Observer<List<CurrencyModel>>() {
            @Override
            public void onChanged(List<CurrencyModel> currencyModels) {
                displayCurrenciesFromStateStore(currencyModels);
            }
        });
    }
    
    //display currencies
    private void displayCurrenciesFromStateStore(List<CurrencyModel> currencyModels) {
        int showingCurrencies = LocalStore.getNumOfCurrenciesDisplay();
        if(showingCurrencies == 2){
            displayCurrencyDetails(firstCurrency, currencyModels.get(0));
            displayCurrencyDetails(secondCurrency, currencyModels.get(1));
        }
        if(showingCurrencies == 3){
            displayCurrencyDetails(firstCurrency, currencyModels.get(0));
            displayCurrencyDetails(secondCurrency, currencyModels.get(1));
            displayCurrencyDetails(thirdCurrency, currencyModels.get(2));
        }
        if(showingCurrencies == 4){
            displayCurrencyDetails(firstCurrency, currencyModels.get(0));
            displayCurrencyDetails(secondCurrency, currencyModels.get(1));
            displayCurrencyDetails(thirdCurrency, currencyModels.get(2));
            displayCurrencyDetails(fourthCurrency, currencyModels.get(3));
        }
    }


    //Make single currency rate network work
    private void singleCurrencyApiCall(List<CurrencyModel> models, String destination, int clickIndex){
        String source = getSourceCurrency();
        currencyViewModel.convertCurrencyUsingApiRemote(models, source, destination, clickIndex);
    }


    //Make API call to fetch currency rates
    private void makeCurrencyApiLayerCall(){
        String source = getSourceCurrency();
        String destination = getDestinationCurrency();

        //extract currency view content
        List<CurrencyModel> showingMoney = currencyViewHelper.getListOfOpenCurrencies(firstCurrency, secondCurrency, thirdCurrency, fourthCurrency);

        //Make api layer call
        currencyViewModel.convertCurrencyUsingApiRemote(showingMoney, source, destination, 0);
    }


    private String getSourceCurrency(){
        return firstCurrency.getCountryLanguageCode().getText().toString();
    }

    
    //Return currencies based on the number of open currencies
    private String getDestinationCurrency(){
        int showingCurrencies = LocalStore.getNumOfCurrenciesDisplay();
        String destination = "";
        if(showingCurrencies == 2){
            destination = secondCurrency.getCountryLanguageCode().getText().toString();
        }
        if(showingCurrencies == 3){
            destination = secondCurrency.getCountryLanguageCode().getText().toString() + "," +
            thirdCurrency.getCountryLanguageCode().getText().toString();
        }
        if(showingCurrencies == 4){
            destination = secondCurrency.getCountryLanguageCode().getText().toString() + "," +
            thirdCurrency.getCountryLanguageCode().getText().toString() + "," + fourthCurrency.getCountryLanguageCode().getText().toString();
        }
        return destination;
    }


    //Update compound view 
    private void displayCurrencyDetails(CurrencyBoxView view, CurrencyModel item){
        if(item.getMoneyFlag() != -1){
            view.getCircleImageView().setImageResource(item.getMoneyFlag());
            view.getCircleImageView().setTag(item.getMoneyFlag());
        }
        view.getCountryCurrencyCode().setText(item.getMoneyName());
        view.getCountryLanguageCode().setText(item.getMoneyCode());
        float mRate = item.getAmount();
        view.getCurrencyAmount().setText(CommonUtils.removeTailingZero(mRate));
    }

    @Override
    public void onBackPressed() {
        // save current currencies state
        saveOpenCurrencyData();
        //super.onBackPressed();

        //go to home
        Intent startMain = new Intent(Intent.ACTION_MAIN);
        startMain.addCategory(Intent.CATEGORY_HOME);
        startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(startMain);
        finish();
    }

    //Save open currencies before navigating
    private void saveOpenCurrencyData() {
        List<CurrencyModel> currencies = currencyViewHelper.getListOfOpenCurrencies(firstCurrency, secondCurrency, thirdCurrency, fourthCurrency);
        storeHelper.saveOpenCurrenciesOnAppExist(gson, currencies);
    }
}

10. Create Currency List Activity File and Adapter Class

Create a new activity like we did previously. I will name my activity ListCurrencyActivity. You are free to choose any name.

The activity contains a RecyclerView which is connected to an adapter that links the RecyclerView with the data source.

First open the activity_list_currency.xml and add a RecyclerView to it. Alternatively, you can copy the code below and paste it on the file.

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".listcurrency.ListCurrencyActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/currency_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

    </androidx.recyclerview.widget.RecyclerView>

</androidx.appcompat.widget.LinearLayoutCompat>

Now, we need to add the code for the ListCurrencyActivity class. Instantiate the RecyclerView, attach an adapter and finally load its data.

Open ListCurrencyActivity.java file and add the code snippets below.

//ListCurrencyActivity class


public class ListCurrencyActivity extends AppCompatActivity {

    private static final String TAG = ListCurrencyActivity.class.getSimpleName();

    @BindView(R.id.currency_list)
    RecyclerView recyclerView;

    private Context context = this;

    private FastAdapter<CurrencyAdapter> fastAdapter;

    private ItemAdapter<CurrencyAdapter> itemAdapter;

    public OnSelectCurrency onSelectCurrency;

    private int selectCurrencyIndex;


    public interface OnSelectCurrency{
        void OnCurrencySelected(CurrencyAdapter currencyAdapter);
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //Load theme
        boolean newNightMode = LocalStore.getIsNightMode();
        setTheme(newNightMode ? R.style.darkTheme : R.style.AppTheme);

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_list_currency);
        ButterKnife.bind(this);

        ActionBar supportActionBar = getSupportActionBar();
        if (supportActionBar != null) {
            supportActionBar.setTitle("Search Currency");
            supportActionBar.setDisplayHomeAsUpEnabled(true);
        }

        //select currency index
        selectCurrencyIndex = IntentBundle.returnIntValue(getIntent().getExtras(), Constants.CLICK_POSITION);

        initRecyclerView();

        itemAdapter.getItemFilter().withFilterPredicate(new IItemAdapter.Predicate<CurrencyAdapter>() {
            @Override
            public boolean filter(CurrencyAdapter item, CharSequence constraint) {
                String userInput = String.valueOf(constraint);
                return item.getMoneyCode().toLowerCase().startsWith(userInput);
            }
        });
    }


    public void setOnSelectCurrency(OnSelectCurrency onSelectCurrency) {
        this.onSelectCurrency = onSelectCurrency;
    }


    private void initRecyclerView(){
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ListCurrencyActivity.this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setHasFixedSize(true);
        setUpRecyclerAdapter();
    }


    private void setUpRecyclerAdapter(){
        itemAdapter = new ItemAdapter<>();
        fastAdapter = FastAdapter.with(itemAdapter);
        recyclerView.setAdapter(fastAdapter);

        fastAdapter.withSelectable(true);
        //multiple events mapping (click and select)
        fastAdapter.withEventHook(new ClickEventHook<CurrencyAdapter>() {

            @Nullable
            @Override
            public List<View> onBindMany(RecyclerView.ViewHolder viewHolder) {
                List<View> clickableView = new ArrayList<>();
                AppCompatImageView favoriteIcon = ((CurrencyAdapter.ViewHolder) viewHolder).getFavoriteCurrency();
                AppCompatTextView codename = ((CurrencyAdapter.ViewHolder) viewHolder).getCurrencyName();

                clickableView.add(favoriteIcon);
                clickableView.add(codename);
                return clickableView;
            }

            @Override
            public void onClick(View v, int position, FastAdapter<CurrencyAdapter> fastAdapter, CurrencyAdapter item) {
                if(v instanceof AppCompatImageView){
                    Toast.makeText(ListCurrencyActivity.this, "Start icon has been clicked ", Toast.LENGTH_SHORT).show();
                }

                if(v instanceof AppCompatTextView){
                    //convert item object to string
                    Gson gson = ((CustomApp)getApplication()).getGson();
                    String itemString = CommonUtils.convertObjectToString(gson, item);

                    Intent sendNewCurrencyIntent = new Intent(ListCurrencyActivity.this, CurrencyActivity.class);
                    sendNewCurrencyIntent.putExtra(Constants.OBJECT_STORE, itemString);
                    sendNewCurrencyIntent.putExtra(Constants.CLICK_POSITION, selectCurrencyIndex);
                    startActivity(sendNewCurrencyIntent);
                    Bungee.slideRight(ListCurrencyActivity.this);
                    finish();
                }
            }
        });

        getCurrencyDetailsFromAPI(itemAdapter);
    }


    private void getCurrencyDetailsFromAPI(ItemAdapter<CurrencyAdapter> itemAdapter){
        List<CurrencyAdapter> allCurrencies = new ArrayList<>();
        List<ExtendedCurrency> currencies = ExtendedCurrency.getAllCurrencies();
        for (ExtendedCurrency currency : currencies){
            Log.d(TAG, "Currency Name " + currency.getName() + " Currency Code " + currency.getCode());
            allCurrencies.add(new CurrencyAdapter(currency.getFlag(), currency.getName(), currency.getCode(), false));
        }
        itemAdapter.add(allCurrencies);
    }


    @Override
    public void onBackPressed() {
        //super.onBackPressed();
        Intent currencyIntent = new Intent(ListCurrencyActivity.this, CurrencyActivity.class);
        startActivity(currencyIntent);
        Bungee.slideRight(ListCurrencyActivity.this);
        finish();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.search_menu_layout, menu);
        MenuItem searchItem = menu.findItem(R.id.search);
        SearchView searchView = (SearchView)searchItem.getActionView();

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                Log.d(TAG, "Submit text : " + query + " Adapter Counter " + itemAdapter.getAdapterItemCount());
                itemAdapter.filter(query);
                Log.d(TAG, "Adapter Counter " + itemAdapter.getAdapterItemCount());
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                Log.d(TAG, "New text : " + newText);
                itemAdapter.filter(newText);
                return true;
            }
        });
        return super.onCreateOptionsMenu(menu);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id){
            case android.R.id.home:
                onBackPressed();
                finish();
                break;
            case R.id.search:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

}

11. Create CurrencyAdapter Class

Create a new java file and name it CurrencyAdapter.java. The class will contain a ViewHolder, setter and getter for its data object.

Open the class and add the code below to it.

public class CurrencyAdapter extends AbstractItem<CurrencyAdapter, CurrencyAdapter.ViewHolder>{

    private static final String TAG = CurrencyAdapter.class.getSimpleName();

    private static final int CURRENCY_LAYOUT_ID = 202;

    private int moneyFlag;

    private String moneyName;

    private String moneyCodes;

    private boolean isFavourite;


    public CurrencyAdapter(int moneyFlag, String moneyName, String moneyCode, boolean isFavourite) {
        this.moneyFlag = moneyFlag;
        this.moneyName = moneyName;
        this.moneyCodes = moneyCode;
        this.isFavourite = isFavourite;
    }

    public int getMoneyFlag() {
        return moneyFlag;
    }

    public String getMoneyName() {
        return moneyName;
    }

    public String getMoneyCode() {
        return moneyCodes;
    }

    @NonNull
    @Override
    public ViewHolder getViewHolder(View v) {
        return new ViewHolder(v);
    }

    @Override
    public int getType() {
        return CURRENCY_LAYOUT_ID;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.currency_item_layout;
    }

    public static class ViewHolder extends FastAdapter.ViewHolder<CurrencyAdapter>{

        @BindView(R.id.currency_favorite)
        AppCompatImageView favoriteCurrency;

        @BindView(R.id.country_flag)
        CircleImageView currencyFlag;

        @BindView(R.id.currency_code)
        AppCompatTextView currencyCode;

        @BindView(R.id.currency_name)
        AppCompatTextView currencyName;


        public ViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        @Override
        public void bindView(CurrencyAdapter item, List<Object> payloads) {
            int flag = item.getMoneyFlag();
            if(flag > -1){
                currencyFlag.setImageResource(flag);
                currencyFlag.setTag(flag);
            }
            currencyCode.setText(item.getMoneyCode());
            currencyName.setText(item.getMoneyName());

            boolean inFavoriteList = item.isFavourite;
            if(inFavoriteList){
                favoriteCurrency.setImageResource(R.drawable.ic_star_yellow_700_24dp);
            }else{
                favoriteCurrency.setImageResource(R.drawable.ic_star_border_yellow_700_24dp);
            }
        }

        @Override
        public void unbindView(CurrencyAdapter item) {
            currencyCode.setText(null);
            currencyName.setText(null);
        }

        public AppCompatImageView getFavoriteCurrency() {
            return favoriteCurrency;
        }

        public AppCompatTextView getCurrencyCode() {
            return currencyCode;
        }

        public AppCompatTextView getCurrencyName() {
            return currencyName;
        }
    }
}

12. Create a layout for the adapter list item

Go to res folder > layout folder, right click and select layout file. In the open dialog, name the layout currency_item_layout. Open the layout file and add the code snippet below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/first_event"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:padding="12dp">

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/country_flag"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_margin="2dp"
            android:contentDescription="@string/app_name"
            android:src="@drawable/usaflag" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/currency_code"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginStart="20dp"
            android:gravity="center"
            android:text="USD"
            android:textColor="?attr/colorText"
            android:textSize="22sp"
            android:textStyle="bold" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/currency_name"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="12dp"
            android:layout_marginTop="4dp"
            android:gravity="center"
            android:text="US Dollar"
            android:textColor="@color/colorDivider"
            android:textSize="13sp" />

    </androidx.appcompat.widget.LinearLayoutCompat>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:gravity="center|end"
        android:paddingEnd="12dp"
        android:layout_weight="1">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/currency_favorite"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="6dp"
            android:padding="8dp"
            android:src="@drawable/ic_star_border_yellow_700_24dp"
            tools:ignore="RtlHardcoded" />

    </androidx.appcompat.widget.LinearLayoutCompat>

</androidx.appcompat.widget.LinearLayoutCompat>

13. Register and get a Currency API Key

Here we need to register and obtain our currency API key from Apilayer website. In the home page, click the currency API link to navigate to this page below.

Click on the SignUp free button

Enter your signup details and submit.

Copy your generated API key and put it in a save place.

Create a new Java Class

Create a new java file and name it Constants.java. This class will contain all our constant variables and keys.

Open the file and add the code below to it.

public class Constants {


    private Constants() {
    }

    public static final int SPLASH_TIME = 2000;

    public static final String DISPLAY_CURRENCY_COUNTER = "currency_counter";
    public static final String NIGHT_MODE_STATUS = "night_mode_status";
    public static final String OBJECT_STORE = "object_store";
    public static final String CLICK_POSITION = "click_position";
    public static final String BASE_URL = "https://apilayer.net/";
    public static final String STORED_STATE = "stored_state";
    public static final String SPLASH = "splash";
    public static final String EXTRA_ID = "id";
    public static final String CURRENT_RATE = "current_rate";
    public static final String TARGET_RATE = "target_rate";
}

 

What We Have Now

Like I said from the beginner, we will only cover the core feature of the currency converter app and the code above has achieved that. If you want to download the complete source code see the section below.

 How to download the complete source code

You can follow this tutorial and complete the tutorial with the code snippets provided in the tutorial.

The source code is not free to download because we spent a lot of time to create these apps from scratch and your little support will help us to even create more apps from scratch.

Buy

Source Code Customization

If you like the source code and will also like to customize its look and feel or add and remove some features, kindly contact us using the comment section below or through our contact page.

Please note that we charge $20 per hour for customization.

Summary

We have walk through the core feature of android currency converter and I guess you have the better insight on how to continue to improve your source code.

I will suggest you buy the source code to learn how other features were implemented.

If you have questions and suggestions, kindly use the comment box below to get in touch

I look forward in seeing you in our next build from scratch episode.

 

Add a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.