I'm having problems querying Flickr REST API for searching photos:
https://www.flickr.com/services/api/explore/flickr.photos.search
I'm writing a small test app in Android using HttpURLConnection and I do not want to use any frameworks (such as OkHttp etc.) as this is just simple learning exercise.
The problem that I am having is that although my HttpURLConnection returns a 200, there is no JSON response. But when I take the constructed REST URL from my logs, for example:
https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=API_KEY&tags=basketball&format=json&nojsoncallback=1&api_sig=API_SIG
and copypaste it to a browser, I can see proper JSON.
This is A snippet of the JSON that the browser returns:
{"photos":{"page":1,"pages":2614,"perpage":100,"total":"261380","photo":[{"id":"39168832065","owner":"23023080#N02","secret":"1fb9ee772a","server":"4615","farm":5,"title":"_MG_2714_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194325488","owner":"23023080#N02","secret":"3bc00e37ee","server":"4656","farm":5,"title":"_MG_2719_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"39168829925","owner":"23023080#N02","secret":"15580858ce","server":"4695","farm":5,"title":"_MG_2723_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194323798","owner":"23023080#N02","secret":"c5e445bd6e","server":"4743","farm":5,"title":"_MG_2727_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"39168828415","owner":"23023080#N02","secret":"89b54b28bc","server":"4648","farm":5,"title":"_MG_2729_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194322658","owner":"23023080#N02","secret":"7eff365389","server":"4648","farm":5,"title":"_MG_2732_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"39168826725","owner":"23023080#N02","secret":"2eda660b60","server":"4723","farm":5,"title":"_MG_2734_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194321108","owner":"23023080#N02","secret":"0c794e38a8","server":"4765","farm":5,"title":"_MG_2735_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40034887842","owner":"23023080#N02","secret":"6269997f0f","server":"4755","farm":5,"title":"_MG_2737_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194319778","owner":"23023080#N02","secret":"32991c9151","server":"4763","farm":5,"title":"_MG_2739_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194319168","owner":"23023080#N02","secret":"4dd5555f5c","server":"4709","farm":5,"title":"_MG_2746_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40034885802","owner":"23023080#N02","secret":"3f9c5031db","server":"4671","farm":5,"title":"_MG_2747_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"26194317818","owner":"23023080#N02","secret":"e20b503f8f","server":"4668","farm":5,"title":"_MG_2757_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40067785161","owner":"23023080#N02","secret":"4ab87667fd","server":"4612","farm":5,"title":"_MG_2760_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40034884132","owner":"23023080#N02","secret":"235b7dc32d","server":"4744","farm":5,"title":"_MG_2762_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40067784231","owner":"23023080#N02","secret":"0bbae58322","server":"4622","farm":5,"title":"_MG_2763_edit","ispublic":1,"isfriend":0,"isfamily":0},{"id":"40034882942","owner":"23023080#N02","secret":"30345b6b7b","server":"4626","farm":5,"title":"_MG_2764_edit","ispublic":1,"isfriend":0,"isfamily":0},
Why is the code not getting/reading the JSON from connection's input stream?
package com.bing.ary.xyz;
import android.os.AsyncTask;
import android.util.Log;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.net.ssl.HttpsURLConnection;
import java.net.URL;
public class SearchFlickerAsync extends AsyncTask<String, Void, flikrPhotosResponse> {
private static final String TAG = "SearchFlickerAsync";
private String query;
public SearchFlickerAsync(String query) {
this.query = query;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected flikrPhotosResponse doInBackground(String... query) {
Log.i(TAG,"doInBackground(), SearchFlickerAsync input param:"+query);
HttpsURLConnection httpURLConnection = null;
flikrPhotosResponse FlikrPhotosResponse = null;
JsonElement jsonElemnt = null;
JsonObject jsonObject = null;
String queryUrl = null;
StringBuilder queryBuilder = null;
try {
//create url string
queryBuilder = new StringBuilder();
queryBuilder.append(flickerApi.baseUrl);
queryBuilder.append(flickerApi.searchFlicker);
queryBuilder.append(flickerApi.flickrQuery_key + flickerApi.Key);
queryBuilder.append(flickerApi.flickrQuery_tag);
queryBuilder.append(this.query);
queryBuilder.append("&format=json");
queryBuilder.append("&nojsoncallback=1&api_sig=be97f5275f5a128fbe69dc2cde2560b9");
//instantiate url for connection
URL url = new URL(queryBuilder.toString());
httpURLConnection = (HttpsURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setUseCaches(false);
httpURLConnection.setAllowUserInteraction(false);
httpURLConnection.setRequestProperty("Content-length", "0");
httpURLConnection.connect();
//no authorization token needed public API httpURLConnection.setRequestProperty("Authorization", "");
Log.i(TAG,"doInBackground(), http request:"+url.toString());
int status = httpURLConnection.getResponseCode();
switch (status) {
case 200:
case 201:
Log.i(TAG,"doInBackground(), http response status:"+status);
BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
Log.i(TAG,"doInBackground(), http response line:"+line);
jsonElemnt = new JsonParser().parse(sb.toString());
jsonObject = jsonElemnt.getAsJsonObject();
/*Further parse & instantiate FlikrPhotosResponse = */
br.close();
break;
//TODO: ERRORS https://www.flickr.com/services/api/flickr.groups.search.html
default:
Log.e(TAG,"doInBackground(), http response error status:"+status);
//TODO: handle error responses
break;
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (httpURLConnection != null) {
try {
httpURLConnection.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
return FlikrPhotosResponse;
}//end doInBackgroud
protected void onPostExecute(flikrPhotosResponse FlikrPhotosResponse) {
Log.i(TAG,"onPostExecute(), FlikrPhotosResponse:"+FlikrPhotosResponse);
}
}//end class
Relevant logs there is no errpr or exception:
02-04 13:24:12.037 3750-4270/com.bing.ary.skywelltest I/SearchFlickerAsync: doInBackground(), http request:https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=37ae86d629a2e4a62917253419cb9e94&tags=basketball&format=json&nojsoncallback=1&api_sig=be97f5275f5a128fbe69dc2cde2560b9
02-04 13:24:12.220 3750-4270/com.bing.ary.skywelltest I/SearchFlickerAsync: doInBackground(), http response status:200
02-04 13:24:12.221 3750-4270/com.bing.ary.skywelltest I/SearchFlickerAsync: doInBackground(), http response line:null
I also
You're logging the wrong thing:
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
Log.i(TAG,"doInBackground(), http response line:"+line);
Of course line is null at this point. That's why the loop terminated. You should be logging sb.toString().
NB:
You don't need any of the following:
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("Content-length", "0");
httpURLConnection.connect();
The numerous claims in comments that you need to use HttpsURLConnection are not correct. Using HttpURLConnection is perfectly valid even if the URL is an HTTPS one, as long as you don't need the extra methods of HttpsURLConnection, as HttpsURLConnection extends HttpURLConnection.
We've been trying to send a POST request to a node.js server in an android app. Because the old apache dependencies are deprecated (and I can't seem to access them - I've tried) we've been using the HttpURLConnection classes. We've coded a class in java that works as just a standalone class (Request.java) but when incorperated in the android program, it throws an error every time and when trying to get the message of the error, it just returns null.
Request.java
package andrewmmattb.beacongame;
/**
* Created by matt on 05/03/2016.
*/
import java.net.HttpURLConnection;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class Request {
public static void main(String[] args) throws Exception {
Request http = new Request();
System.out.println("POST");
http.sendPost("{\"username\": \"matt\",\"newPoints\":5}");
}
public static void sendPost(String json) throws Exception {
String url = "http://ec2-54-187-69-193.us-west-2.compute.amazonaws.com/points";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Content-Type", "application/json");
String urlParameters = "";
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(json);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + urlParameters);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
}
}
GameActivity.java
package andrewmmattb.beacongame;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Intent;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.util.Base64;
import android.util.JsonWriter;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import org.json.*;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class GameActivity extends Activity {
String username;
String serverPath = "THE PATH TO THE SERVER";
int score = 0;
int prevScore = 0;
TextView usernameTextView;
TextView scoreTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
usernameTextView = (TextView)findViewById(R.id.textViewGameUsername);
scoreTextView = (TextView)findViewById(R.id.textViewGameScore);
Intent intent = getIntent();
username = intent.getStringExtra("username");
usernameTextView.setText(username);
try {
makeSeverPost();
}
catch (IOException e) {
Toast.makeText(GameActivity.this,"There was an IO error, called after function call (line 56)",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
void makeSeverPost() throws IOException {
// creates a map object with username and the additional points to the previous sent score
Map<String,Object> values = new HashMap<String,Object>();
values.put("username",username);
values.put("newPoints",score-prevScore);
// sets the previous score to equal the current score
prevScore = score;
// writes the map into a string in JSON format
String jsonString = new JSONObject(values).toString();
try {
Request.sendPost(jsonString);
} catch (Exception e) {
e.printStackTrace();
Log.e("problem",""+e.getMessage());
}
}
}
There are many redundant dependancies due to all the other attempts to do this we've made.
In android network on main thread are not allowed.
You have to call this method from an AsyncTask.
Example:
class MakeSeverPostTask extends AsyncTask<Void, String, JSONObject>
{
Map<String,Object> params;
public MakeSeverPostTask(Map<String,Object> params){
this.params = params;
}
protected JSONObject doInBackground(Void... v)
{
String jsonString = new JSONObject(this.params).toString();
return Request.sendPost(jsonString);
}
protected void onPostExecute(JSONObject result)
{
}
}
Usage:
Map<String,Object> values = new HashMap<String,Object>();
values.put("username",username);
values.put("newPoints",score-prevScore);
new MakeSeverPostTask(values).execute();
Here is more elaborated solution:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
usernameTextView = (TextView)findViewById(R.id.textViewGameUsername);
scoreTextView = (TextView)findViewById(R.id.textViewGameScore);
// creates a map object with username and the additional points to the previous sent score
Map<String,Object> values = new HashMap<String,Object>();
values.put("username",username);
values.put("newPoints",score-prevScore);
// writes the map into a string in JSON format
String jsonString = new JSONObject(values).toString();
String url = "http://ec2-54-187-69-193.us-west-2.compute.amazonaws.com/points";
// executing AsyncTask with passing string parameters.
ServerAsyncTask makeServerPost = new ServerAsyncTask();
makeServerPost.execute(url, jsonString);
}
private class ServerAsyncTask extends AsyncTask<String, Void, JSONObject> {
private final String TAG = ServerAsyncTask.class.getSimpleName();
#Override
protected JSONObject doInBackground(String... params) {
JSONObject result = null;
try {
URL obj = new URL(params[0]); // added url
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Content-Type", "application/json");
String urlParameters = "";
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(params[1]); // Added json
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
Log.i(TAG, "\nSending 'POST' request to URL : " + params[0]);
Log.i(TAG, "Post parameters : " + urlParameters);
Log.i(TAG, "Response Code : " + responseCode);
// safer way to parse response
if(responseCode == HttpURLConnection.HTTP_OK){
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
Log.i(TAG, response.toString());
result = new JSONObject(response.toString());
}
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
/* You get response jsonObject here,
you can now update your UI here*/
// Example update your score.
try {
String score = (String) jsonObject.get("score");
scoreTextView.setText(score);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
I am trying to pass JSON object from android app using HTTP post to heroku server and then get it back, but I keep getting response code : 404, I don't know if the problem is from the client side or the server side, here is the client side HTTP connection :
class JsonAsyncTask extends AsyncTask<Void, Void, String> {
private final String USER_AGENT = "Mozilla/5.0";
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... params) {
try {
String url = "https://jce-blb.herokuapp.com/test";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-type", "application/json");
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "Android");
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(String content) {
}
}
And this is server side in heroku, I used java :
import java.sql.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Map;
import java.net.URI;
import java.net.URISyntaxException;
import static spark.Spark.*;
import spark.template.freemarker.FreeMarkerEngine;
import spark.ModelAndView;
import static spark.Spark.get;
import com.heroku.sdk.jdbc.DatabaseUrl;
public class Main {
public static void main(String[] args) {
port(Integer.valueOf(System.getenv("PORT")));
staticFileLocation("/public");
get("/test", (req,res) -> {
return "im back";
});
}
}
The client sends a POST request to /test but the server only defines a GET handler for that route. (Imho the server should responds with a 405 method not allowed, but maybe this is how Spark responds).
Therefore try to also define a handler for POST requests.
i followed a tutorial of login/register on android studio (toni kami tutorial) , i did all of what he did , but the httpclient /httpparams method is no longer working on android studio , im new to app programming so i searched the internet for a way to work this problem , i found a url connection code , i copy it but its not working .
****** this is all the java class ******
------ help me by correcting this or give me a new idea to work it out ------
when i run the app i get this :
package com.thenewboston.loginr;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* Created by sleeman on 1/1/16.
*/
public class ServerRequests {
ProgressDialog progressDialog;
public static final int CONNECTION_TIMEOUT = 1000 * 15;
public static final String SERVER_ADDRESS = "http://sleemanb94.tk/";
public ServerRequests(Context context){
progressDialog = new ProgressDialog(context);
progressDialog.setCancelable(false);
progressDialog.setTitle("Processing");
progressDialog.setMessage("Please Wait...");
}
public void storeUserDataInBackground(User user, getUserCallBack userCallback){
progressDialog.show();
new StoreUserDataAsyncTask(user,userCallback).execute();
}
public void fetchUserDataInBackground(User user, getUserCallBack callback) {
progressDialog.show();
new fetchUserDataAsyncTask(user, callback).execute();
}
public class StoreUserDataAsyncTask extends AsyncTask<Void, Void, Void>{
User user;
getUserCallBack userCallback;
public StoreUserDataAsyncTask(User user, getUserCallBack userCallback){
this.user = user;
this.userCallback = userCallback;
}
#Override
protected Void doInBackground(Void... params) {
Map<String,String> dataToSend = new HashMap<>();
dataToSend.put("fname", user.fname);
dataToSend.put("lname", user.lname);
dataToSend.put("email", user.email);
dataToSend.put("password", user.password);
//Server Communication part - it's relatively long but uses standard methods
//Encoded String - we will have to encode string by our custom method (Very easy)
String encodedStr = getEncodedData(dataToSend);
//Will be used if we want to read some data from server
BufferedReader reader = null;
//Connection Handling
try {
//Converting address String to URL
URL url = new URL(SERVER_ADDRESS + "Register.php");
//Opening the connection (Not setting or using CONNECTION_TIMEOUT)
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//Post Method
con.setRequestMethod("POST");
//To enable inputting values using POST method
//(Basically, after this we can write the dataToSend to the body of POST method)
con.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream());
//Writing dataToSend to outputstreamwriter
writer.write(encodedStr);
//Sending the data to the server - This much is enough to send data to server
//But to read the response of the server, you will have to implement the procedure below
writer.flush();
//Data Read Procedure - Basically reading the data comming line by line
StringBuilder sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while((line = reader.readLine()) != null) { //Read till there is something available
sb.append(line + "\n"); //Reading and saving line by line - not all at once
}
line = sb.toString(); //Saving complete data received in string, you can do it differently
//Just check to the values received in Logcat
Log.i("custom_check", "The values received in the store part are as follows:");
Log.i("custom_check",line);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(reader != null) {
try {
reader.close(); //Closing the
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
private String getEncodedData(Map<String,String> data) {
StringBuilder sb = new StringBuilder();
for(String key : data.keySet()) {
String value = null;
try {
value = URLEncoder.encode(data.get(key), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if(sb.length()>0)
sb.append("&");
sb.append(key + "=" + value);
}
return sb.toString();
}
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
userCallback.done(null);
super.onPostExecute(aVoid);
}
}
public class fetchUserDataAsyncTask extends AsyncTask<Void, Void, User> {
User user;
getUserCallBack userCallback;
public fetchUserDataAsyncTask(User user, getUserCallBack userCallback) {
this.user = user;
this.userCallback = userCallback;
}
#Override
protected User doInBackground(Void... params) {
//Use HashMap, it works similar to NameValuePair
Map<String, String> dataToSend = new HashMap<>();
dataToSend.put("email", user.email);
dataToSend.put("password", user.password);
//Server Communication part - it's relatively long but uses standard methods
//Encoded String - we will have to encode string by our custom method (Very easy)
String encodedStr = getEncodedData(dataToSend);
//Will be used if we want to read some data from server
BufferedReader reader = null;
//Connection Handling
User returnedUser = null;
try {
//Converting address String to URL
URL url = new URL(SERVER_ADDRESS + "FetchUserData.php");
//Opening the connection (Not setting or using CONNECTION_TIMEOUT)
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//Post Method
con.setRequestMethod("POST");
//To enable inputting values using POST method
//(Basically, after this we can write the dataToSend to the body of POST method)
con.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream());
//Writing dataToSend to outputstreamwriter
writer.write(encodedStr);
//Sending the data to the server - This much is enough to send data to server
//But to read the response of the server, you will have to implement the procedure below
writer.flush();
//Data Read Procedure - Basically reading the data comming line by line
StringBuilder sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while ((line = reader.readLine()) != null) { //Read till there is something available
sb.append(line + "\n"); //Reading and saving line by line - not all at once
}
line = sb.toString(); //Saving complete data received in string, you can do it differently
//Just check to the values received in Logcat
Log.i("custom_check", "The values received in the store part are as follows:");
Log.i("custom_check", line);
returnedUser = new User( user.fname, user.lname);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close(); //Closing the
} catch (IOException e) {
e.printStackTrace();
}
}
}
return returnedUser;
}
#Override
protected void onPostExecute(User returnedUser) {
progressDialog.dismiss();
userCallback.done(returnedUser);
super.onPostExecute(returnedUser);
}
private String getEncodedData(Map<String, String> data) {
StringBuilder sb = new StringBuilder();
for (String key : data.keySet()) {
String value = null;
try {
value = URLEncoder.encode(data.get(key), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (sb.length() > 0)
sb.append("&");
sb.append(key + "=" + value);
}
return sb.toString();
}
}
}
HttpClient is deprecated. But you can use it in android studio easily
Check this answer
I've been working on an open source code of a Twitter reader (read only) (oauth 2.0) that pulls JSON from a user timeline. It successfully pulls the JSON from Twitter API 1.1. The challenge I'm facing is converting that JSON into something user friendly. I've implemented sections of another source code that focused on parsing the JSON, but I'm not very familiar with parsing JSON. It's patchwork so I know I might be overlooking something. Possibly a redundancy or missing part.
UPDATED:
When I run the app, it doesn't crash, it's just stuck at "Got Token!". What I'm hoping to display is a list of tweets somewhat formatted to look like one. I believe it's the MainActivity, but I could be wrong. You will need a Consumer Key and Secret to test. I'll put up what I have at the moment, but if anyone knows how I can get out of that loop, I'd appreciate your input.
Thanks!
MainActivity.java
package com.example.readtwitterfeed;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.json.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.JSONValue;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Base64;
import android.util.Log;
import android.widget.TextView;
import com.example.readtwitterfeed.R;
public class MainActivity extends Activity {
// CONSUMER API KEY - 21 characters (go here to get one: https://dev.twitter.com/apps/)
// **** CHANGE THIS ****
static final String twitterAPIKEY = "################";
// CONSUMER SECRET - 41 characters (go here to get one: https://dev.twitter.com/apps/)
// **** CHANGE THIS ****
static final String twitterAPISECRET = "###############################";
static final String twitterAPIurl = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=";
// Twitter 'Screen Name'
// **** CHANGE THIS ****
static final String screenName = "Insert_Username_Here";
// Tweets to return
// **** CHANGE THIS, if needed ****
static final int tweets2Return = 1;
// Final URL will look like this (# is your sreen name/return tweets):
// https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=###&include_rts=1&count=#
static String tweeterURL = twitterAPIurl + screenName
+ "&include_rts=1&count=" + tweets2Return;
static String twitterToken = null;
static String jsonTokenStream = null;
static String jsonFeed = null;
static String tweetJSON = null;
TextView twitterText;
// ////////////////////////////////////
// onCreate - Let's get the GUI going
// ////////////////////////////////////
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
twitterText = (TextView) findViewById(R.id.tweetFeed);
// Call first AsyncTask
new loadTwitterToken().execute();
}
// ////////////////////////////////////////////////////////////////////
// AsyncTask - First, let's get our Token for oAuth (from Twitter)
// If you need oAuth help: https://dev.twitter.com/docs/auth/oauth/faq/
// ////////////////////////////////////////////////////////////////////
protected class loadTwitterToken extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
//As of this writing, Twitter says, "We do not currently expire access tokens."
try {
DefaultHttpClient httpclient = new DefaultHttpClient(
new BasicHttpParams());
HttpPost httppost = new HttpPost(
"https://api.twitter.com/oauth2/token");
String apiString = twitterAPIKEY + ":" + twitterAPISECRET;
String authorization = "Basic "
+ Base64.encodeToString(apiString.getBytes(),
Base64.NO_WRAP);
httppost.setHeader("Authorization", authorization);
httppost.setHeader("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
httppost.setEntity(new StringEntity(
"grant_type=client_credentials"));
InputStream inputStream = null;
// Let's send to web
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
// Our response
inputStream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
// Will look like this:
// {"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAAAABiQTgAAAAAACGie2o%2Bm7jNnxw8txVG99c1wAU8%3DmZq7qrX8JZpDFrgYyh5gLtOkJhQ7BvPD6bZ0ssitjg"}
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
jsonTokenStream = sb.toString();
// onPostExecute likes to get a parameter passed to work right.
// Just passing something.
return 1;
} catch (Exception e) {
Log.e("loadTwitterToken",
"doInBackground Error:" + e.getMessage());
return null;
}
}
#Override
protected void onPostExecute(Integer result) {
// Extract Token from JSON stream
try {
JSONObject root = new JSONObject(jsonTokenStream);
twitterToken = root.getString("access_token");
} catch (Exception e) {
Log.e("loadTwitterToken", "onPost Error:" + e.getMessage());
}
twitterText.setText("Got Token!");
// Now that we have a oAuth Token, lets get our JSON feed from twitter.
// We call it from here to make sure the Token has been received already.
new loadTwitterFeed().execute();
}
}
// ///////////////////////////////////////////////////////////
// AsyncTask - Download Twitter Feed w/Token as authorization
// //////////////////////////////////////////////////////////
protected class loadTwitterFeed extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
BufferedReader reader =null;
try{
DefaultHttpClient httpclient = new DefaultHttpClient(
new BasicHttpParams());
HttpGet httpget = new HttpGet(tweeterURL);
httpget.setHeader("Authorization", "Bearer " + twitterToken);
httpget.setHeader("Content-type", "application/json");
InputStream inputStream = null;
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
reader = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"), 8);
return null;
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
if (reader != null)
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
protected void onPostExecute(String result) {
StringBuilder sb = new StringBuilder();
try{
JSONObject resultObject = new JSONObject(result);
org.json.JSONArray tweetArray = resultObject.getJSONArray("results");
for (int t=0; t<tweetArray.length(); t++) {
JSONObject tweetObject = tweetArray.getJSONObject(t);
sb.append(tweetObject.getString("from_user")+": ");
sb.append(tweetObject.get("text")+"\n\n");
}
}
catch (Exception e) {
Log.e("Tweet", "Error retrieving JSON stream" + e.getMessage());
jsonFeed = sb.toString();
e.printStackTrace();
}
}
}
/*String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}*/
protected void onPostExecute(Integer result) {
// Update GUI
if (jsonFeed.length() > 0) {
twitterText.setText(jsonFeed);
} else {
//I'd assume wrong Consumer Key/Secret if this happens.
twitterText.setText("Nothing Returned");
}
}
}
Activity_Main.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/tweetFeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Loading..." />
</ScrollView>
You forgot to close the ProgressDialog in onPostExecute method.
just do this pd.dismiss(); in onPostExecute like this.
#Override
protected void onPostExecute(Integer result) {
pd.dismiss();
// Extract Token from JSON stream
try {
JSONObject root = new JSONObject(jsonTokenStream);
twitterToken = root.getString("access_token");
} catch (Exception e) {
Log.e("loadTwitterToken", "onPost Error:" + e.getMessage());
}
twitterText.setText("Got Token!");
// Now that we have a oAuth Token, lets get our JSON feed from twitter.
// We call it from here to make sure the Token has been received already.
new loadTwitterFeed().execute();
}