I create an application for Android, which saves GPS coordinates and displays them with addresses.
I have a function:
public String getAddressByGpsCoordinates(String latlan) {
requestQueue = Volley.newRequestQueue(this);
String url= "http://maps.googleapis.com/maps/api/geocode/json?latlng="+latlan+"&sensor=true&key=(I have a correct key :))";
JsonObjectRequest request = new JsonObjectRequest(url,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
address = response.getJSONArray("results").getJSONObject(0).getString("formatted_address");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
requestQueue.add(request);
return address;
}
It is returned NULL all the time.
Can You help me what is wrong with my code?
Using JsonObjectRequest with a RequestQueue is an asynchronous mechanism--the work is performed in the background and the onResponse callback is called whenever the response is ready.
Because of this, it is very likely that you return from your method before onResponse gets called, and since address isn't set beforehand (that you've shown, anyway), its value will be null.
If you want to block your thread until the request has completed and set the value of address, you should use a RequestFuture: Can I do a synchronous request with volley?
Related
I can get very strange issue in my project. I can get the response from volley over the internet and after reposne I want to store it in sharedpref, but issue is that when I get the response and showed up within resonse function then it shows correct data, but when I used to save it outside the response function sharedpref it gives 0. I declared the string public and top of the class but got no luck. Am very strange whats the issue.
SharedPreferences savelogin = getSharedPreferences("login",MODE_PRIVATE);
final SharedPreferences.Editor slogin = savelogin.edit();
String url = "https://datafinderdatabase.xyz/dfapi/FetchId.php?username="+fuser;
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
userid = response.toString();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toasty.error(getApplicationContext(), "Network Issue", Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
requestQueue.add(stringRequest);
slogin.putString("username",fuser);
slogin.putString("password",fpass);
slogin.putString("userid",userid);
slogin.commit();
This is because your call to the API is asynchronous. Therefore, the result you get back may be processed after that function finishes. To solve this, you can take a Interface approach, explained here for a similar issue:
wait until firebase retrieves data
OR: you need to save the variable to the shared preferences inside the onResponse function.
These:
slogin.putString("username",fuser);
slogin.putString("password",fpass);
slogin.putString("userid",userid);
slogin.commit();
must be inside this:
#Override
public void onResponse(String response) {
userid = response.toString();
//here
}
I am not sure what I am doing wrong. I am very new to this and just jumped straight into trying to make API calls. I am trying to retrieve information from rapidAPI for a simple project I am working on to view prices of stocks and so on. I am using the volley package from Android Studio to make my APIcalls to retrieve JSON and trying to put that into a textView. The way I imagine this to work is that I press a button and then once that is clicked, it runs the code to get the information and then shows the response in the textView. however, when the button is clicked, nothing happens. no error or response of any sort.
private TextView mTextViewResult;
private RequestQueue mQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewResult= findViewById(R.id.text_view_result);
Button buttonParse= findViewById(R.id.button_parse);
mQueue= Volley.newRequestQueue(this);
buttonParse.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
jsonParse();
}
});
}
private void jsonParse(){
String url="https://apidojo-yahoo-finance-v1.p.rapidapi.com/market/get-quotes?region=CA&lang=en&symbols=VEQT.TO";
JsonObjectRequest request= new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray= response.getJSONArray("result");
JSONObject result=jsonArray.getJSONObject(0);
int marketPrice= result.getInt("regularMarketPrice");
mTextViewResult.setText(String.valueOf(marketPrice));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mTextViewResult.setText("" +error.toString());
}
}){
#Override
public Map<String,String> getHeaders() throws AuthFailureError{
Map<String,String> params= new HashMap<>();
params.put("x-rapidapi-host", "apidojo-yahoo-finance-v1.p.rapidapi.com");
params.put("x-rapidapi-key", "APIKEY");
return params;
}
};
mQueue.add(request);
}
}
From what you've posted are you sure your x-rapidapi-key is APIKEY. Pretty sure that's the primary reason of your issue. Only after you put a valid API key in your request header, will your API call return a proper expected response.
You can read how to generate the rapidapi key from their official docs here
Currently the response you receive on api call using the wrong apikey is something like this:
{
"message": "Key doesn't exists"
}
Now in your java code you are looking for a JSONArray based on the key "result", while the response currently only has "message" being returned. That's the reason nothing happens, you can try finding the value in response for message and get the error messages if you wish. Generate a valid rapidapi key and try again, Good luck!
How do I get the response out of the public void onResponse function?
Edit: I got Parse Error: "Cannot assign a value to final variable 'res'"
public JSONObject getRestRequest() {
final JSONObject res;
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, this.restPath, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) { // basically I just want to return this response
res = response;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}
);
return res;
}
}
you cannot do this exactly as you have written because the network request is happening on a separate thread.
First, let's walk through your code so you're clear what's happening:
public JSONObject getRestRequest() { // 1 - your method is invoked by another method and control starts here
final JSONObject res; // 2 - This final (i.e. immutable) field is created
// 3 - You create a new request object - no networking is happening yet
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, this.restPath, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) { // basically I just want to return this response
// 5 - Some time later, after the request completes, this method is invoked
// BUT - you can't assign to res because it's final (immutable)
res = response;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}
);
// 4 - IMMEDIATELY after creating "request", the value that was created in step 2 (which is null) is returned
return res;
}
So you're trying to execute an asynchronous operation (launching a thread to make a network request and parse the response) synchronously (blocking until it completes to return the result).
So that's your issue. To solve this, you have two options:
1 - Use an asynchronous callback:
public void getRestRequest(final Callback<JSONObject> callback) { // 1 - your method is invoked by another method and control starts here
// Now you're passing in a callback that will be invoked later with the result
// final JSONObject res; // 2 - You no longer need this local variable
// 3 - You create a new request object - no networking is happening yet
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, this.restPath, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) { // basically I just want to return this response
// 5 - Some time later, after the request completes, this method is invoked
// This time, you invoke your callback with the result
callback.onSuccess(response)
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
// 6 - You can also pass back errors to your callback
callback.onError(error);
}
}
);
// 4 - You return IMMEDIATELY after creating "request"
}
This method is more common. You create your callback, pass it in to the function and then just handle the response:
// 1 - Start showing some UI that a request is happening
showProgressDialog();
// 2 - A new callback to handle the network response is created - no request is happening yet
Callback<JSONObject> callback = new Callback<>() {
public void onSuccess(JSONObject response) {
// 4 - Some time later, when the network response finishes, this called
// Handle response
dismissProgressDialog(); // Back on the main thread, so safe to update the UI
}
public void onError(VolleyError error) {
// 5 - Or this is called if the request failed
// Handle error
dismissProgressDialog(); // Back on the main thread, so safe to update the UI
}
}
// 3 - Invoke the network request which will happen in a background thread.
// Meanwhile, the main (UI) thread is not blocked and the progress dialog continues to spin
network.getRestRequest(callback)
Option 2 - Use a RequestFuture.
public JSONObject getRestRequest() { // 1 - your method is invoked by another method and control starts here
// 2 - Initialize a Future to use to synchronously get the result
RequestFuture<JSONObject> future = RequestFuture.newFuture();
// 3 - You create a new request object with the future as the listener - no networking is happening yet
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, this.restPath, future, future);
// 4 - You return the value the future will obtain by making the network request
// THIS IS A BLOCKING CALL SO DON'T DO THIS ON THE MAIN THREAD
// This will also throw an exception if it fails
return future.get();
}
So now you can get the result like you originally intended:
...
JSONObject response = network.getRestRequest()
...
But you cannot do this on the main (UI) thread (Android throws an exception if you try to do networking on the main thread. But if you're already doing work on a separate thread, this is fine.
Hope that helps!
You are trying to get results immediately but request is asynchronous you can call request synchronously
synchronized (this) {
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, "", null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) { // basically I just want to return this response
res = response;
YourClassName.this.notify();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}
);
this.wait();
}
But it will lock your thread until request will be finished
i'm sure that you need to do it asynchronous
please read documentation about multi threading in java
My java skills are quite good, still I fail to grasp what happens here.
I am programming an android app and right now I am programming a class which uses the Google Volley API in order to interact with a web-server.
The problem is that I want the class to be called like this:
Server_interaction s_i = new Server_interaction(getApplication);
String text = s_i.post_request();
Text should now contain the returned post request, in my case the string "Hello from server". Instead, it turns out to be null. This happens because the post_request method seems to return before having executed the post_request.
Here is the Server_interaction class:
public class Server_interaction
{
String server_url = "someipadress/greeting.php"; //this address is correct, but I want to hide it for you guys :)
String response_string;
Context myContext;
RequestQueue requestQueue;
public static final String TAG = Server_interaction.class.getSimpleName();
/* Here we add a constructor that takes in context. We need a context for volley requestqueue, and this is an elegant way*/
public Server_interaction(Context context)
{
myContext = context;
requestQueue = Volley.newRequestQueue(myContext);
}
public String post_request()
{
StringRequest stringRequest = new StringRequest(Request.Method.POST, server_url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response)
{
response_string = response;
requestQueue.stop();
Log.i(TAG, "the response is: "+ response_string);
}
}
, new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error)
{
response_string = "Something went wrong";
//error.printstacktrace()
requestQueue.stop();
}
}
); //stringrequest parameter end
//add request to requestqueue
requestQueue.add(stringRequest);
Log.i(TAG, "the response again:: "+ response_string);
return response_string;
}
}
When being executed, logcat shows this:
01-22 19:00:44.878 2954-2954/com.example.koenraad.Exigentia I/Server_interaction: the response again:: null
01-22 19:00:44.926 2954-2954/com.example.koenraad.Exigentia I/Server_interaction: the response is: hello from server
So this means that the string is null when being returned, then afterwards it is set. How can this be fixed?
Thanks in advance!
Your code is asynchrounous.
The StringRequest object created in method post_request() will be used by the framework after the method returns.
I want to get some JSON code from my API. I wish to do something like this in the OnCreate:
try
{
String jsonstr = getSomeThingAndPauseAndroid("http://someplace.com/api/xyz");
if (!jsonstr.isEmpty()) JSONObject jsonobj = new JSONObject(jsonstr);
}
catch { // handle error }
But when it happens, Android just go doing stuff and don't wait for the request to complete and response and I get nothing on jsonstr.
Is there some way to do that not needing a lot of new class files?
The correct way to do this is to make the request asynchronously and trigger a method on response. This is an example using Google's Volley:
//Start volley:
RequestQueue queue = Volley.newRequestQueue(this); // this = context
final String url = "http://someplace.com/api/xyz"";
// prepare the Request
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>()
{
#Override
public void onResponse(JSONObject response) {
//This is where you setup your UI
//Remember to dismiss the ProgressDialog
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
//Remember to dismiss the ProgressDialog
Log.d("Error.Response", response);
}
}
);
// add it to the RequestQueue
//Here you should add a ProgressDialog so the user knows to wait
queue.add(getRequest);