Skip to content
Advertisement

Get EditText input values and display some calculation result in an TextView

I have made a very basic weighted average calculator as Android Application (in Java) and it worked fine.

The user just inputs 3 values a, b, c in three EditTexts and it calculates formula:

d = 0.25 * a + 0.25 * b + 0.5 * c;

Result of this mathematical equation is displayed in a TextView, all of this in the MainActivity at the press of a button.

But after creating a new project for better UI (used Android Studio template Navigation Drawer Activity) I realized that my code is not working.

How could i modify that calculator to get input in my fragment (named CalculatorWeightedFragment) to make calculations and display the result in a TextView in the same fragment when my button is pressed?

At this point all I’m getting is the display of something static and no action assigned to the button.

The code is below:

CalculatorWeightedFragment.java

public class CalculatorWeightedFragment extends Fragment {

    private CalculatorWeightedViewModel calculatorWeightedViewModel;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        calculatorWeightedViewModel =
                ViewModelProviders.of(this).get(calculatorWeightedViewModel.class);
        View root = inflater.inflate(R.layout.fragment_calculator_w, container, false);

        final TextView textView = root.findViewById(R.id.id_result);  // result d stored in id_result


        calculatorWeightedViewModel.takeText().observe(getViewLifecycleOwner(),
                new Observer<String>() {
                    @Override
                    public void onChanged(@Nullable String str) {
                        textView.setText(str);
                    }
                });

        return root;
    }
}

CalculatorWeightedViewModel.java

public class CalculatorWeightedViewModel extends ViewModel {

    private MutableLiveData<String> testString;

    public CalculatorWeightedViewModel() {
        testString = new MutableLiveData<>();
        testString.setValue("" + 0.5);
    }

    public LiveData<String> takeText() {
        return testString;
    }
}

Advertisement

Answer

Base on your xml layout content:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/id_a"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/id_b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/id_c"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/id_buton_rata"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="calculateFunction" />

    <TextView
        android:id="@+id/id_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Example #1 (without LiveData and ViewModel)

I create some new simple fragment (as example)

public class CalculatorWeightedFragment extends Fragment {

    private Button button;
    private EditText editTextA;
    private EditText editTextB;
    private EditText editTextC;
    private TextView textViewD;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_calculator_w, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        button = view.findViewById(R.id.id_buton_rata);
        editTextA = view.findViewById(R.id.id_a);
        editTextB = view.findViewById(R.id.id_b);
        editTextC = view.findViewById(R.id.id_c);
        textViewD = view.findViewById(R.id.id_result);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                double result = calculateResult();
                String output = String.format("Result:  %s", result);
                textViewD.setText(output);
            }
        });
    }

    private double calculateResult() {
        try {
            int a = Integer.parseInt(editTextA.getText().toString());
            int b = Integer.parseInt(editTextB.getText().toString());
            int c = Integer.parseInt(editTextC.getText().toString());

            // Result
            return 0.25 * a + 0.25 * b + 0.5 * c;
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return 0;
        }
    }
}

Example #2 (with LiveData and ViewModel)

When you are using LiveData and ViewModel, you no need button in your Fragment. You can observe all of the changes.

Activity where you are creating this fragment. To have ViewModel in Fragment, you can use dependency injection (e.g. using Dagger library) or get it from ViewModelProviders (or AndroidViewModelFactory).

Here, to make example as simple as possible, I’m passing it via constructor.

Activity

public class MainActivity extends AppCompatActivity {

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

        CalculatorWeightedViewModel vm = new CalculatorWeightedViewModel();

        CalculatorWeightedFragment fragment = new CalculatorWeightedFragment(vm);

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.add(R.id.frame_layout, fragment);
        transaction.commit();
    }
}

ViewModel

You can store you values (a, b, c) as fieldsfor different purpose. Here, I’m recalculating result live, without any extra fiels. To make it as simple as possible.

package com.example.stack_android;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class CalculatorWeightedViewModel extends ViewModel {

    private MutableLiveData<String> testString = new MutableLiveData<>();

    public LiveData<String> takeText() {
        return testString;
    }

    void updateValues(double a, double b, double c) {
        double result = recalculate(a, b, c);
        String value = "Result: " + result;
        testString.postValue(value);
    }

    void showError() {
        testString.postValue("Wrong Value");
    }

    private double recalculate(double a, double b, double c) {
        return 0.25 * a + 0.25 * b + 0.5 * c;
    }
}

Fragment:

Additionaly you can create separate listeners (for each of the fields). Here, I’m using one (named TextWatcher listener) for all of the fields.

public class CalculatorWeightedFragment extends Fragment {

    private CalculatorWeightedViewModel viewModel;

    private EditText editTextA;
    private EditText editTextB;
    private EditText editTextC;
    private TextView textViewD;

    public CalculatorWeightedFragment(CalculatorWeightedViewModel viewModel) {
        this.viewModel = viewModel;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_calculator_w, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        editTextA = view.findViewById(R.id.id_a);
        editTextB = view.findViewById(R.id.id_b);
        editTextC = view.findViewById(R.id.id_c);
        textViewD = view.findViewById(R.id.id_result);

        TextWatcher listener = new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                textChanged();
            }

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

            @Override
            public void afterTextChanged(Editable s) {
                // Not used
            }
        };

        editTextA.addTextChangedListener(listener);
        editTextB.addTextChangedListener(listener);
        editTextC.addTextChangedListener(listener);

        viewModel.takeText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String newValue) {
                textViewD.setText(newValue);
            }
        });
    }

    private void textChanged() {
        try {
            int a = Integer.parseInt(editTextA.getText().toString());
            int b = Integer.parseInt(editTextB.getText().toString());
            int c = Integer.parseInt(editTextC.getText().toString());

            viewModel.updateValues(a, b, c);
        } catch (NumberFormatException e) {
            viewModel.showError();
            e.printStackTrace();
        }
    }
}

It should works like there:

Demo

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement