Android TabLayout and using LoaderCallbacks to populate a Fragment - java

So I'm working on an assignment where I have to create a TabLayout representing different categories of news, where the news is retrieved using the Bing search API and the JSON is parsed and used to populate the ListView in the three Fragments that make up the TabLayout. I'm also using a ViewPager.
My issue is that for some reason, the content of all three Fragments is the same... same article results. Why is this? I'm using Loader IDs, and the loader is initialized in the onActivityCreated() method. Is there a way I can load the articles relevant to the current Fragment when the user swipes over to that tab?
Here are the relevant methods of my Fragments. They're almost identical in each Fragment, with the exception of the LOADER_ID and CATEGORY_NAME values.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Get a reference to the ConnectivityManager to check state of network connectivity
ConnectivityManager connMgr = (ConnectivityManager)
getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
// Get details on the currently active default data network
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// If there is a network connection, fetch data
if (networkInfo != null && networkInfo.isConnected()) {
// Get a reference to the LoaderManager, in order to interact with loaders.
LoaderManager loaderManager = getLoaderManager();
// Initialize the loader. Pass in the int ID constant defined above and pass in null for
// the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
// because this activity implements the LoaderCallbacks interface).
loaderManager.initLoader(WorldFragment.LOADER_ID, null, this);
} else {
// Otherwise, display error
// First, hide loading indicator so error message will be visible
View loadingIndicator = getActivity().findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Update empty state with no connection error message
mEmptyStateTextView.setText(R.string.no_internet_connection);
}
}
#Override
public Loader<List<Article>> onCreateLoader(int id, Bundle args) {
return new ArticleLoader(this.getContext(), WorldFragment.CATEGORY_NAME);
}
#Override
public void onLoadFinished(Loader<List<Article>> loader, List<Article> articles) {
// Hide loading indicator because the data has been loaded
View loadingIndicator = getActivity().findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Set empty state text to display "No articles found."
mEmptyStateTextView.setText(R.string.no_articles);
// Clear the adapter of previous earthquake data
adapter.clear();
// If there is a valid list of {#link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (articles != null && !articles.isEmpty()) {
adapter.addAll(articles);
}
}
#Override
public void onLoaderReset(Loader<List<Article>> loader) {
adapter.clear();
}
And here is the source for my ArticleLoader class. The "fetchArticleData" call is what retrieves the Article objects by parsing the JSON into Article objects.
public class ArticleLoader extends AsyncTaskLoader<List<Article>> {
private static final String LOG_TAG = ArticleLoader.class.getName();
private String category;
public ArticleLoader(Context context, String category) {
super(context);
this.category = category;
}
#Override
protected void onStartLoading() {
forceLoad();
}
#Override
public List<Article> loadInBackground() {
if (category == null) {
return null;
}
// Perform the network request, parse the response, and extract a list of earthquakes.
List<Article> articles = QueryUtils.fetchArticleData(category);
return articles;
}
}
As per request, here is the QueryUtils class.
public class QueryUtils {
private static final String LOG_TAG = QueryUtils.class.getSimpleName();
private static final String REQUEST_BASE_URL = "https://api.cognitive.microsoft.com/bing/v5.0/news/";
private static final String API_KEY = "redacted";
/**
* Create a private constructor because no one should ever create a {#link QueryUtils} object.
* This class is only meant to hold static variables and methods, which can be accessed
* directly from the class name QueryUtils (and an object instance of QueryUtils is not needed).
*/
private QueryUtils() {
}
/**
* Query the USGS dataset and return a list of {#link Article} objects.
*/
public static List<Article> fetchArticleData(String category) {
// Create URL object
HttpURLConnection conn = createUrlConnection(category);
// Perform HTTP request to the URL and receive a JSON response back
String jsonResponse = null;
try {
jsonResponse = makeHttpRequest(conn);
} catch (IOException e) {
Log.e(LOG_TAG, "Problem making the HTTP request.", e);
}
// Extract relevant fields from the JSON response and create a list of {#link Article}s
List<Article> articles = extractFeatureFromJson(jsonResponse);
// Return the list of {#link Article}s
return articles;
}
/**
* Returns new URL object from the given string URL.
*/
private static HttpURLConnection createUrlConnection(String category) {
URL url = null;
HttpURLConnection conn = null;
try {
url = new URL(QueryUtils.REQUEST_BASE_URL);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Category", category);
conn.setRequestProperty("Ocp-Apim-Subscription-Key", QueryUtils.API_KEY);
conn.setDoInput(true);
} catch (Exception e) {
Log.e(LOG_TAG, "Problem building the URL connection ", e);
}
return conn;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private static String makeHttpRequest(HttpURLConnection conn) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (conn == null) {
return jsonResponse;
}
InputStream inputStream = null;
try {
conn.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (conn.getResponseCode() == 200) {
inputStream = conn.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + conn.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the article JSON results.", e);
} finally {
if (conn != null) {
conn.disconnect();
}
if (inputStream != null) {
// Closing the input stream could throw an IOException, which is why
// the makeHttpRequest(URL url) method signature specifies than an IOException
// could be thrown.
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/**
* Return a list of {#link Article} objects that has been built up from
* parsing the given JSON response.
*/
private static List<Article> extractFeatureFromJson(String articleJSON) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(articleJSON)) {
return null;
}
// Create an empty ArrayList that we can start adding articles to
List<Article> articles = new ArrayList<>();
// Try to parse the JSON response string. If there's a problem with the way the JSON
// is formatted, a JSONException exception object will be thrown.
// Catch the exception so the app doesn't crash, and print the error message to the logs.
try {
// Create a JSONObject from the JSON response string
JSONObject baseJsonResponse = new JSONObject(articleJSON);
// Extract the JSONArray associated with the key called "features",
// which represents a list of features (or articles).
JSONArray articleArray = baseJsonResponse.getJSONArray("value");
// For each article in the articleArray, create an {#link Article} object
for (int i = 0; i < articleArray.length(); i++) {
// Get a single article at position i within the list of articles
JSONObject currentArticle = articleArray.getJSONObject(i);
// Extract the value for the key called "name"
String articleName = currentArticle.getString("name");
// Extract the value for the key called "url"
String articleSource = currentArticle.getString("url");
// Extract the value for the key called "image"
JSONObject imageObject = currentArticle.getJSONObject("image");
String imageSource = imageObject.getJSONObject("thumbnail").getString("contentUrl");
// Create a new {#link Article} object with the name, url, and image
// from the JSON response.
Article article = new Article(articleName, articleSource, imageSource);
// Add the new {#link Article} to the list of articles.
articles.add(article);
}
} catch (JSONException e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing the article JSON results", e);
}
// Return the list of articles
return articles;
}
}
Does anyone know what I'm doing wrong?

Related

Java Stack becomes empty for some reason

I'm working on an Android app that is going to call the DarkSky weather API (I have redacted my API key here for obvious reasons). My problem comes when I parse the JSON data and push it to a stack I named dataStack. At the time of pushing the stack I log its size and it shows correctly. However when my code reaches the buildGraph() method, the stack is now empty and all my data has disappeared. What causes the stack to empty?
EDIT: As of 30 minutes after posting I found a workaround. I am now returning the String and parsing it in my MainActivity Android class. However, I still do not know why the stack was being deleted. I would love to know :)
public class MainActivity extends AppCompatActivity {
Button button;
TextView progressLabel;
GraphView graph;
JSONObject jsonObject;
static Stack<DataPoint> dataStack = new Stack<>(); // stack for graph data points
static final String API_URL = "https://api.darksky.net/forecast/API_KEY/42.3611,-71.0570,"; // #TODO: delete API key before comitting to GitHub
static final String URL_TAIL = "?exclude=currently,flags,hourly"; // end of URL
static final long currTime = System.currentTimeMillis() / 1000L; // current UNIX time
static long unixTime = currTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
progressLabel = findViewById(R.id.progressLabel);
graph = findViewById(R.id.graph);
}
public void loadResults(View view) {
for (int x = 0; x < 2; x++) { // 7 API calls for each of 7 days
new APICall().execute();
unixTime -= 86400; // subtract 24 hours in UNIX time
dataStack.size();
}
buildGraph(); // after all data is gathered, build a graph using it
}
private void buildGraph() {
// #TODO: Method to build graph
Log.i("STACK pop", String.valueOf(dataStack.size()));
}
class APICall extends AsyncTask<Void, Void, String> { // Extend AsyncTask so we don't hijack the main UI thread
protected void onPreExecute() {
// Do stuff before executing the AsyncTask
progressLabel.setText("Fetching Data");
}
protected String doInBackground(Void... urls) {
// Execute background task here
try {
final String FULL_URL = API_URL + unixTime + URL_TAIL; // build the full URL with latest time
URL url = new URL(FULL_URL); // URL for the API call
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // connection to URL
try {
// tools for reading API results
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
// accumulate results
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close(); // always close buffered reader
return stringBuilder.toString(); // return results
}
finally {
// inside a finally block so that no matter what we always end a connection that has been started
urlConnection.disconnect(); // end the connection
}
}
catch(Exception ex) {
Log.e("ERROR", ex.getMessage(), ex);
return null;
}
}
protected void onPostExecute(String response) {
// Do stuff after we're finished executing
if (response == null) {
response = "AN ERROR HAS OCCURRED";
}
else {
try {
jsonObject = new JSONObject(response); // create object from our response
JSONArray arr = jsonObject.getJSONObject("daily").getJSONArray("data"); // get data Array
String arrString = arr.getString(0); // full String
String[] splitString = arrString.split(","); // split String into array by comma
String time = splitString[0].substring(8); // time is the first index of the array, use substring to cutout unecessary info
String temp = splitString[11].substring(18);
dataStack.push(new DataPoint(Integer.valueOf(time), Float.valueOf(temp))); // push our data onto the stack as a DataPoint
Log.i("STACK push", String.valueOf(dataStack.toString()));
response = "Data received"; // display this to user
}
catch(Exception ex) {
response = "ERROR DURING JSON PARSING";
}
}
progressLabel.setText(response);
// parse data here
Log.i("INFO", response);
}
}
}
The stack is empty because result isn't in yet. The issue is with your loadResults().
public void loadResults(View view) {
for (int x = 0; x < 2; x++) { // 7 API calls for each of 7 days
new APICall().execute();
unixTime -= 86400; // subtract 24 hours in UNIX time
dataStack.size();
}
buildGraph(); // after all data is gathered, build a graph using it
}
You issued the new APICall().execute(); to request data and update the dataStack and you expect to get the dataStack results 'immediately' inside the same function loadResults()? It's not possible.
One solution is to remove the buildGraph() in loadResults() to inside onPostExecute().

REST API OpenWeatherMap not working with Variable Input, works correctly with fixed input..

Application fetches data from OpenWeatherMap API and works correctly when I indicate a city, e.g. "London". There is an error when I replace "London" with a variable "place".. Underneath you can find the code.
Can anyone help me?
**MAIN ACTIVITY**
public class MainActivity extends AppCompatActivity {
//create the fields on the Activity
private TextView cityName;
private TextView temp;
private TextView description;
private TextView humidity;
private TextView pressure;
private TextView wind;
private TextView sunrise;
private TextView sunset;
private TextView updated;
private Exception error;
Weather weather = new Weather();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up all the resources for the Views here
cityName = (TextView)findViewById(R.id.cityText);
temp = (TextView)findViewById(R.id.tempText);
description = (TextView)findViewById(R.id.CloudText);
humidity = (TextView)findViewById(R.id.HumidText);
pressure = (TextView)findViewById(R.id.PressureText);
wind = (TextView)findViewById(R.id.WindText);
sunrise = (TextView)findViewById(R.id.RiseText);
sunset = (TextView)findViewById(R.id.SetText);
updated = (TextView)findViewById(R.id.UpdateText);
//instantiate a CityPreference object from the MainActivity that
carries the city with it..
//render the data based on the city you get through the parsing
CityPreference cityPreference = new CityPreference(MainActivity.this);
renderWeatherData(cityPreference.getCity());
}
public void renderWeatherData (String city){
// we want to do all of our tasks in the background, use AsyncTask for this
WeatherTask weatherTask = new WeatherTask();
weatherTask.execute(new String[]{city} + "&units=metric");
}
//last parameter is Weather, this is what we will be populating
private class WeatherTask extends AsyncTask<String, Void, Weather>{
//AsyncTask <PARAMETERS, TASK, RESULT>
#Override
protected Weather doInBackground(String... params) {
//background computation
//data variable holds all the data that we have got..
//instantiate the weather client and get the weather data..
//getWeatherData gets all necessary data from HTTPClient
//getWeather parses all the data from the JSONParser
try {
String data = ((new WeatherHTTPClient().getWeatherData(params[0])));
weather = JSONWeatherParser.getWeather(data);
//create a log to test if everything is working
Log.v("Data:",weather.currentCondition.getDescription());
return weather;
} catch (Exception e) {
error = e;
}
return null;
}
//here you will populate the data so you can show it to the user
#Override
protected void onPostExecute(Weather weather) {
super.onPostExecute(weather);
try {
//gets time and decimal formats and applies it to the data underneath
DateFormat df = DateFormat.getTimeInstance();
String sunriseDate = df.format(new Date(Weather.place.getSunrise()));
String sunsetDate = df.format(new Date(Weather.place.getSunset()));
String updateDate = df.format(new Date(Weather.place.getLastupdate()));
DecimalFormat decimalFormat = new DecimalFormat("#.#");
String tempFormat = decimalFormat.format(weather.currentCondition.getTemperature());
//gets the value from the JSON and parses it in the view of the activity
cityName.setText(weather.place.getCity() + "," + weather.place.getCountry());
temp.setText("" + tempFormat + "C");
humidity.setText("Humidity" + weather.currentCondition.getHumidity() + "%");
pressure.setText("Pressure" + weather.currentCondition.getPressure() + "hPa");
wind.setText("Wind" + weather.wind.getSpeed() + "mps");
sunrise.setText("Sunrise" + sunriseDate);
sunset.setText("Sunset" + sunsetDate);
updated.setText("Updated" + updateDate);
description.setText("Condition" + weather.currentCondition.getCondition() + "(" + weather.currentCondition.getDescription() + ")");
} catch(Exception e) {
error = e;
}
}
}
//create an alert dialog to put in the city you want to parse the data for - A subclass of Dialog that can display one, two or three buttons.
private void showInputDialog () {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Change City");
final EditText cityInput = new EditText(MainActivity.this);
cityInput.setInputType(InputType.TYPE_CLASS_TEXT);
cityInput.setHint("put down city name");
builder.setView(cityInput);
builder.setPositiveButton("Submit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which){
CityPreference cityPreference = new CityPreference(MainActivity.this);
cityPreference.setCity(cityInput.getText().toString());
String newCity = cityPreference.getCity();
renderWeatherData(newCity);
}
});
builder.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//inflate the menu, this adds items to the action bar if it is present
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.change_cityId){
showInputDialog();
}
return super.onOptionsItemSelected(item);
}
}
**HTTP CLIENT**
public class WeatherHTTPClient {
public String getWeatherData (String place) throws IOException {
// setting things up.., create connection between application and the web, everything we get from the web comes as an inputstream
HttpURLConnection connection = null;
InputStream inputStream = null;
// api.openweathermap.org/data/2.5/weather?q=London
// errors may occur when you connect to the internet, build this in the model with try...catch
WHEN I REPLACE "place" by "London" in the next statement, the application works. THERE MUST BE AN ERROR WITH THIS PART, BUT I CANNOT FIND IT.. I NEED HELP..
try {
connection = (HttpURLConnection) (new URL(Utils.BASE_URL + place +"&APPID=f77c39703fb6be71e2c5a96e58edc077")).openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
//read the response, buffer "bucket" where you are going to put your data
StringBuffer stringBuffer = new StringBuffer();
//you get a stream of bits and data to your device - everything comes in as an inputstream
inputStream = connection.getInputStream();
//BufferedReader is the only thing that can read the stream of data - hold it and start reading
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
//line is set as the data read by the BufferedReader, Stringbuffer reads the Buffer and goes to the next one
while ((line = bufferedReader.readLine()) != null){
stringBuffer.append(line + "\r\n");
}
inputStream.close();
connection.disconnect();
return stringBuffer.toString();
} catch (IOException e) {e.printStackTrace();}
return null;
}
}
**WEATHER DATA MODEL JSON**
public class Weather {
public static Place place;
public String IconData;
public CurrentCondition currentCondition = new CurrentCondition();
public Temperature temperature = new Temperature();
public Wind wind = new Wind();
public Snow snow = new Snow();
public Clouds clouds = new Clouds();
}
**PLACE DATA MODEL, left out getters and setters**
**LEFT OUT THE FULL DATA MODEL**
public class Place {
private float lon ;
private float lat ;
private long sunset;
private long sunrise;
private String country;
private String city;
private long lastupdate;
**THE WEATHER PARSER**
public class JSONWeatherParser {
public static Weather getWeather(String data){
//we call the top JSON object weather
Weather weather = new Weather();
//create JSONObject that holds all of the data you get from the web
//place is the parameter you use to get all the data for
//the rest of the variables you have to "calculate" from your data model
//tagName needs to be EXACTLY as it is in the JSON
try {
JSONObject jsonObject = new JSONObject(data);
Place place = new Place();
//for each "header" in JSON you create a JSONObject or a JSONArray
JSONObject coorObj = Utils.getObject("coord", jsonObject);
//you set the latitude by getting the "lat" variable from the coorObj from the top JSON Object weather
place.setLat(Utils.getFloat("lat",coorObj));
place.setLon(Utils.getFloat("lon",coorObj));
//get the sys object
JSONObject sysObj = Utils.getObject("sys", jsonObject);
place.setCountry(Utils.getString("country", sysObj));
//dt Lastupdate is found directly under the jsonObject, hence ...
place.setLastupdate(Utils.getInt("dt", jsonObject));
place.setSunrise(Utils.getInt("sunrise",sysObj));
place.setSunset(Utils.getInt("sunset",sysObj));
place.setCity(Utils.getString("name",jsonObject));
weather.place = place;
//get the weather info, it is a JSONArray of the main jsonObject (the whole thing) - starts with square brackets
JSONArray jsonArray = jsonObject.getJSONArray("weather");
//get the underlying Jsonobject from the jsonarray
JSONObject jsonWeather = jsonArray.getJSONObject(0);
weather.currentCondition.setWeatherId(Utils.getInt("id",jsonWeather));
weather.currentCondition.setDescription(Utils.getString("description", jsonWeather));
weather.currentCondition.setCondition(Utils.getString("main",jsonWeather));
weather.currentCondition.setIcon(Utils.getString("icon",jsonWeather));
JSONObject mainObj = Utils.getObject("main", jsonObject);
weather.currentCondition.setHumidity(Utils.getInt("humidity",mainObj));
weather.currentCondition.setPressure(Utils.getInt("pressure",mainObj));
weather.currentCondition.setMin_temp(Utils.getFloat("temp_min",mainObj));
weather.currentCondition.setMax_temp(Utils.getFloat("temp_max", mainObj));
weather.currentCondition.setTemperature(Utils.getDouble("temp",mainObj));
JSONObject windObj = Utils.getObject("wind", jsonObject);
weather.wind.setSpeed(Utils.getFloat("speed", windObj));
weather.wind.setDeg(Utils.getFloat("deg",windObj));
JSONObject cloudObj = Utils.getObject("clouds", jsonObject);
weather.clouds.setPrecipitation(Utils.getInt("all", cloudObj));
return weather;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
If you look at the URL
https://api.openweathermap.org/data/2.5/weather?q=[Ljava.lang.String;#34e4306&units=metric&APPID=f77c39703fb6be71e2c5a96e58edc077
The value for the query field (q) is [Ljava.lang.String;#34e4306, which is invalid. Ensure that you are sending a proper string value in this place.
Can this line be modified from:
weatherTask.execute(new String[]{city} + "&units=metric");
to the code below:
weatherTask.execute(city + "&units=metric");
Hope this would help.

Android Login screen from Json

I´m newbie on Android and need help.
I have a JSON that looks like this:
{
"Id": 1,
"Name": "user",
"userId": 4,
"active": true,
"ProfileId": 1,
"Tema": "green",
"Language": "english",
"success": true,
"error": false
}
Json 2:
{"message":"no user or password","success":false,"erroAplicacao":false}
This is my code:
public class MainActivity extends AppCompatActivity {
EditText usernameWidget;
EditText passwordWidget;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
usernameWidget = (EditText) findViewById(R.id.tv_username);
passwordWidget = (EditText) findViewById(R.id.tv_password);
}// END ON CREATE
public class DownloadTask extends AsyncTask<String, Void, String> {
String message = "message";
String loginSuccess;
String Id = "Id";
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
int data = reader.read();
while (data != -1){
char current = (char) data; // each time creates a char current
result += current;
data = reader.read();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
} // END doInBackground
//Method called when the doInBack is complete
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject jsonObject = new JSONObject(result);
Log.i("***JSON ITSELF***", result);
loginSuccess = jsonObject.getString("success");
Log.i("*****LOGIN SUCCESS*****", loginSuccess);
message = jsonObject.getString("message");
Log.i("*****MESSAGE*****", message);
Id = jsonObject.getString("Id");
Log.i("*****ID*****", pessoaFisicaId);
}catch(JSONException e) {
e.printStackTrace();
}// END CATCH
if (loginSuccess.contains("true")){
Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(intent);
}else if (loginSuccess.contains("false")){
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
}
}// END POST EXECUTE
}// END Download Task
public void login(View view) {
String user = usernameWidget.getText().toString();
String pass = passwordWidget.getText().toString();
String stringJSON = "*URL*login=" + user + "&senha=" + pass;
DownloadTask task = new DownloadTask();
task.execute(stringJSON);
Log.i("*****JSON URL*****", stringJSON);
}// END LOGIN
}// END MAIN
In this order:
loginSuccess = jsonObject.getString("success");
message = jsonObject.getString("message");
Id = jsonObject.getString("Id");
I get the message ("no user or password") from json2 (different url) as a Toast.
If I change the order, lets say, to:
loginSuccess = jsonObject.getString("success");
Id = jsonObject.getString("Id");
message = jsonObject.getString("message");
I don´t get a message. In fact I get the value "message" from the String message at the start of the DownloadTask class.
It seems that the json is only getting two values, the first ones I ask for.
One thing though is that only when the user or password is wrong is that the json has a message (json2):
{"message":"no user or password","success":false,"erroAplicacao":false}
Since my json cant be transformed into an array json (I tried and got error saying this), what should I do?
When you call jsonObject.getString("your_string"), this will throw a JSONException if your string cannot be found. Therefore, the remaining lines in of code in the method will not be executed. Change your LogCat settings to verbose and you should be able to see what's going on.
More info on the getString() method here:
https://developer.android.com/reference/org/json/JSONObject.html#getString(java.lang.String)
Use GSON
public class User{
private int Id;
private String Name;
}
Parse
User user = GSON.fromJSON(jsonString, User.class);

Fetching data from an API with JSON and storing two objects in a single row of an Array Adapter

I've got this code with fetches the "rate" data from an API, along with "rate", I need to get the "name". If I get "name" it often binds it below the "rate".
I need it to join on the same row of the List View, so it is like [Rate Name].
I need to get two objects of a JSON Array and bind it to the array adapter so I can display two objects in the same row of a List View so it is more user friendly.
The code below is of the AsyncTask, the code works fine but I need to add one more object and make sure it is displayed as one rate - one name and then iterating through the loop and adding more as needed in the same order.
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
// the url of the web service to call
String yourServiceUrl = "eg: URL";
#Override
protected void onPreExecute() {
}
String filename = "bitData";
#Override
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// parse returned json string into json array
JSONArray jsonArray = new JSONArray(json);
// loop through json array and add each currency to item in arrayList
//Custom Loop Initialise
for (int i = 1; i < 8; i++) {
JSONObject json_message = jsonArray.getJSONObject(i);
// The second JSONObject which needs to be added
JSONObject json_name = jsonArray.getJSONObject(i);
if (json_message != null) {
//add each currency to ArrayList as an item
items.add(json_message.getString("rate"));
String bitData = json_message.getString("rate");
String writeData = bitData + ',' +'\n';
FileOutputStream outputStream;
File file = getFileStreamPath(filename);
// first check if file exists, if not create it
if (file == null || !file.exists()) {
try {
outputStream = openFileOutput(filename, MODE_PRIVATE);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// if file already exists then append bit data to it
else if (file.exists()) {
try {
outputStream = openFileOutput(filename, Context.MODE_APPEND);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
// below method will run when service HTTP request is complete, will then bind text in arrayList to ListView
#Override
protected void onPostExecute(String strFromDoInBg) {
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
}
}
Just Create Custom Class Messsage:
public class Item{
private String name;
private String rate;
public void Message(String n, String r){
this.name=n;
this.rate=r;
}
// create here getter and setter
}
Now in your background, you have to add name and rate in Message class
Public class MainAcitity extends Activity{
public static List<Item> items= new ArrayList<>();// define in inside the class
// this has to be down on background
Item i=new Item(json_message.getString("name"),json_message.getString("rate"));
items.add(i);
Now pass this listmessge onPostExecute :
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
Is that any helpful for you.
Follow this link.You will get my point.
https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/

Android Twitter App Can't Make Objects from Json Response

I'm trying to simply make objects out of a Twitter stream I download from a user. I am using the information provided from https://github.com/Rockncoder/TwitterTutorial. Can someone help determine if this code actually works? Some of the classes are kind of sketchy, as in the Twitter.java class is just an ArrayList and it only has what's listed below in it.
Is my process correct? Any help is appreciated.
public class MainActivity extends ListActivity {
private ListActivity activity;
final static String ScreenName = "riddlemetombers";
final static String LOG_TAG = "rmt";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
downloadTweets();
}
// download twitter timeline after first checking to see if there is a network connection
public void downloadTweets() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
new DownloadTwitterTask().execute(ScreenName);
} else {
Log.v(LOG_TAG, "No network connection available.");
}
}
// Uses an AsyncTask to download a Twitter user's timeline
private class DownloadTwitterTask extends AsyncTask<String, Void, String> {
final String CONSUMER_KEY = (String) getResources().getString(R.string.api_key);
final String CONSUMER_SECRET = (String)getResources().getString(R.string.api_secret);
final static String TwitterTokenURL = "https://api.twitter.com/oauth2/token";
final static String TwitterStreamURL = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=";
#Override
protected String doInBackground(String... screenNames) {
String result = null;
if (screenNames.length > 0) {
result = getTwitterStream(screenNames[0]);
}
return result;
}
// onPostExecute convert the JSON results into a Twitter object (which is an Array list of tweets
#Override
protected void onPostExecute(String result) {
Twitter twits = jsonToTwitter(result);
// lets write the results to the console as well
for (Tweet tweet : twits) {
Log.i(LOG_TAG, tweet.getText());
}
// send the tweets to the adapter for rendering
ArrayAdapter<Tweet> adapter = new ArrayAdapter<Tweet>(activity, R.layout.items, twits);
setListAdapter(adapter);
}
// converts a string of JSON data into a Twitter object
private Twitter jsonToTwitter(String result) {
Twitter twits = null;
if (result != null && result.length() > 0) {
try {
Gson gson = new Gson();
twits = gson.fromJson(result, Twitter.class);
if(twits==null){Log.d(LOG_TAG, "Twits null");}
else if(twits!=null) {Log.d(LOG_TAG, "Twits NOT null");}
} catch (IllegalStateException ex) {
// just eat the exception
}
}
return twits;
}
// convert a JSON authentication object into an Authenticated object
private Authenticated jsonToAuthenticated(String rawAuthorization) {
Authenticated auth = null;
if (rawAuthorization != null && rawAuthorization.length() > 0) {
try {
Gson gson = new Gson();
auth = gson.fromJson(rawAuthorization, Authenticated.class);
} catch (IllegalStateException ex) {
// just eat the exception
}
}
return auth;
}
private String getResponseBody(HttpRequestBase request) {
StringBuilder sb = new StringBuilder();
try {
DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams());
HttpResponse response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
String reason = response.getStatusLine().getReasonPhrase();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream inputStream = entity.getContent();
BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
String line = null;
while ((line = bReader.readLine()) != null) {
sb.append(line);
}
} else {
sb.append(reason);
}
} catch (UnsupportedEncodingException ex) {
} catch (ClientProtocolException ex1) {
} catch (IOException ex2) {
}
return sb.toString();
}
private String getTwitterStream(String screenName) {
String results = null;
// Step 1: Encode consumer key and secret
try {
// URL encode the consumer key and secret
String urlApiKey = URLEncoder.encode(CONSUMER_KEY, "UTF-8");
String urlApiSecret = URLEncoder.encode(CONSUMER_SECRET, "UTF-8");
// Concatenate the encoded consumer key, a colon character, and the
// encoded consumer secret
String combined = urlApiKey + ":" + urlApiSecret;
// Base64 encode the string
String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP);
// Step 2: Obtain a bearer token
HttpPost httpPost = new HttpPost(TwitterTokenURL);
httpPost.setHeader("Authorization", "Basic " + base64Encoded);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
httpPost.setEntity(new StringEntity("grant_type=client_credentials"));
String rawAuthorization = getResponseBody(httpPost);
Authenticated auth = jsonToAuthenticated(rawAuthorization);
// Applications should verify that the value associated with the
// token_type key of the returned object is bearer
if (auth != null && auth.token_type.equals("bearer")) {
// Step 3: Authenticate API requests with bearer token
HttpGet httpGet = new HttpGet(TwitterStreamURL + screenName);
// construct a normal HTTPS request and include an Authorization
// header with the value of Bearer <>
httpGet.setHeader("Authorization", "Bearer " + auth.access_token);
httpGet.setHeader("Content-Type", "application/json");
// update the results with the body of the response
results = getResponseBody(httpGet);
}
} catch (UnsupportedEncodingException ex) {
} catch (IllegalStateException ex1) {
}
return results;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
TWITTER CLASS
import java.util.ArrayList;
// a collection of tweets
public class Twitter extends ArrayList<Tweet> {
private static final long serialVersionUID = 1L;
}
TWEET CLASS
import com.google.gson.annotations.SerializedName;
public class Tweet {
#SerializedName("created_at")
private String DateCreated;
#SerializedName("id")
private String Id;
#SerializedName("text")
private String Text;
#SerializedName("in_reply_to_status_id")
private String InReplyToStatusId;
#SerializedName("in_reply_to_user_id")
private String InReplyToUserId;
#SerializedName("in_reply_to_screen_name")
private String InReplyToScreenName;
#SerializedName("user")
private TwitterUser User;
public String getDateCreated() {
return DateCreated;
}
public String getId() {
return Id;
}
public String getInReplyToScreenName() {
return InReplyToScreenName;
}
public String getInReplyToStatusId() {
return InReplyToStatusId;
}
public String getInReplyToUserId() {
return InReplyToUserId;
}
public String getText() {
return Text;
}
public void setDateCreated(String dateCreated) {
DateCreated = dateCreated;
}
public void setId(String id) {
Id = id;
}
public void setInReplyToScreenName(String inReplyToScreenName) {
InReplyToScreenName = inReplyToScreenName;
}
public void setInReplyToStatusId(String inReplyToStatusId) {
InReplyToStatusId = inReplyToStatusId;
}
public void setInReplyToUserId(String inReplyToUserId) {
InReplyToUserId = inReplyToUserId;
}
public void setText(String text) {
Text = text;
}
public void setUser(TwitterUser user) {
User = user;
}
public TwitterUser getUser() {
return User;
}
#Override
public String toString(){
return getText();
}
}
I've done several Log.d(LOG_TAG, Stuff) to see if I'm getting stuff, and it indicates I'm getting some kind of content back. Maybe the problem is in making objects of the data.
Not sure why you want to use the code from https://github.com/Rockncoder/TwitterTutorial.
Why don't use use http://twitter4j.org. They have give sample example to use it.
Moreover it support Twitter 1.1 as well. Just include twitter-core.jar and you are ready write your code.
Hope it helps.

Categories

Resources