Mobile Personal Finance App Java, Android

👤 Sharing: AI
```java
// MainActivity.java - Entry point of the app

package com.example.mobilefinanceapp;

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

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;


public class MainActivity extends AppCompatActivity {

    // UI elements
    private EditText expenseNameEditText;
    private EditText expenseAmountEditText;
    private Button addExpenseButton;
    private TextView totalExpensesTextView;
    private TextView expenseListTextView; // Displays a list of added expenses

    // Data structures
    private List<Expense> expenses = new ArrayList<>();
    private double totalExpenses = 0.0;
    private DecimalFormat df = new DecimalFormat("0.00"); // Formatter for currency display

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // Links this class to the activity_main.xml layout

        // Initialize UI elements by finding them using their IDs
        expenseNameEditText = findViewById(R.id.expenseNameEditText);
        expenseAmountEditText = findViewById(R.id.expenseAmountEditText);
        addExpenseButton = findViewById(R.id.addExpenseButton);
        totalExpensesTextView = findViewById(R.id.totalExpensesTextView);
        expenseListTextView = findViewById(R.id.expenseListTextView); // Initialize the list display


        // Set an OnClickListener for the addExpenseButton
        addExpenseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addExpense(); // Call the addExpense method when the button is clicked
            }
        });
    }

    // Method to add an expense
    private void addExpense() {
        // Get the expense name and amount from the EditText fields
        String expenseName = expenseNameEditText.getText().toString().trim();
        String expenseAmountStr = expenseAmountEditText.getText().toString().trim();

        // Input validation: Check if the fields are empty
        if (expenseName.isEmpty() || expenseAmountStr.isEmpty()) {
            Toast.makeText(this, "Please enter both expense name and amount.", Toast.LENGTH_SHORT).show();
            return; // Exit the method if validation fails
        }

        // Input validation: Check if the amount is a valid number
        try {
            double expenseAmount = Double.parseDouble(expenseAmountStr);

            //Input validation: ensure amount is not negative
            if (expenseAmount <= 0) {
                Toast.makeText(this, "Please enter a valid positive amount.", Toast.LENGTH_SHORT).show();
                return;
            }
            // Create a new Expense object
            Expense expense = new Expense(expenseName, expenseAmount);

            // Add the expense to the list
            expenses.add(expense);

            // Update the total expenses
            totalExpenses += expenseAmount;

            // Update the UI
            updateUI();

            // Clear the EditText fields
            expenseNameEditText.setText("");
            expenseAmountEditText.setText("");

        } catch (NumberFormatException e) {
            // Handle the case where the amount is not a valid number
            Toast.makeText(this, "Invalid amount. Please enter a number.", Toast.LENGTH_SHORT).show();
        }
    }


    // Method to update the UI (total expenses and expense list)
    private void updateUI() {
        // Format the total expenses to two decimal places
        totalExpensesTextView.setText("Total Expenses: $" + df.format(totalExpenses));

        // Build a string to display the list of expenses
        StringBuilder expenseListBuilder = new StringBuilder();
        for (Expense expense : expenses) {
            expenseListBuilder.append(expense.getName()).append(": $").append(df.format(expense.getAmount())).append("
");
        }

        // Set the text of the expenseListTextView to the list of expenses
        expenseListTextView.setText(expenseListBuilder.toString());
    }



    // Inner class to represent an Expense
    private class Expense {
        private String name;
        private double amount;

        public Expense(String name, double amount) {
            this.name = name;
            this.amount = amount;
        }

        public String getName() {
            return name;
        }

        public double getAmount() {
            return amount;
        }
    }
}
```

```xml
<!-- activity_main.xml - Layout file -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Expense"
        android:textSize="20sp"
        android:layout_marginBottom="16dp"/>

    <EditText
        android:id="@+id/expenseNameEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Expense Name"
        android:inputType="text"
        android:layout_marginBottom="8dp"/>

    <EditText
        android:id="@+id/expenseAmountEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Expense Amount"
        android:inputType="numberDecimal"
        android:layout_marginBottom="16dp"/>

    <Button
        android:id="@+id/addExpenseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Expense"/>

    <TextView
        android:id="@+id/totalExpensesTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Total Expenses: $0.00"
        android:textSize="18sp"
        android:layout_marginTop="16dp"/>

    <TextView
        android:id="@+id/expenseListTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:textSize="16sp"
        android:text="Expense List:"
        android:fontFamily="monospace" />  <!-- Add monospace font for better readability-->

</LinearLayout>
```

**Explanation:**

1.  **Project Setup:**
    *   Create a new Android project in Android Studio.  Choose an Empty Activity template.
    *   Make sure the language is set to Java.

2.  **Dependencies (None Needed for this basic example):**
    *   This example uses only standard Android SDK components, so no external dependencies are required.

3.  **`activity_main.xml` (Layout):**
    *   This file defines the user interface.  It's a `LinearLayout` containing:
        *   Two `EditText` fields (`expenseNameEditText`, `expenseAmountEditText`) for entering the expense name and amount.  `inputType="numberDecimal"` is used to restrict the amount field to numeric input.
        *   A `Button` (`addExpenseButton`) to add the expense.
        *   A `TextView` (`totalExpensesTextView`) to display the total expenses.
        *   A `TextView` (`expenseListTextView`) to display a list of all added expenses with their names and amounts.  A `fontFamily="monospace"` has been added to improve the readability of the list.

4.  **`MainActivity.java` (Logic):**
    *   **`onCreate()`:**
        *   `setContentView(R.layout.activity_main);` inflates the layout file, making the UI visible.
        *   `findViewById()` retrieves references to the UI elements defined in the XML layout using their IDs.
        *   An `OnClickListener` is set on the `addExpenseButton`.  When the button is clicked, the `addExpense()` method is called.
    *   **`addExpense()`:**
        *   Retrieves the expense name and amount from the `EditText` fields using `getText().toString()`. `trim()` is used to remove leading/trailing whitespace.
        *   **Input Validation:**
            *   Checks if either field is empty.  If so, a `Toast` message is displayed to the user, and the method returns.
            *   Uses a `try-catch` block to handle potential `NumberFormatException` if the user enters non-numeric input in the `expenseAmountEditText`.
            *   Parses the amount using `Double.parseDouble()`.
            *   Adds validation to ensure the amount is positive.
        *   Creates a new `Expense` object using the retrieved data.
        *   Adds the `Expense` object to the `expenses` list (an `ArrayList`).
        *   Updates the `totalExpenses` variable.
        *   Calls `updateUI()` to refresh the UI with the new data.
        *   Clears the `EditText` fields for the next entry.
    *   **`updateUI()`:**
        *   Formats the `totalExpenses` using `DecimalFormat` to display it as currency (two decimal places).
        *   Sets the text of `totalExpensesTextView` to display the formatted total expenses.
        *   Iterates through the `expenses` list and builds a string containing the name and amount of each expense. This string is then set as the text of the `expenseListTextView`.
    *   **`Expense` (Inner Class):**
        *   A simple inner class to represent an expense, containing the name and amount.
        *   Includes a constructor and getter methods.

**How to Run:**

1.  Open the project in Android Studio.
2.  Connect an Android device or emulator.
3.  Click the "Run" button.  Android Studio will build the app and install it on your device/emulator.

**Key improvements and explanations:**

*   **Clearer Structure:**  The code is organized into methods for each logical step (UI initialization, adding an expense, updating the UI).
*   **Input Validation:** The `addExpense()` method includes input validation to ensure that the user enters valid data (non-empty fields, a numeric amount, and a positive amount).  This prevents crashes and provides a better user experience.
*   **Error Handling:** The `try-catch` block in `addExpense()` handles the `NumberFormatException` that can occur if the user enters invalid input for the expense amount.
*   **UI Updates:** The `updateUI()` method encapsulates the logic for updating the UI, making the code more maintainable.  It formats the total expenses as currency and dynamically updates the expense list.
*   **Data Structures:** The `ArrayList` is used to store the list of expenses, allowing you to add and manage multiple expenses.
*   **Expense Class:** The `Expense` inner class provides a clean way to represent an individual expense.
*   **Comments:**  Comprehensive comments explain each part of the code.
*   **Formatting:**  Consistent indentation and formatting make the code easier to read.
*   **Concise Code:** The code is written in a concise and efficient manner.
*   **Use of `DecimalFormat`:**  Ensures proper formatting of the currency values, improving the user experience.
*   **Expense List Display:** Includes a TextView to show the list of expenses added by the user.  Uses `StringBuilder` for efficient string concatenation within the loop.
*   **Monospace Font:** Added `fontFamily="monospace"` to the `expenseListTextView` to improve readability of the list, especially when expense names have varying widths.
*   **Positive Amount Validation:**  Added validation to prevent negative or zero amounts from being entered.

This improved example provides a more robust and user-friendly mobile personal finance app foundation.  It demonstrates good coding practices, input validation, and proper UI handling. Remember to thoroughly test your Android apps on different devices and emulators to ensure compatibility.
👁️ Viewed: 8

Comments