How to set data correctly in Lisview?

Asked

Viewed 102 times

1

Guys, I’m picking up a bit with asynchronous request on Android. I’m requesting a list of states on JSON, via OkHttp, and turn into a ArrayList states to be able to state ListView. However, in every way I tried the request only ends after the creation of the Fragment, thus, the ArrayList as a parameter of adapter to execute the setListAdapter is empty. This way always generates NullPointerException and I don’t know what to do.

I’m going to leave down my last code, I already got from an example here of the stack, but I did not get a positive result.

How do I receive the request correctly? If it is Synchronous the app will get stuck and I believe there should be a cool way to do.

Just follow the code. (Obs: use an interface to help logic, was the idea I saw here in the stack)

Fragment from the list of states

public class PesquisaEstado extends ListFragment implements AsyncResponse {

    private ArrayList<Estado> estados;
    private ArrayAdapter<Estado> mAdapter;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        new EstadosTask(this).execute();

        mAdapter = new ArrayAdapter<>(getActivity(),
                R.layout.item_list_pesquisa, estados);
        setListAdapter(mAdapter);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void processFinish(ArrayList<Estado> estados) {
        this.estados = estados;
    }
}

Class extending Asynctask

public class EstadosTask extends AsyncTask<Void, Void, ArrayList<Estado>>{

    public static final String URL =
            "https://bitbucket.org/Jocsa/jsonauxiliaresotb/raw/1fa827f1179ee827d1bedcdaa4c5befbe7686057/Estados.json";

    public AsyncResponse delegate = null;

    public EstadosTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

    @Override
    protected ArrayList<Estado> doInBackground(Void... params) {
        OkHttpClient client = new OkHttpClient();
        client.setReadTimeout(10, TimeUnit.SECONDS);
        client.setConnectTimeout(15, TimeUnit.SECONDS);

        Request request = new Request.Builder().url(URL).build();
        try {
            Response response = client.newCall(request).execute();
            Type listType = new TypeToken<ArrayList<Estado>>(){}.getType();
            String json = response.body().string();
            Gson gson = new Gson();
            ArrayList<Estado> estados = gson.fromJson(json, listType);
            return estados;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(ArrayList<Estado> estados) {
        delegate.processFinish(estados);
    }
}

Interface I created (based on an example from here in the stack)

public interface AsyncResponse {


  void processFinish(ArrayList<Estado> estados);
}

Ps: I have already debug a light and the method processFinish() in the PesquisaEstado is executed only after onActivityCreated(), for this reason the state becomes empty and gives NullPointerException.

From now on I appreciate any help!

2 answers

2


Some things you will have to change. At first it is not cool to instantiate objects without storing them like this: new EstadosTask(this).execute();

The Garbage Collector usually makes a lot of anger with things like this, mainly asynchronous.

Another thing, if you want to use this type of Adapter, it’s nice that you try to implement your own BaseAdapter, so you can call the interface format you want during listing. Ex: Images, Textview, etc.

That one NullPointerException is rolling because of the Array states that have not been instantiated, to initialize the Adapter you can create with it empty, but have to instantiate. Puts the beginning about like this:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    estados = new ArrayList<Estado>();

    mAdapter = new ArrayAdapter<>(getActivity(),
            R.layout.item_list_pesquisa, estados);
    setListAdapter(mAdapter);

    //Isso tem que ficar no final, pois corre o risco de finalizar antes.
    EstadosTask estadosTask = new EstadosTask(this).execute();

}

Another thing is this method processFinish() In it you have to set the data in your Adapter, otherwise it will not update. It would look something like this:

@Override
public void processFinish(ArrayList<Estado> estados) {
    mAdapter.addAll(estados);
}

This topic has some really cool examples for you to follow! https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView

1

Is giving null pointer because you create the adapter as long as the asynktask is doing the data request (it runs parallel to the main code, ie when you arrow the adapter the code of asynktask is still running).

You first have to run the asynktask and after the result creates the adapter.

How do you know what you’re doing and are using delegate, then in the method processFinish who is in the activity (you gave interface implements AsyncResponse in that activity) you will create the adapter in it.

Flow: executes the Asynk task -- no on result takes the arraylist and sends to the activity via delegate -- in the implemented method, creates the adapter and arrow the data that are in this list that you sent to activity.

You can even make a grace and before performing the asynktask you can set the background layout with a loading animation (progressbar) and then on delegate you arrow the "normal" layout that contains the lists (before creating the adapter, pq if it will not give null pointer when it fetches the list template in xml).

Browser other questions tagged

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