Reputation: 107
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
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
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