I am trying getting data from an API using volley. I am trying to store it as a global variable, but it always returns null. Why?
Here is my sample code:
JsonObjectRequest jsonRequest = new JsonObjectRequest
(Request.Method.GET, url, null, response -> {
try {
if (response.getString("action").equals("success")) {
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
System.out.println(response);
}
} catch (JSONException e) {
e.printStackTrace();
}
}, Throwable::printStackTrace);
Volley.newRequestQueue(MainActivity.this).add(jsonRequest);
What is the problem here?
here is my api json response
{"action":"success","checkin":"08:30:25","chekout":"blank"}
It does not working out of the request parenthesis
because this variable is temporary and it can be null if no data found.
So you have to write looks like
public static String checkInTime = "";
public static String checkOutTime = "";
After declaring global variable of String you can store data and can access from anywhere
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
Its actually working for me
From the context you provided I guess you have a problem with some of these lines:
if (response.getString("action").equals("success")) {
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
Reason 1 - you are not entering the if body
Reason 2 - you are not getting the response values properly
Try to debug the function
If I need to debug it I will:
Print the response before the IF statement
Print these values:
response.getString("action") checkInTime = response.getString("checkin"); checkOutTime = response.getString("chekout");
If it's being done from an Activity:
create a variable, e.g.:
public class MainActivity extends AppCompatActivity {
private String checkInTime;
Then in the code you posted above, add:
if (response.getString("action").equals("success")) {
this.checkInTime = response.getString("checkin");
Now try to access it from other places.
If it's not what you are looking for, please update the question with the relevant code regarding your global variable.
Related
I am developing a weather app for that I am using dark sky API in which I want to know the weather status of a bunch of locations which I have stored in ArrayList<LatLng>.
I am using OKHttp to parse the JSON data from API, so I tried to loop the whole fetching process inside for loop but it doesn't give the desired output.
private void beginTask(ArrayList<LatLng> arrayLis) {
//arraylis contains list of locations(LatLng)
m = 0;
startTask = true;
for (int i = 0;i<arrayLis.size();i++) {
double latitude = ((LatLng)arrayLis.get(i)).latitude;
double longitude = ((LatLng)arrayLis.get(i)).longitude;
String url = "https://api.darksky.net/forecast/APIKEY/"
+latitude+","+longitude+"?units=si";
LatLng mylatlng = new LatLng(latitude,longitude);
startProcess(url,mylatlng);
Log.i("GGGTT",""+latitude+", "+longitude);
}
}
private void startProcess(String myurl, final LatLng myLatlng){
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(myurl)
.build();
Call call = httpClient.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String data = response.body().string();
Log.i("DATASS",data);
if (response.isSuccessful()){
try {
getCurrentDetails(data,myLatlng);
} catch (JSONException e){
e.printStackTrace();
}
}
}
});
}
private void getCurrentDetails(String data,LatLng myLatlng) throws JSONException{
JSONObject main = new JSONObject(data);
double la = main.getDouble("latitude");
double lon = main.getDouble("longitude");
JSONObject currently = main.getJSONObject("currently");
String summary = currently.getString("summary");
double temperature = currently.getDouble("temperature");
String icon = currently.getString("icon");
LatLng latLngo = new LatLng(la,lon);
ter.add(latLngo);
weatherInfo.add(icon);
// Output here is not in the same order that I have passed
Log.i("LETSCHECK",""+la+", "+lon +icon);
}
I am passing the values as:
19.21111,73.07729
19.20238,73.06582
19.19383,73.05362
19.18848,73.04221
But the output is not in the same order inside the getCurrentDetails method
19.19383,73.05362
19.20238,73.06582
19.18848,73.04221
19.21111,73.07729
I think the method is not waiting before the previous loop gets completed.
Are there any solutions for getting the weather status of all locations stored in ArrayList without changing its order?
EDIT
Hi, I have gone through this method to fetch data in order and its working fine, thanks but one more problem is that I was expecting to show data 4 times as there are four LatLngs in ArrayList and it's working fine, but when I try to read the fetching data that I have stored in another array it only shows 2 items rather than 4.
private void getCurrentDetails(String data,LatLng myLatlng) throws JSONException{
JSONObject main = new JSONObject(data);
double la = main.getDouble("latitude");
double lon = main.getDouble("longitude");
JSONObject currently = main.getJSONObject("currently");
String summary = currently.getString("summary");
double temperature = currently.getDouble("temperature");
String icon = currently.getString("icon");
//Log.i("LETSCHECK",""+la+", "+lon +icon+",k");
loopi++;
Log.i("LETSCHECK",""+loopi);
if (loopi < arrayList.size()) {
getItAgain();
} else if (loopi == arrayList.size()){
for (String l:weatherInfo){
Log.i("LETSCHECK",l);
//expected 4 items to show but its showing only 2 items
}
}
Log.i("LETSCHECK",""+la+", "+lon +icon);
weatherInfo.add(icon);
}
private void getItAgain() {
double latitude = ((LatLng)arrayList.get(loopi)).latitude;
double longitude = ((LatLng)arrayList.get(loopi)).longitude;
String url = "https://api.darksky.net/forecast/74d8feeda5ecf5ee6667d034778b239d/"
+latitude+","+longitude+"?units=si";
LatLng mylatlng = new LatLng(latitude,longitude);
startProcess(url,mylatlng);
}
The network calls are asynchronous and this the expected behavior that you are having here. If you want to get them sorted as you have passed them, then you might need to have a mechanism of waiting for the network call of the previous one to be completed and then again call the next one. However, this might increase the delay of waiting for the response from the server, as you are not fetching multiple responses from the server concurrently.
If you want to wait for the response to maintain the sorted manner, you might just need to do the following.
// Declare a global variable of the list of your locations.
ArrayList<LatLng> arrayLis;
int i = 0;
// Just start the first task without the loop.
double latitude = ((LatLng)arrayLis.get(i)).latitude;
double longitude = ((LatLng)arrayLis.get(i)).longitude;
String url = "https://api.darksky.net/forecast/APIKEY/"
+latitude+","+longitude+"?units=si";
LatLng mylatlng = new LatLng(latitude,longitude);
startProcess(url,mylatlng);
Now in the getCurrentDetails function, you might just have to do the following.
private void getCurrentDetails(String data,LatLng myLatlng) throws JSONException{
JSONObject main = new JSONObject(data);
double la = main.getDouble("latitude");
double lon = main.getDouble("longitude");
JSONObject currently = main.getJSONObject("currently");
String summary = currently.getString("summary");
double temperature = currently.getDouble("temperature");
String icon = currently.getString("icon");
LatLng latLngo = new LatLng(la,lon);
ter.add(latLngo);
weatherInfo.add(icon);
// Now initiate the next call
i++;
if(i < arrayLis.size()) getItAgain();
Log.i("LETSCHECK",""+la+", "+lon +icon);
}
public void getItAgain() {
// Just start the first task without the loop.
double latitude = ((LatLng)arrayLis.get(i)).latitude;
double longitude = ((LatLng)arrayLis.get(i)).longitude;
String url = "https://api.darksky.net/forecast/APIKEY/"
+latitude+","+longitude+"?units=si";
LatLng mylatlng = new LatLng(latitude,longitude);
startProcess(url,mylatlng);
}
Update
I do not understand why it is showing 2 instead of 4 results. However, I think you need to modify the code as follows.
private void getCurrentDetails(String data,LatLng myLatlng) throws JSONException {
JSONObject main = new JSONObject(data);
double la = main.getDouble("latitude");
double lon = main.getDouble("longitude");
JSONObject currently = main.getJSONObject("currently");
String summary = currently.getString("summary");
double temperature = currently.getDouble("temperature");
String icon = currently.getString("icon");
// Move this upto here
weatherInfo.add(icon);
loopi++;
Log.i("LETSCHECK",""+loopi);
if (loopi < arrayList.size()) {
getItAgain();
} else {
for (String l:weatherInfo) {
Log.i("LETSCHECK",l);
//expected 4 items to show but its showing only 2 items
}
}
}
You are running asynchronous code, and the reason that their callbacks are not returning one after the other is logical since each HTTP call takes some amount of time, unrelated to the others, so the response for your third call might actually be received before the first one.
You can either use RxJava (and its operators), or improve the current code. For your startProcess, pass the i from your for-loop as the index and create an array outside of our function. Whenever you get a response from the server, you can store it in the ith position of your array. After each call you can check If all values have been fetched (by a counter or something). It is much better to move all this stuff to its own class so its contained and testable.
One thing to note is how you are gonna handle errors, because your calls might not be received successfully.
This is a sample code. After each success call remove the current proceed item from the array and do a another API request.
private void startProcess(ArrayList<LatLong> elementList){
LatLong myLatlng = elementList.get(0);
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(myurl)
.build();
Call call = httpClient.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String data = response.body().string();
Log.i("DATASS",data);
if (response.isSuccessful()){
try {
getCurrentDetails(data,myLatlng);
elementList.remove(0)
startProcess(elementList)
}catch (JSONException e){
e.printStackTrace();
}
}
}
});
}
I want to add TokenID in member data form but I don't know how to add it.
private void registerUser() {
displayLoader();
JSONObject request = new JSONObject();
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(Dashboard.this, new OnSuccessListener < InstanceIdResult > () {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String newToken = instanceIdResult.getToken();
Log.e("newToken", newToken);
}
});
try {
//Populate the request parameters
request.put(KEY_USERNAME, username);
request.put(KEY_PASSWORD, password);
request.put("deviceID", newToken); // <--- token
} catch (JSONException e) {
e.printStackTrace();
}
[...]
How do I send TokenID together with the form?
Error:
error: cannot find symbol variable newToken
You are getting the following error:
error: cannot find symbol variable newToken
Because you are using the newToken String outside the scope that is initially defined. To solve this, just move that try-catch block inside the onSuccess() method right after this line of code:
Log.e("newToken", newToken);
And your problem will be solved.
My android app used the old microsoft Translator very well but I am having
problems getting the app to work with the new Cognitive Services.
First I got a new azure translation account that has the following values
(these are not the real values)
Name: MYTranslateAcct
Resource group: translate
subscription ID: 981h5ce7-7ac7-4f6f-b4a5-ff04dc9e4266
key1 d122230418a8479ab5c06f2f1fca664c
key2 39c1f187o9814f4e983jba9eedd2e2c7
My first step is to try to get a token. Microsoft has docs on doing
this in JAVA but not in an Android environment. I dug around and have
put together some code but it is not working. One problem is that the
docs use terms that I don't have in my account such as "app-id" and
"key". I don't have those things - I just have the list of values
above.
Here is my code . . .
class translateMessage extends AsyncTask<Void, Void, String>
{
String retString;
String inString = null;
translateMessage(String inString) { this.inString = inString; }
#Override
protected String doInBackground(Void... arg0)
{
try
{
String key = "881b5ce7-9ac7-4f6f-b4a5-ff04dc9e3199";
String authenticationUrl = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
HttpsURLConnection authConn = (HttpsURLConnection) new URL(authenticationUrl).openConnection();
authConn.setRequestMethod("POST");
authConn.setDoOutput(true);
authConn.setRequestProperty("Ocp-Apim-Subscription-Key", key);
IOUtils.write("", authConn.getOutputStream(), "UTF-8"); //following line of code gets the exception . . .
String token = IOUtils.toString(authConn.getInputStream(), "UTF-8"); //this blows
}
catch (Exception e)
{
String myString = e.getMessage();
String aString = "look at e";
}
return retString;
}
#Override
protected void onPostExecute(String result)
{
String debugStr = result;
translation.setText(result);
}
}
Following is the exception . . .
java.io.FileNotFoundException:https://api.cognitive.microsoft.com/sts/v1.0/issueToken
What am I doing wrong?
Is anyone aware of any working Android java code using the new services?
I posted this on Azure support and someone called me within an hour. I was passing the wrong key. When you get a translate cognitive account you get Key1 and Key2. Either of them will work. So the code is a useful example of working code that will get a token.
I have the following method in my Android app which I use for user login/registration.
public void registerUser(final String username, final String email, final String password) {
pDialog.setMessage("Signing Up...");
pDialog.show();
request = new StringRequest(Method.POST, SL_URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
pDialog.dismiss();
String[] split = s.split("Config.php");
String after = split[1];
try {
JSONObject jsonObject = new JSONObject(after);
boolean error = jsonObject.getBoolean("error");
if (error) {
String errorMsg = jsonObject.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
} else {
session.setLogin(true, username, email);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("tag", "login");
hashMap.put("username", name);
hashMap.put("password", password);
return hashMap;
}
};
queue.add(request);
}
Now I am writing my app for iOS and trying to replicate this in Swift. So far I have the following code:
let username = usernameTxt.text
let password = passwordTxt.text
let urlPath: String = "***"
let url: NSURL = NSURL(string: urlPath)!
let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
let stringPost="tag=login&username=" + username! + "&password=" + password! // Key and Value
NSLog(stringPost)
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody=data
request1.HTTPShouldHandleCookies=false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
var jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch _ {}
})
Now as someone new to iOS development and Swift in general, I have the following questions:
What is the best way to replicate the progressDialog I use in Java in Swift, it must be visible until the request is complete and then it should be dismissed. I'm guessing this should be placed in the completionHandler, however I'm not sure which UI element to use for the progress Dialog.
How do I obtain my response as a String and replicate the behaviour of the split function, and then convert the result of this into a jsonObject like I do in my Java code.
What is the best way to replicate the Toast used to show the error message. I don't think using a dialog which must be closed with a button would be optimal here.
Thank you.
I am also developing Applications for Android and IOS. Here i Answered your three Problems which is faced by me also as a beginner. I hope this would help you.
1) Use MBProgressHUD Link to replicate the progressDialog in Swift .There are two method to show and dismiss the progressDialog:
Use showLoadingHUD() before making HTTP request
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.labelText = "Loading..."
}
And hideLoadingHUD() after receiving the response from server
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
2) you can use Alamofire Link which can handle Network stuff And you can easily obtain response in String.
Example:
self.showLoadingHUD()
Alamofire.request(.GET, data, parameters: nil)
.response { (request, response, data, error) in
print(data) // if you want to check data in debug window.
let Result = NSString(data: data!, encoding: NSUTF8StringEncoding)
Result!.stringByReplacingOccurrencesOfString("\"", withString: "")
if(newResult == "1"){
self.navigationController!.popViewControllerAnimated(true)
JLToast.makeText("Success").show()
}
else if (newResult == "0"){
JLToast.makeText("Failed").show()
}
self.hideLoadingHUD()
3) mankee Toas are used for a purpose of displaying information for short period of time and disappear themselves. Here we can use Android like Toast which is JLToast. Available on github .
JLToast.makeText("Success").show()
I am trying to make this application in Android, I am getting data from foursquare's API in JSON format and I need to Parse it to present it in another intent.
I am using Android's volley library to get the JSON but the problem is the onResponse() function of JsonObjectRequest has no return parameter.so I cannot get the JSON object gotten from url outside of the the onResponse.
I haven't worked with volley before and hence don't know much about it, any help is appreciated. Here is the code that I am trying to make it work.
Edit: The main problem I'm facing is that I cannot assign a value to global variable in this case myPlaces inside the JsonObjectRequest's onResponse method. Or to be exact, the variable assigned inside means nothing outside, thus in the last line
Toast.makeText(MainActivity.this, myPlaces[2].getName(), Toast.LENGTH_LONG).show();
when I try to access the myPlaces[2] it gives me an null pointer exception.
Thanks.
public void onClick(View v) {
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(urlString, null, new com.android.volley.Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONObject meta = response.getJSONObject("meta");
String status = meta.getString("code");
Toast.makeText(MainActivity.this, status, Toast.LENGTH_SHORT).show();
if(status.equals("200"))
{
JSONObject responseJson = response.getJSONObject("response");
JSONArray venues = responseJson.getJSONArray("venues");
Places[] tempPlaces = new Places[venues.length()];
for (int i = 0 ; i < venues.length(); i++)
{
Places place = new Places();
JSONObject venueObject = venues.getJSONObject(i);
place.setName(venueObject.getString("name"));
JSONObject locatVenue = venueObject.getJSONObject("location");
place.setLat(locatVenue.getDouble("lat"));
place.setLon(locatVenue.getDouble("lng"));
tempPlaces[i] = place;
}
Toast.makeText(MainActivity.this, tempPlaces[2].getName(), Toast.LENGTH_LONG).show();
myPlaces = tempPlaces;
}
else
{
Toast.makeText(MainActivity.this, "No response from API", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "There is some error here", Toast.LENGTH_LONG).show();
}
}
}, new com.android.volley.Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "There has been some error", Toast.LENGTH_LONG).show();
}
});
requestQueue.add(jsonObjectRequest);
Toast.makeText(MainActivity.this, myPlaces[2].getName(), Toast.LENGTH_LONG).show();
Volley itself isn't an inner class; the response is an anonymous class.
You don't need a return in Volley, you just use the variables already defined in your class.
I'm assuming myPlaces is a field in your class? Otherwise, I'm not sure where it is declared outside the onClick..
This line assigns myPlaces and looks like it would work fine
myPlaces = tempPlaces;
You could define a method in your class to parse the whole JSONObject instead of needing to return from Volley. This just passes the logic to another method, so you don't need to think about "returning" inside Volley.
public void parseJSON(JsonObject object)
And pass the response from volley into that and do your normal parsing and variable assignment and you can Toast myPlaces inside that method.
Also, note that Volley is asynchronous, meaning you aren't guaranteed an immediate result, so
Toast.makeText(MainActivity.this, myPlaces[2].getName(), Toast.LENGTH_LONG).show();
Would likely have thrown either a NullPointerException or IndexOutOfBoundsException because myPlaces was either undeclared or empty before the Volley request. I say that because it does not appear to be assigned before the Volley request.