1

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)
pantank14
  • 175
  • 1
  • 10

4 Answers4

0

It is not really an error, and you will find it is quite common actually. Basically any ui element not directly controlled by code (IE: something in a fragment used by a separate activity, or elements defined in a list adapter.) will give you this warning because it cant guarantee the UI element exists and is instantiated.
You can add a null check around the .getText() to silence the warning and prevent it from trying to pull from the element if it is indeed null.

if(textInputEmail != null){
   String emailInput = textInputEmail.getEditText().getText().toString().trim();
}
Notsileous
  • 548
  • 3
  • 9
  • 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. – pantank14 Nov 29 '18 at 17:33
0

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();
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • I have added the "editText" line into MainFragment.java. There is warning that says: "Call requires API level 19 (current min is 16): java.util.Objects#requireNonNull". When run the app, everything seems fine again, but when I click the Send button, the app crashes again. – pantank14 Nov 29 '18 at 17:43
  • Ah okay, if you're minSdkVersion 16 you'll just need to define your own in your project. You'd need to provide the stack trace for the crash if you're still seeing issues. – Kevin Coppock Nov 29 '18 at 17:45
  • I believe I have added the stack trace to the main question. – pantank14 Nov 29 '18 at 17:59
  • Updated the answer -- the issue is unrelated to the warning, but I've left both parts to the answer. – Kevin Coppock Nov 29 '18 at 18:14
  • I have removed the onClick attribute of the Button xml file and added an id attribute for it. In the MainFragment.java I have added two lines in the onCreateView. In the second of the added lines I get an error pointing to the "view" and saying "Variable 'view' is already defined in the scope". What should I do? I also updated the main question with the new code. – pantank14 Nov 29 '18 at 18:55
  • Oh right, you already have a variable `view`. You can just change the `view -> buttonSend(view)` to `v -> buttonSend(v)`. Alternatively if Java 8 features (lambdas) are not enabled in your project just use `setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { buttonSend(v); } })` – Kevin Coppock Nov 29 '18 at 18:58
  • It works by doing the last thing you said. It looks confusing for a beginner. How about using the one with lambdas enabled? How do I enable Java 8 features and how does that change my overall text? – pantank14 Nov 29 '18 at 19:13
  • There's a good writeup here: https://developer.android.com/studio/write/java8-support. Basically for lambdas it's a shorthand you can use for an interface with a single method. You could also just write it as a method reference: `button.setOnClickListener(this::buttonSend)` – Kevin Coppock Nov 29 '18 at 19:21
  • By adding Java 8 features will every thing still work in my code/app? Does it change anything important? Since my minimum API is 16, does adding Java 8 features cause any problems to that? – pantank14 Nov 29 '18 at 19:43
  • Shouldn't cause any issues, you may just get some IDE assisting to simplify your code in places. It's mostly syntax improvements. – Kevin Coppock Nov 29 '18 at 20:21
0

If you are sure that your code is correct then just convert your project into Kotlin project Android studio will do it for you Then the exception will bhe a history

Akshat Tamrakar
  • 2,193
  • 2
  • 13
  • 21
0

The problem is cause you are casting:

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

use:

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