0

I am building out a Unit Conversion app. I need to have one inputs and 2 spinners. The spinners regulate what the current unit is, and what the new unit will be. Below is my code. I am confused on how to use if statements to compare the two. I have been trying to use .equals("lb"), but it just returns false for some reason. Let me know where I might be going wrong.

Main Code:

package com.stproductions.commonconverter;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

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

        //Convert From Box
        setContentView(R.layout.activity_main);
        Spinner spinner1 = findViewById(R.id.spinner1);
        ArrayAdapter<CharSequence>adapter1 = ArrayAdapter.createFromResource(this, R.array.fromchoices, android.R.layout.simple_spinner_item);
        adapter1.setDropDownViewResource(android.R.layout.simple_spinner_item);
        spinner1.setAdapter(adapter1);
        spinner1.setOnItemSelectedListener(this);

        //Convert To Box
        Spinner spinner2 = findViewById(R.id.spinner2);
        ArrayAdapter<CharSequence>adapter = ArrayAdapter.createFromResource(this, R.array.choices, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
        spinner2.setAdapter(adapter);
        spinner2.setOnItemSelectedListener(this);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        String text = parent.getItemAtPosition(position).toString();
        String text2 = parent.getItemAtPosition(position).toString();
//        View text = parent.findViewById(R.id.spinner1);
//        View text2 = parent.findViewById(R.id.spinner2);
//        Spinner spinner1 = (Spinner) findViewById(R.id.spinner1);
//        Spinner spinner2 = (Spinner) findViewById(R.id.spinner2);

        if(text.equals("lb") && text2.equals("oz")){
            Toast.makeText(this,"hello", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
}

String.XML:

<resources>
    <string name="app_name">Common Converter</string>

        <string-array name="choices">
            <item>lb</item>
            <item>oz</item>
            <item>g</item>
            <item>kg</item>
            <item>ton</item>
            <item>mg</item>
        </string-array>

    <string-array name="fromchoices">
        <item>lb</item>
        <item>oz</item>
        <item>g</item>
        <item>kg</item>
        <item>ton</item>
        <item>mg</item>
    </string-array>

</resources>

Activity_Main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner2"
        android:layout_width="97dp"
        android:layout_height="59dp"
        android:background="#E6E6E6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.595" />

    <Spinner
        android:id="@+id/spinner1"
        android:layout_width="97dp"
        android:layout_height="59dp"
        android:background="#E6E6E6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.309" />


</androidx.constraintlayout.widget.ConstraintLayout>

I now get the following in my logcat:

2021-01-06 14:48:00.985 18954-18954/com.stproductions.commonconverter E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.stproductions.commonconverter, PID: 18954
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.view.View.toString()' on a null object reference
    at com.stproductions.commonconverter.MainActivity.onItemSelected(MainActivity.java:39)
    at android.widget.AdapterView.fireOnSelected(AdapterView.java:957)
    at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:946)
    at android.widget.AdapterView.access$300(AdapterView.java:55)
    at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:910)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Zain
  • 37,492
  • 7
  • 60
  • 84
Seth T
  • 68
  • 1
  • 7

2 Answers2

1

EDIT: Firstly, as I said in the comments below this answer, your onItemSelected will be called once you select a value from Spinner1 and again when you select a value from Spinner2. Each time, text and text2 will be the same values, so comparing them there to different values won't ever be true. You need another approach.

To do this, instead of using .setOnItemSelectedListener() you can do this without that. I added Button to your layout like this:

<Button
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:text="Click"
        android:id="@+id/button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.309"/>

After that in your MainActivity.class I deleted both spinner1.setOnItemSelectedListener(this) and spinner2.setOnItemSelectedListener(this) and added btn.setOnClickListener() like this:

Button btn = findViewById(R.id.button);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (spinner1.getSelectedItem() != null && spinner2.getSelectedItem() != null) {
                    String first_option = spinner1.getSelectedItem().toString();
                    String second_option = spinner2.getSelectedItem().toString();

                    if (first_option.contentEquals(second_option)) {
                        Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(MainActivity.this, "sad face", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

So now you don't even need your listeners. There is a check if the spinner is equaled to null if it is you should handle that by informing the user that he needs to select any value. If your value is selected as first by default you don't need to do that. Now you can create switch cases inside this onClick method and show your output as you wish.

Anyway, my recommendation for using string.contentEquals() still stands.

This is my final code:

MainActivity.class

public class MainActivity extends AppCompatActivity {

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

        //Convert From Box
        Spinner spinner1 = findViewById(R.id.spinner1);
        ArrayAdapter<CharSequence>adapter1 = ArrayAdapter.createFromResource(this, R.array.fromchoices, android.R.layout.simple_spinner_item);
        adapter1.setDropDownViewResource(android.R.layout.simple_spinner_item);
        spinner1.setAdapter(adapter1);

        //Convert To Box
        Spinner spinner2 = findViewById(R.id.spinner2);
        ArrayAdapter<CharSequence>adapter = ArrayAdapter.createFromResource(this, R.array.choices, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
        spinner2.setAdapter(adapter);

        Button btn = findViewById(R.id.button);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (spinner1.getSelectedItem() != null && spinner2.getSelectedItem() != null) {
                    String first_option = spinner1.getSelectedItem().toString();
                    String second_option = spinner2.getSelectedItem().toString();

                    if (first_option.contentEquals(second_option)) {
                        Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(MainActivity.this, "sad face", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }
}

And activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner2"
        android:layout_width="97dp"
        android:layout_height="59dp"
        android:background="#E6E6E6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.595" />

    <Spinner
        android:id="@+id/spinner1"
        android:layout_width="97dp"
        android:layout_height="59dp"
        android:background="#E6E6E6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.309" />

    <Button
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:text="Click"
        android:id="@+id/button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.831"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.309"/>


</androidx.constraintlayout.widget.ConstraintLayout>

You should use string.contentEquals() instead of string.equals(). The reason why is that string.equals() compares the String's contents but also it checks if the other object is also an instance of a String. String.contentEquals() only compares the contents of the objects. So it can be CharSequence or anything similar, String, StringBuilder, etc.

Also you have one extra setContentView() in onCreate

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

        //Convert From Box
        setContentView(R.layout.activity_main); <--- DELETE THIS LINE
        Spinner spinner1 = findViewById(R.id.spinner1);

Source:

String#equals()

String#contentEquals()

SlothCoding
  • 1,546
  • 7
  • 14
  • That still doesn't work. I have updated the question at the bottom to show my logcat readouts. I appreciate you helping out here! – Seth T Jan 06 '21 at 22:59
  • There is another problem. When you click on the item in your spinner1 the onItemSelected will be called. In there you are trying to get text1 and text2, which would both be the same because you are taking them from the same parent, in this case spinner1. So when you check if text one is equal to "lb" and text2 equal to "oz" this will never be true, since they are both the same. – SlothCoding Jan 06 '21 at 23:02
  • For the last error, you got, it's a null pointer. You are trying to call .toString on a null value. So your spinner doesn't have a selected option, so it's probably null. I'll try to edit my answer and get this fixed, I'll tag you here when I finish. – SlothCoding Jan 06 '21 at 23:03
  • @SethT there, I edited my answer and now you don't even need listeners. You can do it without them with spinner.getSelectedItem().toString(). Just now create your switch cases and show your result. – SlothCoding Jan 06 '21 at 23:20
  • Answered it perfectly. I really appreciate what you did. I see where I went wrong, and I guess I deserved that after trying to follow Youtube videos. I don't know to much code, so this was dead useful. Thanks! – Seth T Jan 08 '21 at 01:12
  • @SethT I am glad I could help. Happy coding! – SlothCoding Jan 08 '21 at 19:07
0

Point 1: Actually you are using the same AdapterView.OnItemSelectedListener for both Spinner & Spinner2.. So the same onItemSelected() callback will be triggered when you select value of either of both spinners.

Point 2: The second point text and text2 inside onItemSelected() have the same value .. I guess you though that text will point to Spinner1 selected item, and text2 will point to Spinner2 selected item; and that is wrong as of point 1.

So to solve this: you can either use a different listener/callback for the spinners, or use the same listener/callback but do some logic to differentiate which spinner triggers the onItemSelected() callback.

Here I am using the id attribute to know which spinner triggers onItemSelected().

I made both spinners as global fields to facilitate accessing them. And put a Toast to show the spinners' values for any change of any of them.

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

    private static final String TAG = "LOG_TAG";
    private Spinner mSpinner2;
    private Spinner mSpinner1;

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

        //Convert From Box
        setContentView(R.layout.activity_main);
        mSpinner1 = findViewById(R.id.spinner1);
        ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(this, R.array.fromchoices, android.R.layout.simple_spinner_item);
        adapter1.setDropDownViewResource(android.R.layout.simple_spinner_item);
        mSpinner1.setAdapter(adapter1);
        mSpinner1.setOnItemSelectedListener(this);

        //Convert To Box
        mSpinner2 = findViewById(R.id.spinner2);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.choices, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
        mSpinner2.setAdapter(adapter);
        mSpinner2.setOnItemSelectedListener(this);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        String text = "", text2 = "";
        if (parent.getId() == R.id.spinner1) {
            Log.d(TAG, "onItemSelected: spinner 1");
            text = parent.getItemAtPosition(position).toString();
            text2 = mSpinner2.getSelectedItem().toString();
        } else if (parent.getId() == R.id.spinner2) {
            Log.d(TAG, "onItemSelected: spinner 1");
            text2 = parent.getItemAtPosition(position).toString();
            text = mSpinner1.getSelectedItem().toString();
        }
        Toast.makeText(this, "Spinner1: " + text + " Spinner2: " + text2, Toast.LENGTH_SHORT).show();


//        View text = parent.findViewById(R.id.spinner1);
//        View text2 = parent.findViewById(R.id.spinner2);
//        Spinner spinner1 = (Spinner) findViewById(R.id.spinner1);
//        Spinner spinner2 = (Spinner) findViewById(R.id.spinner2);

        if (text.equals("lb") && text2.equals("oz")) {
            Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
}
Zain
  • 37,492
  • 7
  • 60
  • 84
  • spinner2.getSelectedItem().toString() inside the if statement can produce NullPointerException? Am I wrong? Maybe not in this case but in general with other adapters or when there is no default value selected, then it's just an empty null value. – SlothCoding Jan 07 '21 at 00:23
  • @SlothCoding thanks .. you're right if there is no data in it .. but we actually know that there is some data .. [as long as the spinner has some data .. there must be selected value](https://stackoverflow.com/questions/4726490/how-to-set-spinner-default-value-to-null) – Zain Jan 07 '21 at 00:27
  • Oh okay, actually didn't know that for Spinner. Thanks! – SlothCoding Jan 07 '21 at 00:35