I'm using Volley in an Android App to fetch data from the Misfit API (http://build.misfit.com). I tried to construct an intermittent activity, after someone logged in, to get all the data from the API. In that activity, I perform a JsonObject GET request, that should give me some information about the user of the app. Here's the code so far:
package com.iss_fitness.myapplication;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import learn2crack.weboauth2.R;
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 500;
private static final String QUERY_URL = "https://api.misfitwearables.com/move/resource/v1/user/me/profile";
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
// Instantiate the RequestQueue.
final RequestQueue queue = Volley.newRequestQueue(this);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
executeJson();
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this, DataView.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
private Response.ErrorListener createRequestErrorListener() {
return new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
};
}
private void executeJson() {
SharedPreferences prefs = this.getSharedPreferences("AppPref", MODE_PRIVATE);
final String token = prefs.getString("token", null);
RequestQueue queue = Volley.newRequestQueue(this);
Map<String, String> params = new HashMap<String, String>();
System.out.println(token);
params.put("access_token", token);
CustomRequest jsonRequest = new CustomRequest(Request.Method.GET, QUERY_URL, params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
System.out.println(response);
}
}, this.createRequestErrorListener());
System.out.println(jsonRequest);
queue.add(jsonRequest);
}
}
I'm quite new to Android development, so please bear with me, I'll try to describe the code. I've implemented a help class as suggested for JsonObjectRequest, as, as I understood, you can't override the getparams method when defining a request locally. the executeJson() method is the interesting one: I get the user access token from my SharedPreferences (Where it's correctly stored), put that in a String Map and give that to the CustomRequest, where, inside the help class, it gets thrown into a getparams method that simply returns the params. The responselistener sadly never gets called, as the errorlistener reports the following:
com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found
According to the API reference of Misfit, that should work.
Now, I know that a GET request requires "headers" and not "params" but does that make any difference?
Okay, I found a solution. The helper class contained an overriding getparams method, but no getheaders method. GET request requires getheaders, post requires getparams.
Related
I'm quite new to Java/Android Studio and am spending the past two days figuring this out, without succes. I keep getting: Cannot resolve constructor 'JsonArrayRequest(int, java.lang.String, java.lang.String, anonymous com.android.volley.Response.Listener)'
On other threads I see answers that suggest to replace the null to a string or cast the null but this doesn't seem to make the trick.
I'm trying to read the JSON Array at https://www.smartvibes.be/profiles/api/profileview.php?id=5073 for instance.
This is my code:
package com.smartvibes.smartbeat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class profileViewActivity extends AppCompatActivity {
RequestQueue rs;
String url,id, nick, age, city, mainpic, numpics, extrapic0, extrapic1, extrapic2, extrapic3, extrapic4, extrapic5;
TextView profileIntro;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_view);
Bundle getProfileId = getIntent().getExtras();
if(getProfileId == null){
return;
}
String profileid = getProfileId.getString("profileid");
url = "https://www.smartvibes.be/profiles/api/profileview.php?id="+profileid;
rs = Volley.newRequestQueue(this);
sendjsonrequest();
profileIntro = (TextView) findViewById(R.id.profileIntro);
//profileIntro.setText(profileData.getPnick());
profileIntro.setText(profileid);
}
public void sendjsonrequest(){
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, url, "", new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
// Get current json Array
JSONArray profile = new JSONArray(response);
JSONObject jresponse = profile.getJSONObject(0);
Toast.makeText(profileViewActivity.this, "test", Toast.LENGTH_LONG).show();
nick = jresponse.getString("nick");
age = jresponse.getString("age");
city = jresponse.getString("city");
mainpic = jresponse.getString("mainpic");
numpics = jresponse.getString("numpics");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
rs.add(jsonArrayRequest);
}
}
When trying to run it I get:
error: no suitable constructor found for JsonArrayRequest(int,String,String,<anonymous Listener<JSONArray>>)
constructor JsonArrayRequest.JsonArrayRequest(String,Listener<JSONArray>,ErrorListener) is not applicable
(actual and formal argument lists differ in length)
constructor JsonArrayRequest.JsonArrayRequest(int,String,JSONArray,Listener<JSONArray>,ErrorListener) is not applicable
(actual and formal argument lists differ in length)
I'm probably doing something (or several things) bad... But can't figure out what.
You miss Response.ErrorListener()
Use this
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
// Get current json Array
JSONArray profile = new JSONArray(response);
JSONObject jresponse = profile.getJSONObject(0);
Toast.makeText(profileViewActivity.this, "test", Toast.LENGTH_LONG).show();
nick = jresponse.getString("nick");
age = jresponse.getString("age");
city = jresponse.getString("city");
mainpic = jresponse.getString("mainpic");
numpics = jresponse.getString("numpics");
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error){
// Do something when error occurred
Snackbar.make(
mCLayout,
"Error...",
Snackbar.LENGTH_LONG
).show();
}
}
);
Hope it's help
Everything seems fine in your codes except ErrorListener.
If you check the source of the JsonArrayRequest, you'll notice that it takes another method as the last parameter which handles the errors which you don't have it.
Simply, adding the Response.ErrorListener() right after the onResponse() method will solve the issue.
You can however make it null to ignore errors, which is not recommended.
Take a look: https://android--examples.blogspot.com/2017/02/android-volley-json-array-request.html
My weather app uses Openweathermap API. But i can only get forecast for the city I put in the code.
I want to add an option so the user types his city name and get the weather forecast for it.
I've added an EditText to the layout but don't know how to get the data from it and use as the city name input.
Here is my code:
package com.hamed.myapplication;
import android.content.Context;
import android.util.Log;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.hamed.myapplication.view.dataModel.WeatherInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by Hamed on 8/20/2017.
*/
public class ApiService {
private static final String TAG = "ApiService";
private Context context;
public ApiService (Context context){
this.context=context;
}
public void getCurrentWeather(final OnWeatherInfoRecieved onWeatherInfoRecieved, String cityName){
JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET,
"http://api.openweathermap.org/data/2.5/weather?q=ahvaz&apikey=01a477912e47daf2010808cc62015829",
null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG, "onResponse: "+response.toString());
onWeatherInfoRecieved.onRecieved(parseResponseToWeatherInfo(response));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse: "+error.toString());
onWeatherInfoRecieved.onRecieved(null);
}
});
request.setRetryPolicy(new DefaultRetryPolicy(8000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
RequestQueue requestQueue= Volley.newRequestQueue(context);
requestQueue.add(request);
}
private WeatherInfo parseResponseToWeatherInfo(JSONObject response){
WeatherInfo weatherInfo= new WeatherInfo();
try {
JSONArray weatherJsonArray= response.getJSONArray("weather");
JSONObject weatherJsonObject= weatherJsonArray.getJSONObject(0);
weatherInfo.setWeatherName(weatherJsonObject.getString("main"));
weatherInfo.setWeatherName(weatherJsonObject.getString("description"));
JSONObject mainJsonObject=response.getJSONObject("main");
weatherInfo.setWeatherTemperature((float)mainJsonObject.getDouble("temp"));
weatherInfo.setHumidity(mainJsonObject.getInt("humidity"));
weatherInfo.setPressure(mainJsonObject.getInt("pressure"));
weatherInfo.setMinTemperature((float)mainJsonObject.getDouble("temp_min"));
weatherInfo.setMaxTemperature((float)mainJsonObject.getDouble("temp_max"));
JSONObject windJsonObject=response.getJSONObject("wind");
weatherInfo.setWindSpeed((float)windJsonObject.getDouble("speed"));
weatherInfo.setWindDegree((float)windJsonObject.getDouble("deg"));
return weatherInfo;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
public interface OnWeatherInfoRecieved {
void onRecieved(WeatherInfo weatherInfo);
}
}
Edit:
My app has a button to request data from server. I want the user to type his city name in the EditText and the API address use that city name in it...
Someone told me I have to use the EditText value as QueryString and give it to the API.
Does anyone know how to do this?
To get value from EditText:
EditText edit = (EditText) view.findViewById("myEditText");
String city = edit.getText().toString();
Is that what you're looking for?
To add city selection, you would have to call the remote openweathermap service and retrieve the cities.
For Openweathermap API, you can refer to this tutorial, which explains in detail how to add the city search option in your weather app. The final source code for it is on Github here. You can take a look in the XML file and the Java Class specifically for the city selection in the sample application source code.
I am very new to Android, it would be great if you could help me with the error "Cannot resolve symbol ..." in the variables:
- value 1
- banner_id
- full_id
My code is the following:
package com.example.sienstranslation.siensapp;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.android.gms.appdatasearch.GetRecentContextCall;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class Main3Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
Intent intent=getIntent();
double precio = intent.getExtras().getDouble("precio");
String precio_rounded = String.format("%.2f", precio);
TextView txtCambio = (TextView) findViewById(R.id.textView4);
txtCambio.setText("Precio Total: "+ precio_rounded + " €");
}
void MakePostRequest() {
String posting_url ="http://ipaddress/app.php";
// its your url path ok
StringRequest postRequest = new StringRequest(Request.Method.POST, posting_url ,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
value1= jsonResponse.getString("precio_rounded");
} catch (JSONException e) {
e.printStackTrace();
banner_id = null;
full_id = null;
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
value1= null;
}
}
) {
// here is params will add to your url using post method
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("app", getString(R.string.app_name));
//params.put("2ndParamName","valueoF2ndParam");
return params;
}
};
Volley.newRequestQueue(this).add(postRequest);
}
Thank you very much for your time
At first , Declare banner_id & full_id ;
public class Main3Activity extends AppCompatActivity {
public int banner_id,full_id;
Then Clean-Rebuild Your Project .
It is a bad idea to start directly with Android ... when you don't have any clue about java itself. In your program, you are using those three variables without ever declaring them before. That is what the compiler is telling you. That is super basic stuff.
So I seriously recommend you to step back; and study those java basics for some more time. Otherwise your programming experience will be nothing else but a (probably short) series of very frustrating moments.
This is not meant to be rude; but it looks like you intend to build a skyscraper; but you actually have no idea how to dig the hole for the basement. That is simply not a very rewarding or efficient approach to get things done.
And you see, your follow-on comments to the answers ... just prove my point. Your current approach is nothing but trial-and-error. And just to be precise: the Android java programming model is itself something that can drive experienced java programmers nuts.
You must declare all variables before they can be used. The basic form of a variable declaration is shown here:
data type variable [ = value][, variable [= value] ...] ;
I am trying to query an API to get the JSON response and store the response in an ArrayList.
This ArrayList will be later used for setting up a RecyclerView.
I am getting the response if I Log in the OnResponse() method from OkHttp. But when I am receiving the response in my Fragment as a String via the return in the OkhttpHandler then the string value is being received as null
Here's the code
OkHttpHelper.Java
package com.execube.genesis.utils;
import android.util.Log;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class OkHttpHandler {
private String queryUrl;
private String jsonData;
private static final String TAG = "CustomTAG1";
public OkHttpHandler(String Url) {
this.queryUrl = Url;
}
public String fetchData() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(queryUrl)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.v(TAG, "Exception: ", e);
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.v(TAG, response.body().string());
if (response.isSuccessful()) {
jsonData = response.body().string();
}
}
});
return jsonData; //Even this is null when I check via Debugger
}
}
PopularMoviesFragment.java
package com.execube.genesis.views;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.execube.genesis.R;
import com.execube.genesis.model.Movie;
import com.execube.genesis.utils.API;
import com.execube.genesis.utils.OkHttpHandler;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class PopularMoviesFragment extends Fragment {
private static final String TAG = "CustomTAG";
private ArrayList<Movie> mMovies;
private String jsonResponse;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
mMovies=new ArrayList<>();
String url= API.BASE_URL+API.API_KEY+API.SORT_POPULARITY;
OkHttpHandler handler= new OkHttpHandler(url);
jsonResponse=handler.fetchData();
try {
mMovies= parseItems(jsonResponse);
} catch (JSONException e) {
Log.v(TAG,"Exception caught: ",e);
}
super.onCreate(savedInstanceState);
}
private ArrayList<Movie> parseItems( String jsonResponse) throws JSONException{
JSONObject jsonData= new JSONObject(jsonResponse);
JSONArray moviesJSONArray= jsonData.getJSONArray("results");
ArrayList<Movie> Movies= new ArrayList<>();
for (int i = 0; i <moviesJSONArray.length() ; i++) {
Movie movie= new Movie();
JSONObject movieJson= moviesJSONArray.getJSONObject(i);
movie.setId(movieJson.getInt("id"));
Log.v(TAG,"TITLE IS "+movieJson.getString("title"));
movie.setOriginalTitle(movieJson.getString("original_title"));
movie.setOverview(movieJson.getString("overview"));
movie.setPosterPath(movieJson.getString("poster_path"));
movie.setVoteAverage((float) movieJson.getDouble("vote_average"));
movie.setTitle(movieJson.getString("title"));
Movies.add(movie);
}
return Movies;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_popular_movies,container,false);
return view;
}
}
API.java for building the url
package com.execube.genesis.utils;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class API {
public static String BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
public static String MOVIE_BASE_URL = "http://api.themoviedb.org/3/movie/";
public static String API_KEY = "api_key=a98debe57ccd9b42fe6b99b9014c80e3";
public static String SORT_POPULARITY = "&sort_by=popularity.desc";
public static String SORT_R_RATED = "&certification_country=US&certification=R&sort_by=vote_average.desc&vote_count.gte=250";
public static String IMAGE_URL = "http://image.tmdb.org/t/p/";
public static String IMAGE_SIZE_185 = "w500";
}
Here's the URL that I am querying http://api.themoviedb.org/3/discover/movie?api_key=a98debe57ccd9b42fe6b99b9014c80e3&sort_by=popularity.desc
Call#enqueue is OkHttp's asynchronous API. This means the request will be handled on a background thread and the calling thread will continue to run with OR without running the callback.
To use the data you either need to use some form of Future (Guava's ListenableFuture or RxJava might work) to respond to the eventual availability of the data or use Call#execute() instead of Call#enqueue to do the call in a synchronous way.
The thing is, you're accessing the variable jsonData before the network operation can finish and put something in it.
Which is very unlikely to happen.
Use something like an Event Bus (I like Green Robot's), and post an event when the jsonData has something, right after the line jsonData = response.body().string();
And listen to this event in your UI fragment, and populate data once you receive this event.
Till then, keep showing the progress dialog/UI.
This way your code will remain async and you'll get this done as well
I have a few asynstask that are definined inside of my main activity. I tried to make the code more modular by putting each one of these classes on a separate file. Unfortunately I keep getting some errors such as not being able to get the intents to work. How do I connect this code with my main activity. By the way if I place this code as is(without the imports) in the mainActivity it works just fine. Thanks
package com.example.food4thought;
import java.net.URL;
import twitter4j.TwitterException;
import twitter4j.auth.RequestToken;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
// Starts an intent that loads up a web browser and asks the user to log in to twitter
// and get a pin#
public class TwitterLogin extends AsyncTask<URL, Integer, RequestToken> {
protected RequestToken doInBackground(URL... arg0) {
try {
requestToken = twitter.getOAuthRequestToken();
Log.i("Got Request Token", "food4thought");
} catch (TwitterException e) {
Log.i("Failed to get Request Token", "food4thought");
}
//Log.i(requestToken.getAuthorizationURL(), "food4thought");
//requestToken.getAuthorizationURL();
//log_in.setText();
try {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(requestToken.getAuthorizationURL()));
startActivity(browserIntent);
}
catch(NullPointerException e) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Unable to log in, No access to the Internet.", Toast.LENGTH_LONG).show();
}
});
}
return null;
}
}
To do that you need to understand what dependencies your AsyncTask has.
To fire Intents you need Context intance. I also see some twitter variable.
So you need declare appropriate fields and to pass those objects to your TwitterLogin constructor.
Something like that:
public class TwitterLogin extends AsyncTask<URL, Integer, RequestToken> {
private Context context;
//other fields here
public TwitterLogin(Context context, ...){ // other variables here
this.context = context;
//other fields assignment
}
}
Later you can fire Intent:
context.startActivity(browserIntent);
What's important to understand is that all those methods like startActivity are not some "global functions", rather they are methods of some class instance, and you can't just call those methods from AsycTask instance.