Search code examples
javaandroidxmlnullpointerexceptionnullable

NullPointerException in a fragment problem


For the last few hours I've been trying to find the answer to my question, and after trying out different things, I was unable to fix my problem.

What I want is to use an Edittext and a button that does something with that edittext. Here's my code in fragment_main.xml:

<android.support.design.widget.TextInputLayout
    android:id="@+id/text_input_email"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:errorEnabled="true">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/email_input"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:hint="Email"
        android:inputType="textEmailAddress"/>

</android.support.design.widget.TextInputLayout>

<Button
    android:id="@+id/send_email_button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Send"/>

And my code in MainFragment.java:

import ...
public class MainFragment extends Fragment {

private TextInputLayout textInputEmail;

public MainFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, container, false);

    textInputEmail = (TextInputLayout) view.findViewById(R.id.text_input_email);

    Button send_button = (Button) view.findViewById(R.id.send_email_button);
    send_button.setOnClickListener(view -> buttonSend(view));

    return view;
}

private boolean validateEmail() {
    String emailInput = textInputEmail.getEditText().getText().toString().trim();

    if (emailInput.isEmpty()) {
        textInputEmail.setError("Field can't be empty!");
        return false;
    } else {
        textInputEmail.setError(null);
        return true;
    }
}

public void buttonSend(View v) {
    if (!validateEmail() ) {
        return;
    }

    /*do something*/
}
}

For this I don't get any errors in either of my codes so I don't truly understand what the problem is. The warning that I get in MainActivity.java is a "'getText' may produce 'java.lang.NullPointerException'" exactly at the .getText() part in validateEmail() method.

Hope I explained it well. Thanks to anybody who tries to help!

EDIT: I believe I have not explained it well enough. I forgot to say that when I press the Send button, my app crashes instantly. That is the problem I am trying to solve.

EDIT 2: Here is what I think is the "stack trace".

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.luka.straingeremailapp, PID: 2728
java.lang.IllegalStateException: Could not find method buttonSend(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton
    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:424)
    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:381)
    at android.view.View.performClick(View.java:6291)
    at android.view.View$PerformClick.run(View.java:24931)
    at android.os.Handler.handleCallback(Handler.java:808)
    at android.os.Handler.dispatchMessage(Handler.java:101)
    at android.os.Looper.loop(Looper.java:166)
    at android.app.ActivityThread.main(ActivityThread.java:7425)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

Solution

  • For the crash:

    This is caused because the android:onClick attribute only works when the method is declared on an Activity, not on a Fragment. I would recommend never using the android:onClick attribute.

    Instead, resolve your Button in onCreateView just like you are for your TextInputLayout, and manually call button.setOnClickListener(view -> buttonSend(view)); to assign the click listener.

    For the warning:

    This is because TextInputLayout declares its getEditText() method as @Nullable (meaning that it does not guarantee that you will get a non-null value when you call it).

    The reason for this is that TextInputLayout assigns its internal EditText after inflation (the TextInputEditText that you've declared in your XML layout).

    If you didn't include that TextInputEditText as a child of the TextInputLayout, then getEditText() will return null. In your case, you can guarantee that unless you change that layout, you'll get the right value, so what you can do is make that assertion to avoid the warning:

    EditText editText = Objects.requireNonNull(textInputEmail.getEditText());
    String emailInput = editText.getText().toString().trim();