简体   繁体   中英

Android/Java application - How to call a activity function from a fragment properly?

I have this code for my Main Activity:

public class MainActivity extends AppCompatActivity {
    static EditText Nome, CPF;
    static CadastroBD helper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        Log.d("Insere", "Sistema entrando na Main Activity");

        Nome= (EditText) findViewById(R.id.Nome_In);
        CPF= (EditText) findViewById(R.id.CPF_In);


        helper = new CadastroBD(this);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Selecione a aplicação com que deseja compartilhar os dados", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });




    }

    public void inserePessoa(View view)
    {
        Log.d("Insere", "Func inserePessoa iniciada");
        String t1 = Nome.getText().toString();
        String t2 = CPF.getText().toString();
        Log.d("Insere", "Func inserePessoa - variáveis iniciadas");

        if(t1.isEmpty() || t2.isEmpty())
        {
            Log.d("Insere", "Func inserePessoa - Campo em branco");
            Message.message(getApplicationContext(),"Entre com o Nome e o CPF");
        }
        else
        {
            Log.d("Insere", "Func InserePessoa - chamando insertDataPessoa");
            long id = helper.insertDataPessoa(t1,t2);
            if(id<=0)
            {
                Message.message(getApplicationContext(),"Insertion Unsuccessful");
                Nome.setText("");
                CPF.setText("");
            } else
            {
                Message.message(getApplicationContext(),"Insertion Successful");
                Nome.setText("");
                CPF.setText("");
            }
            Log.d("Insere", "Func InserePessoa - Finalizando");
        }
    }

I am calling the function InserePessoa on a Fragment. The code of the Fragment is:

public class FirstFragment extends Fragment {



    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false);
    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {



                ((MainActivity)getActivity()).inserePessoa(view);

                Snackbar.make(view, "Inserção feita com sucesso", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
                //NavHostFragment.findNavController(FirstFragment.this)
                //        .navigate(R.id.action_FirstFragment_to_SecondFragment);

            }
        });
    }
}

When I call the function inserePessoa from the Fragment, the application is minimized and the code stops on the log message "Log.d("Insere", "Func inserePessoa iniciada");" The other messages does not appear on logcat because the application stops on that part.

I think it happens because I am missing something when calling the inserePessoa function from the Fragment.

Why is it happening? How can I make it work?

**I get on logcat:

2020-10-26 17:15:54.885 27220-27220/? D/Insere: Sistema entrando na Main Activity 2020-10-26 17:15:54.886 27220-27220/? D/Insere: Criado o Banco de Dados 2020-10-26 17:16:08.767 27220-27220/? D/Insere: Func inserePessoa iniciada 2020-10-26 17:17:36.753 28648-28648/? D/Insere: Sistema entrando na Main Activity 2020-10-26 17:17:36.754 28648-28648/? D/Insere: Criado o Banco de Dados 2020-10-26 17:17:48.000 28648-28648/? D/Insere: Func inserePessoa iniciada

The error that I am getting is:

2020-10-26 21:11:25.167 27342-27342/br.com.pim E/AndroidRuntime: FATAL EXCEPTION: main Process: br.com.pim, PID: 27342 java.lang.NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference at br.com.pim.MainActivity.inserePessoa(MainActivity.java:56) at br.com.pim.FirstFragment$1.onClick(FirstFragment.java:37) at android.view.View.performClick(View.java:7339) at android.widget.TextView.performClick(TextView.java:14222) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:967) at android.view.View.performClickInternal(View.java:7305) at android.view.View.access$3200(View.java:846) at android.view.View$PerformClick.run(View.java:27787) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7091) at java.lang.reflect.Method.inv oke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

The textview is defined on the fragment, XML code bellow:

<?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"
    tools:context=".FirstFragment">

    <TextView
        android:id="@+id/textview_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="72dp"
        android:text="Cadastre o nome e o CPF"
        android:textSize="22dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.198"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="44dp"
        android:text="Cadastrar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:layout_editor_absoluteX="122dp"
        tools:layout_editor_absoluteY="208dp"
        tools:ignore="MissingConstraints">

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/Nome_In"
        android:layout_width="325dp"
        android:layout_height="52dp"
        android:layout_marginTop="68dp"
        android:hint="Nome"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="@+id/textview_first"
        app:layout_constraintTop_toBottomOf="@+id/textview_first" />

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:layout_editor_absoluteX="65dp"
        tools:layout_editor_absoluteY="277dp"
        tools:ignore="MissingConstraints">

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/CPF_In"
        android:layout_width="325dp"
        android:layout_height="52dp"
        android:layout_marginTop="68dp"
        android:hint="CPF"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="@+id/Nome_In"
        app:layout_constraintTop_toBottomOf="@+id/Nome_In" />
</androidx.constraintlayout.widget.ConstraintLayout>

You should access the views where they are defined, so you should access CPF and Nome from the fragment and not from the activity. Move the variables

 EditText Nome, CPF;
 CadastroBD helper;

into the fragment, and bind them inside onViewCreated

 Nome= (EditText) findViewById(R.id.Nome_In);
 CPF= (EditText) findViewById(R.id.CPF_In);

Now you can access the views from the fragment.

To come back to your question. There are couple techniques to access the activity. One of them is of course the way you are doing it, but that is not a preferable one because of the tight coupling to the activity (you are explicitly casting to MainActivity).This kinda defeats the purpose of using a fragment. Besides the one I will explain there is also a "reactive" technique where the Activity is observing a state, and when that the fragment sets a new state the activity reacts to it.

The one I will explain is via interfaces or callbacks. You define an interface inside the activity, something like

public interface FragmentActions {
  void processData(String parameter1, int parameter2)
}

Then you let the activity implement this interface:

public class MainActivity extends AppCompatActivity implements FragmentActions {
     ...

  @Override
  void processData(String parameter1, String parameter2) { 
  Log.d("fragmentaction", "Display data")
}

}

And the last step is to call this interface from the fragment. First we need to check whether the underlying activity is implementing this particular interface, and if so, call the function you want:

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            
    
            Nome = (EditText) view.findViewById(R.id.Nome_In);
            CPF = (EditText) view.findViewById(R.id.CPF_In);
    
            view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
    
                    if (getActivity() instanceof FragmentActions) {
                      ((FragmentActions) getActivity()).processData(Nome.getText().toString(), 
CPF.getText().toString() ) ;
                    }
                  
                }
            });
        }

for using a method of a activity on a fragment your activity most implement before that fragment. what I see in your code you are calling your fragment in another place not in main activity so your activity not implemented and onCreate() method not called so when you are using your edittext its produce nullpointerexception.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM