java.lang.Nullpointerexception: return null button

Asked

Viewed 92 times

2

Good Morning,

How do I reference a button from another Activity? In main, I am using another layout to inflate my list, and the button event is obviously returning null because it is not finding the view. Help.

private static String pesquisarDadosLivro;
private DadosLivrosAdapter adapter;

private static final String GOOGLE_LIVROS_URL =
        "https://www.googleapis.com/books/v1/volumes?q=  " + pesquisarDadosLivro;

private static final int DADOSLIVROS_ID_LOADER = 1;

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

    Button pesquisarLivro = (Button) findViewById(R.id.pesquisar);
    pesquisarLivro.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            EditText dadosLivro = (EditText) findViewById(R.id.dados_livro);
            pesquisarDadosLivro = dadosLivro.getText().toString();
            //Log.v("MainActivity", "Texto a ser pesquisado " + pesquisarDadosLivro);
        }
    });

    ListView listView = (ListView) findViewById(R.id.lista);
    adapter = new DadosLivrosAdapter(this, new ArrayList<DadosLivro>());
    listView.setAdapter(adapter);

    LoaderManager loaderManager = getLoaderManager();
    loaderManager.initLoader(DADOSLIVROS_ID_LOADER, null, this);
}

@Override
public android.content.Loader<List<DadosLivro>> onCreateLoader(int i, Bundle bundle) {
    // Create a new loader for the given URL
    return new DadosLivrosLoader(this, GOOGLE_LIVROS_URL);
}

@Override
public void onLoadFinished(android.content.Loader<List<DadosLivro>> loader, List<DadosLivro>
        informacoesLivros) {

    if (informacoesLivros != null && !informacoesLivros.isEmpty()) {
        adapter.addAll(informacoesLivros);
    }
}

@Override
public void onLoaderReset(android.content.Loader<List<DadosLivro>> loader) {
    adapter.clear();
}

}

Hello, I managed to solve the problem by inflating the same main Activity, as it contains the components that interacts with the user and is only 1 screen, I found more feasible, however I’m with another error, my http request returned 400, the value entered by the user is not sending the URL, I need the Loader to be loaded after the button event, know how I can do this?

package com.example.android.listadelivros;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity
        implements LoaderCallbacks<List<DadosLivro>> {

    private String pesquisarDadosLivro;
    private DadosLivrosAdapter mAdapter;

    private  String GOOGLE_LIVROS_URL = null;

    private static final int DADOSLIVROS_ID_LOADER = 1;

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

        final Button pesquisarLivro = (Button) findViewById(R.id.pesquisar);
        pesquisarLivro.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                EditText dadosLivro = (EditText) findViewById(R.id.dados_livro);
                pesquisarDadosLivro = dadosLivro.getText().toString();
                GOOGLE_LIVROS_URL =
                        "https://www.googleapis.com/books/v1/volumes?q= " + pesquisarDadosLivro;

                final LoaderManager loaderManager = getLoaderManager();
                loaderManager.initLoader(DADOSLIVROS_ID_LOADER, null,);

            }
        });

        ListView listView = (ListView) findViewById(R.id.lista);

        mAdapter = new DadosLivrosAdapter(this, new ArrayList<DadosLivro>());

        listView.setAdapter(mAdapter);

    }

    @Override
    public android.content.Loader<List<DadosLivro>> onCreateLoader(int i, Bundle bundle) {

        return new DadosLivrosLoader(this, GOOGLE_LIVROS_URL);
    }

    @Override
    public void onLoadFinished(android.content.Loader<List<DadosLivro>> loader, List<DadosLivro>
            informacoesLivros) {

        if (informacoesLivros != null && !informacoesLivros.isEmpty()) {
            mAdapter.addAll(informacoesLivros);
        }
    }

    @Override
    public void onLoaderReset(android.content.Loader<List<DadosLivro>> loader) {
        mAdapter.clear();
    }
}
  • The idea is that you do not refer to a View of an Activity in another Activity. If you want to use information from another Activity, you need to communicate between them: https://developer.android.com/training/basics/intents/result.html .

  • I believe this answer can help you: https://answall.com/a/135889/2461

  • It is necessary that the button be declared in xml that you set as contentView ( setContentView(R.layout.list_view) ), as Erick said, it is not possible to reference one Activity in another!

1 answer

1

Hello, Aline

What you intend to do unfortunately is not possible. A View only exists after an activity inflates it (instantiates, makes it exist...) through the method setContentView(int layout) and start to manipulate it. A Activity cannot manipulate in any way the View other’s Activity.

I have two possible solutions, and that the choice will depend on how your project is going as a whole.

1- Working with Fragments and have the interactions in the fragment sent to Activity so she can manipulate.

For starters, the idea is that Activity implements an interface that Fragment know and call. Then, we will create such interface that will be called when there was the click on Fragment:

public interface OnFragmentButtonClickListener  {
    public void onButtonClick();
}

And we will then have Activity inherit this interface and implement the method:

public class MinhaActivity extends AppCompact implements OnFragmentButtonClickListener {

    //... Outros métodos comuns da Activity

    public void onButtonClick() {
       //O botão do fragment foi clicado, faça o que tem que fazer na activity!
    }

}

Right, in the method onAttach() of your Fragment , which is called during the Fragment lifecycle when a Fragment is attached to Activity, capture the Activity using polymorphism to give us an instance OnFragmentButtonClickListener. Thus:

public void FragmentTwo extends Fragment {

   OnFragmentButtonClickListener onFragmentButtonClickListener

   @Override
    public void onAttach(Context context) {
        if(context instanceof OnFragmentButtonClickListener) {
            onFragmentButtonClickListener = (OnFragmentButtonClickListener) context;
        }
        super.onAttach(context);
    }

    //Métodos comuns ao fragment
}

Now, in the onClickListener from your button call the interface that is implemented by Activity so that so the Activity can match to the Fragment click:

fragmentButton.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
       //onFragmentButtonClickListener.onButtonClick(); Lembrando que onFragmentButtonClickListener pode ser null caso a activity não implemente a interface.
    } 
});

2- An Activity transfers the event to another Activity through startActivityForResult(Intent intent, int FLAG).

What happens is that an Activity B is opened by Activity A, that awaits some return from Activity B. Activity B only exists for interactions to occur and thus ends its life cycle by returning something to Activity A. What we can do is to make Activity A open Activity B and, when the X button is clicked, end the life of Activity B by returning Activity A an indicator that the button has been clicked. I don’t know if this fits into the project context that you have and nor believe that it is an elegant solution, but come on.

In Activity A, you will open Activity B not through the method startActivitiy(Intent intent), but through startActivityForResult(Intent, FLAG).

When starting Activityb, we inform the return flag:

Intent intent = new Intent(this, ActivityB.class);
int flagRetorno = 55;
startActivityForResult(intent, flagRetorno);

When there is the click on the Activity B button, we can inform you to store in some way that it was clicked and, when we finish Activity B, we can inform Activity A that it was clicked like this:

Intent returnIntent = new Intent();
returnIntent.putExtra("botaoclicado", true);
setResult(Activity.RESULT_OK, returnIntent);
finish();

But how will I receive this in Activity A? Through the methodonActivityResult(int requestCode, int resultCode, Intent data) which is part of the Activity.

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == flagRetorno) { 
        if(resultCode == Activity.RESULT_OK){
             boolean botaoFoiClicado = data.getStringExtra("botaoclicado");
         }
     }
}

I reaffirm that I do not believe it is the most elegant and even functional solution for your case, but it looks like something to think about and suddenly be used if you analyze your project structure better.

Att,

  • Hello, I managed to solve the problem by inflating the same main Activity, as it contains the components that interacts with the user and is only 1 screen, I found more feasible, however I’m with another error, my http request returned 400, the value entered by the user is not sending the URL, I need the Loader to be loaded after the button event, know how I can do this?

  • Could you create a specific question for this error? So more people can help you, and it makes it easier for other users to benefit from your question!

  • Aline, interesting your new problem. I agree with Thiago, better create another question to have better possibility to expose the problem. That would be very interesting. How about?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.