I am using volley package to retrieve data from a website(JSON).
Here is my method
private void getEarthquakeList(){
// ...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
//Earthquake Feeder
String url ="https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_month.geojson";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("Response is: ",response);
//Parsing Json
parseJson(response);
final ListView earthquakeListView = (ListView)findViewById(R.id.list);
//Sort the array according to magnitude
earthquakeArrayList.sort((a, b) -> Double.compare(b.getTime(), a.getTime()));
mAdapter = new EarthquakeAdapter(getApplicationContext(), earthquakeArrayList);
earthquakeListView.setAdapter(mAdapter);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error",error.getMessage());
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
}
The problem is that right now I am updating the UI inside this method after it returns the response.
These are the lines
//Sort the array according to a date
earthquakeArrayList.sort((a, b) -> Double.compare(b.getTime(), a.getTime()));
mAdapter = new EarthquakeAdapter(getApplicationContext(), earthquakeArrayList);
earthquakeListView.setAdapter(mAdapter);
While I am running in the MainActivity there is no issue, the user opens the app and gets the list of earthquakes.
The issues start when I want to switch to service where I monitor every couple of minutes or when the website content is changing.
So I want my method without updating the UI in it.
The problem is that If I am not updating the UI inside onResponse, the UI thread continues and results in an empty array.
So this array stay empty earthquakeArrayList if I am not doing it inside
public void onResponse(String response)
Ideas how to separate the two, in one hand running the method and fetching the data and on the other hand the main thread will be able to access the data and not finish executing.
Thanks
EG
The recommended solution right now is to use LiveData. LiveData works on the Observer Pattern, so you can have any number of observers to the updated data both in the Service and the Activity but they need to be under the same context. These are a bit advanced topics but a good way to decouple your UI with the data layer. You can go through these two links
Google IO 2018 session on Livedata
Medium Article on LiveData
Related
I have to make several requests to an API for an Android App and I am having the following problem:
I have a list of items and I have to make a request for each in order to get some data and show it in the app. When my list's size is 1 (in case I have only one item), the app works perfectly but if I have more I get the data mixed and one item have the value of other and things like that.
I am using JsonObjectRequest and Volley. I use callback interfaces for sending back the request data to the activities. I think it's probably a synchronisation problem but I'm not sure and I'm a bit frustrated. I've tried everything!
Request Code:
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, urlMarket, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONObject singleResult;
singleResult = response.getJSONArray("result").getJSONObject(0);
coin.setHigh(singleResult.getDouble("High"));
coin.setLow(singleResult.getDouble("Low"));
coin.setLast(singleResult.getDouble("Last"));
coin.setVolInBtc(singleResult.getDouble("BaseVolume"));
coin.setBid(singleResult.getDouble("Bid"));
coin.setAsk(singleResult.getDouble("Ask"));
coin.setPrevDay(singleResult.getString("PrevDay"));
callback.onSuccess(coin);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
requestQueue.add(request);
Any kind of help would be appreciated!!
PD.: if there's a better way for doing that instead of JsonObjectRequest, please tell me!
Consider either of these two options:
Extend JSONObjectRequest that accepts a id/token field which is returned as part of the Success/Error callback.
Use a final field as an identifier before you make an API call. Assuming you are making these calls in a loop, you can then refer to this final field from your anonymous callbacks to identify the specific Stock. For example, you can use the ISIN, database ID or ticker symbol to identify the response.
What I want to achieve is to be able to observe changes in my web service and then update my textview if there is any change. I am currently using timer to achieve this by running it every x second. The problem though, is that the memory leaks so it's not a good solution. Now I stumbled upon this rxjava/rxjava but I'm confused on how to use it. The documentation is confusing to me and I can't find alot of tutorials about this. I am using volley to get data from my web service by the way.
this is the Observable that someone on answered on my other question but I'm getting an error which is "Incompatible types" on return sendRequest.
Observable.interval(500, TimeUnit.MILLISECONDS, Schedulers.io()).map(new Func1<Long, Object>() {
#Override
public Object call(Long tick) {
return sendRequest();
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe();
here is my volley request code
public void sendRequest(){
//While the app fetched data we are displaying a progress dialog
//final ProgressDialog loading = ProgressDialog.show(this,"Fetching Data","Please wait...",false,false);
StringRequest stringRequest = new StringRequest(JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//text.setText(response);
//loading.dismiss();
showJSON(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
requestQueue.add(stringRequest);
}
private void showJSON(String json){
ParseJson pj = new ParseJson(json);
pj.parseJSON();
text.setText(ParseJson.playing[0]);
}
Your method sendRequest doesn't return anything(void). You can either return null or something.
#Override
public Object call(Long tick) {
sendRequest();
return null;
}
I would suggest you firstly read Java basics instead of writing Android app.
Use push notifications to send messages from the server to the users when data is updated and avoid sending unwanted requests to the server.
Then you can send the request for new data only when notified and update the Observer someway, maybe use a rx subject, or better store the data in SQLite table and observe changes from the DB.
Recommend this to create a rx stream from sqlite
https://github.com/square/sqlbrite
GCM: https://developers.google.com/cloud-messaging/
In my application i need to display the data in list view from rest service . I have gone through many samples but am not satisfied with that so can somebody help me ? Need sample or explanation . Thanks in advance!
In android you can use libraries to consuming REST
Volley
Retrofit
Your question is very general. Try one from above.
Sample use Volley:
in gradle: compile 'com.mcxiaoke.volley:library:1.0.19'
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
you can call api in fragments.
if you are new to android,
1)first fetch the data from api with a asynctask(check android json parsing with url in learn2crack).
2)after step 1 you have your data to populate to your list,if you want to make a custom list the same site also gives an example for android custom list(learn2crack)
you can call json on asynctask class.
call the async task in onCrateView of your fragment
Is there a way to send and listen for volley batch requests and responses in android?
i want to sync all the offline data once the network is back.
Currently am using a for loop to add the requests to the queue.I get responses individually for each request.
Is there any way for batch request and response listener?
I had a same problem then I resolved it by a little stupid way.It's only useful if you have a small number of requests in a batch. Hope it help :)
public static void requestData(#NonNull final Context context, final String url, final String cityID, final int typeOfResult, final int batchId) {
MySingletonWraper.getInstance(context).addToRequestQueue(new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// add json object to list json of this batch
Batch batch = listBatch().get(batchID);
batch .getListRespones().add(respone);
// listBatch is a ArrayList of Object Batch which have id, queue url, list results
urlsQueue = batch .getUrlsQueue();
if (urlsQueue.isEmpty()) { // I create a queue for control in a batch, check if it's empty - this is last request
// parse JsonObject for today weather
parseJsonToWeatherObject(typeOfResult);
return;
}
// only request if sure the previous request is successed
// if have too many reuqests in a batch, just break it if you can
requestData(context, urlsQueue .poll(), cityID, typeOfResult, batchID);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// write log error
error.printStackTrace();
// refresh this batch
listBatch().refresh();
// re-request
fetch(context, cityID, batchID);
}
}));
}
I don't think there is realistic implementation of a batch listener. Although it is possible to send multiple requests, responses don't arrive at a same time. It might be important to note that in Volley, network pool size is capped at 4 ( I believe this is defined by the constant DEFAULT_NETWORK_THREAD_POOL_SIZE ). You may add many requests to queue but only 4 get processed at a time. And up to now, Volley doesn't have a callback for completed queue which would technically be a close enough implementation of a batch listener.
So you would still need to work on each response individually it seems. Although considering that network process is expensive, I'd work on the server to pre-process whatever data to be sent to the devices, avoiding the need to do multiple requests.
I want to send two different requests and handle two different responses in one Activity using Volley library.
My activity implements onResponseListener, so i have only one onResponse method and both responses are handled here. As they are completely same in structure i cant tell which is which.
How can i tell from which request i have received the response so i can handle them differently? Is there a way to "tag" a request or something like that?
I could set some kind of check variable, e.g. boolean firstRequestIsSent when i send the request, and then check it in the onResponse method, but its a pretty ugly solution.
Many thanks
Instead of implementing onResponse as part of the class, you can instantiate a new Response.Listener with the request. This way you will have a separate listener for each request.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener() {
#Override
public void onResponse(String response) {
// individual response here
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error here
}
});