mrobertini1239
mrobertini1239

Reputation: 107

Parsing GSON - how to?

I've a application which displays cryptocurrency prices. I have activity which calls the api class for retrieving the large JSON data.

This is the priceactivity class.

public class PriceActivity extends AppCompatActivity {

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

        ApiCall apiCall = new ApiCall(this, "https://api.coinmarketcap.com/v1/ticker/?convert=EUR");

        RecyclerView customView = (RecyclerView) findViewById(R.id.recyclerviewprice);
        CoinAdapter CoinAdapter = new CoinAdapter(apiCall.coins, this);
        customView.setLayoutManager(new LinearLayoutManager(this));
        customView.setAdapter(CoinAdapter);
        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setTitle("Links");
    }
}

This is the api class

public class ApiCall {
    private Context mcontext;
    private String URL;
    public static List<Coin> coins;

    public ApiCall(Context mcontext, String URL) {
        this.mcontext = mcontext;
        this.URL = URL;
        connect(mcontext);
    }

    public void connect(Context mcontext) {
        RequestQueue requestQueue = Volley.newRequestQueue(mcontext);
        StringRequest objectRequest = new StringRequest(
                Request.Method.GET,
                URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {

                        GsonBuilder builder = new GsonBuilder();
                        Gson gson = builder.create();

                        coins = Arrays.asList(gson.fromJson(response, Coin[].class));

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.i(TAG, "onResponse: ");
                    }
                }
        );

        requestQueue.add(objectRequest);
    }
}

The problem is, the priceactivity class doesn't wait till the api class is finished. How do I solve this problem? Or how do I proper parse large data?

Upvotes: 0

Views: 49

Answers (2)

devops
devops

Reputation: 9179

Put the API Call logic in you Adapter class and initiate the request from onResume method:

public class PriceActivity extends AppCompatActivity {

    [...]

    @Override
    protected void onResume() {
        super.onResume();
        this.coinAdapter.reload();
    }

}

public class CoinAdapter extends [...] {

    [...]
    List<Coin> coins = new ArrayList<>(0); // empty on start
    Context ctx;

    public CoinAdapter(Context ctx){
        this.ctx = ctx;
    }  

    public void reload() {
        RequestQueue requestQueue = Volley.newRequestQueue(this.ctx);
        StringRequest objectRequest = new StringRequest(
                Request.Method.GET,
                URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {

                        GsonBuilder builder = new GsonBuilder();
                        Gson gson = builder.create();

                        coins = Arrays.asList(gson.fromJson(response, Coin[].class));

                        // refresh UI
                        notifyDataSetChanged();

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.i(TAG, "onResponse: ");
                    }
                }
        );

        requestQueue.add(objectRequest);
    }

}

Don't forget to call notifyDataSetChanged from onResponse to refresh the UI

Upvotes: 0

Reaz Murshed
Reaz Murshed

Reputation: 24211

This is because your Activity is running in the main thread while the API is being called in a separate thread. The Activity execution will not wait for the API call to be finished. The proper way of handling this situation is to notify the calling activity about the result from the API has been arrived.

To achieve the behaviour you need to implement an interface like this.

public interface HttpResponseListener {
    void httpResponseReceiver(List<Coin> result);
}

Now, you need to have a HttpResponseListener instance in your ApiCall class which needs to be initialized in the constructor. So the modified ApiCall class should be something like this.

public class ApiCall {
    private Context mcontext;
    private String URL;
    public static List<Coin> coins;
    public HttpResponseListener mHttpResponseListener;

    public ApiCall(Context mcontext, String URL, HttpResponseListener listener) {
        this.mcontext = mcontext;
        this.URL = URL;
        this.mHttpResponseListener = listener;  // Initialize
        connect(mcontext);
    }

    public void connect(Context mcontext) {
        RequestQueue requestQueue = Volley.newRequestQueue(mcontext);
        StringRequest objectRequest = new StringRequest(
                Request.Method.GET,
                URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        GsonBuilder builder = new GsonBuilder();
                        Gson gson = builder.create();
                        coins = Arrays.asList(gson.fromJson(response, Coin[].class));
                        mHttpResponseListener.httpResponseReceiver(coins);
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.i(TAG, "onResponse: ");
                    }
                }
        );

        requestQueue.add(objectRequest);
    }
}

Now from your Activity, you need to listen to the callback function of the interface that is you are going to implement in your Activity.

public class PriceActivity extends AppCompatActivity implements HttpResponseListener {

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

        // Modify the call to support the constructor
        ApiCall apiCall = new ApiCall(this, "https://api.coinmarketcap.com/v1/ticker/?convert=EUR", this);

        RecyclerView customView = (RecyclerView) findViewById(R.id.recyclerviewprice);
        CoinAdapter CoinAdapter = new CoinAdapter(apiCall.coins, this);
        customView.setLayoutManager(new LinearLayoutManager(this));
        customView.setAdapter(CoinAdapter);

        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setTitle("Links");
    }

    // Implement the overriden function
    @Override
    public void httpResponseReceiver(List<Coin> result) {
        // Do something with the list of coins here.
    }
}

Hope that solves your problem.

Upvotes: 2

Related Questions