Nothing happens on pressing Menu Item - android

I am trying to build an app following a tutorial. I have a "Refresh" button that's supposed to populate a ListView (through and ArrayAdaptor)with an array of data from an API call but when I press the "Refresh" button. The button is supposed to run updateWeather() method to load the ListView with some weather data that looks like this (This data appears in my Log actually):
Can someone please help with this. Can't seem to get my head around it.
05-10 23:23:23.921: V/FetchWeatherTask(2037): Forecast entry: Sun May 10 - Clouds - 10/8
05-10 23:23:23.921: V/FetchWeatherTask(2037): Forecast entry: Mon May 11 - Clear - 17/5
05-10 23:23:23.921: V/FetchWeatherTask(2037): Forecast entry: Tue May 12 - Rain - 21/8
05-10 23:23:23.921: V/FetchWeatherTask(2037): Forecast entry: Wed May 13 - Rain - 15/10
05-10 23:23:23.921: V/FetchWeatherTask(2037): Forecast entry: Thu May 14 - Rain - 20/15
05-10 23:23:23.922: V/FetchWeatherTask(2037): Forecast entry: Fri May 15 - Rain - 13/11
05-10 23:23:23.922: V/FetchWeatherTask(2037): Forecast entry: Sat May 16 - Rain - 13/8
ForecastFragment.java
package com.example.siaw.sunshine;
import ...
public class ForecastFragment extends Fragment {
private ArrayAdapter<String> forecastAdaptor;
public ForecastFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_refresh){
updateWeather();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
forecastAdaptor = new ArrayAdapter<String>(getActivity(),R.layout.list_item_forecast,
R.id.list_item_forecast_textview, new ArrayList<String>());
ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
listView.setAdapter(forecastAdaptor);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String forecast = forecastAdaptor.getItem(position);
Intent intent = new Intent(getActivity(), DetailActivity.class)
.putExtra(Intent.EXTRA_TEXT, forecast);
startActivity(intent);
}
});
return rootView;
}
private void updateWeather() {
FetchWeatherTask weatherTask = new FetchWeatherTask();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String location = prefs.getString(getString(R.string.pref_location_key),
getString(R.string.pref_location_default));
weatherTask.execute(location);
}
#Override
public void onStart() {
super.onStart();
updateWeather();
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd");
return shortenedDateFormat.format(time);
}
/**
* Prepare the weather high/lows for presentation.
*/
private String formatHighLows(double high, double low) {
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
String highLowStr = roundedHigh + "/" + roundedLow;
return highLowStr;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "max";
final String OWM_MIN = "min";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
// OWM returns daily forecasts based upon the local time of the city that is being
// asked for, which means that we need to know the GMT offset to translate this data
// properly.
// Since this data is also sent in-order and the first day is always the
// current day, we're going to take advantage of that to get a nice
// normalized UTC date for all of our weather.
Time dayTime = new Time();
dayTime.setToNow();
// we start at the day returned by local time. Otherwise this is a mess.
int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);
// now we work exclusively in UTC
dayTime = new Time();
String[] resultStrs = new String[numDays];
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime;
// Cheating to convert this to UTC time, which is what we want anyhow
dateTime = dayTime.setJulianDay(julianStartDay+i);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
}
for (String s : resultStrs) {
Log.v(LOG_TAG, "Forecast entry: " + s);
}
return resultStrs;
}
#Override
protected String[] doInBackground(String... params){
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
if (params.length == 0){
return null;
}
HttpURLConnection urlConnection = null;
//TODO: track and remove.
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
String format = "json";
String units = "metric";
int numDays = 7;
try {
final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built URI " + builtUri.toString());
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuilder buffer = new StringBuilder();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
Log.v(LOG_TAG, "Forecast String: " + forecastJsonStr);
} catch (IOException e) {
Log.e("ForecastFragment", "Error", e);
// If the code didn't successfully get the weather data, there's no point in attempting
// to parse it.
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("ForecastFragment", "Error closing stream", e);
}
}
}
try {
return getWeatherDataFromJson(forecastJsonStr, numDays);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
//This will only happen if there was an error getting/parsing the forecast.
return null;
}
#Override
protected void onPostExecute(String[] result) {
if (result != null) {
forecastAdaptor.clear();
for (String dayForecastStr : result) {
forecastAdaptor.add(dayForecastStr);
}
// New data is back from the server. Hooray!
}
}
}
}
The data in this ListView is actually not from the API call, the funny thing is I deleted the static String array that's holding THIS data but after cleaning and rebuilding, the static data still appears. I am not sure why this is happening. In the code this data has been removed!
I want to populate this fake data with the data from the API call with the kind of data that shows in LogCat.

It looks like the main issue is that you are not calling notifyDataSetChanged() after modifying the data set in onPostExecute(). This should be all you need to get it working:
#Override
protected void onPostExecute(String[] result) {
if (result != null) {
forecastAdaptor.clear();
for (String dayForecastStr : result) {
forecastAdaptor.add(dayForecastStr);
}
// New data is back from the server. Hooray!
forecastAdapter.notifyDataSetChanged(); //added
}
}
As an alternative, I usually prefer to do all data manipulation on the underlying ArrayList instead of using the methods of ArrayAdapter, see below for details:
Create a ArrayList<String> as a member variable, which will be your data source for the ListView:
public class ForecastFragment extends Fragment {
private ArrayAdapter<String> forecastAdaptor;
private ArrayList<String> data; //added
//.........
Initialize in onCreate():
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
data = new ArrayList<String>(); //added
}
Then, pass in the data source when calling setAdapter():
forecastAdaptor = new ArrayAdapter<String>(getActivity(),R.layout.list_item_forecast,
R.id.list_item_forecast_textview, data);
Then, in onPostExecute() of your AsyncTask, update the data source, then call notifyDataSetChanged():
#Override
protected void onPostExecute(String[] result) {
if (result != null) {
//forecastAdaptor.clear(); //no need for this
data.clear(); //clear the data source
for (String dayForecastStr : result) {
//forecastAdaptor.add(dayForecastStr);
data.add(dayForecastStr); //update data source
}
// New data is back from the server. Hooray!
forecastAdapter.notifyDataSetChanged(); //added
}
}
See documentation for notifyDataSetChanged()

Related

android sunshine app live data is not loaded on list when i press refresh button

hi i have been following android sunshine Udacity course but i got stuck at loading live data from internet i log and i see data but it is not loaded on listView thanks in advance.
package com.example.ali.ican;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new ForcastFragment())
.commit();
}
}
}
ForcastFragment
/**
* A placeholder fragment containing a simple view.
*/
public class ForcastFragment extends android.support.v4.app.Fragment {
private static ArrayAdapter<String> ForcastIncoming;
public ForcastFragment() {
}
//---------------------------------------------------------
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new FetchWeatherTask().execute("London");
}
#Override
public void onCreateOptionsMenu(Menu menu,MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.forcastfragment, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_refresh) {
FetchWeatherTask fetchWeatherTask = new FetchWeatherTask();
fetchWeatherTask.execute("119505");
Log.v("Action_refresh","works");
return true;
}
return super.onOptionsItemSelected(item);
}
//---------------------------------------------------------
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
// api.openweathermap.org/data/2.5/forecast?q=Qazvin,Iran&mode=Json
// api.openweathermap.org/data/2.5/forecast/daily?q=Qazvin,Iran&mode=Json&units=metric&cnt=7
String [] wheather ={
"Today - sunny 88/66",
"Tommorow - foggy 65/66",
"Sunday - windy 55/63",
"Monday - cloudy 89/66"
};
List<String> WeekForecast =new ArrayList<String>(
Arrays.asList(wheather)
);
ForcastIncoming =
new ArrayAdapter<String>
(getActivity()
,R.layout.list_item_forcast,
R.id._list_item_forecast_textView,
WeekForecast);
ListView firstlist =(ListView) rootView.findViewById(R.id.list_view_foreccast);
firstlist.setAdapter(ForcastIncoming);
return rootView;
}
public class FetchWeatherTask extends AsyncTask<String ,Void, String[]>{
private final String LOG_TAG =FetchWeatherTask.class.getCanonicalName();
#Override
protected String[] doInBackground(String... params) {
Log.v("CityID",""+params);
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
int numDays =7;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
// final String FORCAST_BASE_URL ="http://api.openweathermap.org/data/2.5/forecast?id=119505&APPID=2a1ca9cdf8fa6bece6558112664c02ab";
final String FORCAST_BASE_URL ="http://api.openweathermap.org/data/2.5/forecast?id=119505&APPID=2a1ca9cdf8fa6bece6558112664c02ab";
final String QUERY_PARAM ="id";
final String QUERY_AAPID = "APPID";
final String APPID = "2a1ca9cdf8fa6bece6558112664c02ab";
final String QUERY_CNT = "cnt";
Uri uriBuilder = Uri.parse(FORCAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM,params[0])
.appendQueryParameter(QUERY_AAPID,APPID)
.appendQueryParameter(QUERY_CNT,Integer.toString(numDays))
.build();
// URL url = new URL("http://api.openweathermap.org/data/2.5/forecast?id=119505&APPID=2a1ca9cdf8fa6bece6558112664c02ab");
URL url = new URL(uriBuilder.toString());
Log.v("Uri_builder",""+uriBuilder);
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
// urlConnection.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
// urlConnection.setRequestProperty("Accept","*/*");
// urlConnection.setRequestProperty("API_KEY", "2a1ca9cdf8fa6bece6558112664c02ab");
// urlConnection.setDoInput(true);
// urlConnection.setDoOutput(false);
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
Log.e("inputstreamshouting","yesssssssssnullllllllll");
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
Log.v("MAhdi","forcastJsonStr:" +forecastJsonStr);
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
try {
return getWeatherDataFromJson(forecastJsonStr,numDays);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] res) {
super.onPostExecute(res);
Log.v("From_onPost",""+res);
if (res !=null)
{
ForcastIncoming.clear();
for(String dayForcastTR :res){
ForcastIncoming.add(dayForcastTR);
}
}
ForcastIncoming.notifyDataSetChanged();
}
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
Date date = new Date(time * 1000);
SimpleDateFormat format = new SimpleDateFormat("E, MMM d");
return format.format(date).toString();
}
/**
* Prepare the weather high/lows for presentation.
*/
private String formatHighLows(double high, double low) {
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
String highLowStr = roundedHigh + "/" + roundedLow;
return highLowStr;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
Log.v("Testing_arg","this is the ::"+ forecastJsonStr);
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "temp_max";
final String OWM_MIN = "temp_min";
final String OWM_DATETIME = "dt";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
String[] resultStrs = new String[numDays];
Log.v("here_weatherArray","works ::"+ weatherArray);
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
Log.v("here_dayForecast","works ::"+dayForecast);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime = dayForecast.getLong(OWM_DATETIME);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
Log.v("herewat","worksk ::" + weatherObject);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_DESCRIPTION);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
Log.v("high","temperatureObject ::"+high);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
Log.v("_resultStrs","works ::"+resultStrs);
// Log.v("resultStrs[i]","this is the ::"+ resultStrs[i]);
// for(int ii=0;ii<resultStrs.length;i++){
//
// Log.v("_Parsing", "Forcast entry: " + resultStrs[ii]);
//
//
// }
return resultStrs;
}
return resultStrs;
}
}
}
i hope someone can help me again thanks in advance
Layout Structor
Make your List<String> WeekForecast as global and add new items in onPostExecute to it as in
#Override
protected void onPostExecute(String[] res) {
super.onPostExecute(res);
Log.v("From_onPost",""+res);
if (res !=null)
{
WeekForecast.clear();
WeekForecast.addAll(Arrays.asList(res));
ForcastIncoming.notifyDataSetChanged();
}
}

getDefaultSharedPreferences(getActivity()) in AsyncTask

public class MainActivityFragment extends Fragment {
public static ArrayAdapter<String> mForecastAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mForecastAdapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_forecast, R.id.list_item_forecast_textview, new ArrayList<String>());
ListView listview = (ListView) rootView.findViewById(R.id.listview_forecast);
listview.setAdapter(mForecastAdapter);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
String Forecast = mForecastAdapter.getItem(position);
Intent intent = new Intent(getActivity(), DetailActivity.class).putExtra(Intent.EXTRA_TEXT, Forecast);
startActivity(intent);
}
});
return rootView;
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
Context mContext;
private void FetchWeatherTask(Context context){
mContext = context;
}
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
public String formatHighLows(double high, double low) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
String unitType = sharedPrefs.getString(getString(R.string.pref_location_key),getString(R.string.pref_location_default));
/*
if(unitType.equals(getString(R.string.pref_units_imperial)))
{
high = (high*1.8) + 32;
low = (low * 1.8) +32;
} else if (!unitType.equals(getString(R.string.pref_units_metric)))
{
}
*/
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
String highLowStr = roundedHigh + "/" + roundedLow;
return highLowStr;
}
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
Date date = new Date(time * 1000);
SimpleDateFormat format = new SimpleDateFormat("E, MMM d");
return format.format(date).toString();
}
/**
* Prepare the weather high/lows for presentation.
*/
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "max";
final String OWM_MIN = "min";
final String OWM_DATETIME = "dt";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
String[] resultStrs = new String[numDays];
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime = dayForecast.getLong(OWM_DATETIME);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
}
/*
for (String s : resultStrs)
{
Log.v(LOG_TAG,"Forecast entry: "+s);
}
*/
return resultStrs;
}
#Override
protected String[] doInBackground(String... params) {
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
String format = "json";
String units = "metric";
int numDays = 7;
String ApiKey = "8f044afff5747f43d54f5229904c5dbb";
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARM = "q";
final String FORMAT_PARM = "mode";
final String UNITS_PARM = "units";
final String DAYS_PARM = "cnt";
final String KEY_PARM = "appid";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARM,params[0])
.appendQueryParameter(FORMAT_PARM,format)
.appendQueryParameter(UNITS_PARM,units)
.appendQueryParameter(DAYS_PARM,Integer.toString(numDays))
.appendQueryParameter(KEY_PARM,ApiKey).build();
URL url = new URL(builtUri.toString());
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
forecastJsonStr = null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
forecastJsonStr = null;
}
forecastJsonStr = buffer.toString();
// Log.v(LOG_TAG,"Forecast JSON String"+forecastJsonStr);
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
forecastJsonStr = null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
try {
String[] FinalValue = getWeatherDataFromJson(forecastJsonStr,numDays);
for (String s : FinalValue)
{
Log.v(LOG_TAG,"Forecast entry: "+s);
}
return FinalValue;
} catch (JSONException e) {
Log.e(LOG_TAG,e.getMessage(),e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] result) {
if(result != null)
{
mForecastAdapter.clear();
for(String DayForecastStr : result)
{
mForecastAdapter.add(DayForecastStr);
}
}
}
}
}
This is the logcat
FATAL EXCEPTION: AsyncTask #1
Process: app.com.example.administrator.sunshineapp, PID: 19227
java.lang.RuntimeException: An error occured while executing
doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at
java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual
method 'java.lang.String android.content.Context.getPackageName()' on
a null object reference
at
android.preference.PreferenceManager.getDefaultSharedPreferencesName(PreferenceManager.java:374)
at
android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:369)
at
app.com.example.administrator.sunshineapp.MainActivityFragment$FetchWeatherTask.formatHighLows(MainActivityFragment.java:90)
at
app.com.example.administrator.sunshineapp.MainActivityFragment$FetchWeatherTask.getWeatherDataFromJson(MainActivityFragment.java:184)
at
app.com.example.administrator.sunshineapp.MainActivityFragment$FetchWeatherTask.doInBackground(MainActivityFragment.java:300)
at
app.com.example.administrator.sunshineapp.MainActivityFragment$FetchWeatherTask.doInBackground(MainActivityFragment.java:74)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:818)
this the main activity code :
package app.com.example.administrator.sunshineapp;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
public class MainActivity extends AppCompatActivity {
public Activity mActivity;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setLogo(R.mipmap.sun);
;
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_refresh) {
updateWeather();
return true;
}
if (id == R.id.action_settings) {
startActivity(new Intent(this,SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateWeather ()
{
MainActivityFragment x = new MainActivityFragment();
MainActivityFragment.FetchWeatherTask WeatherTask = x.new FetchWeatherTask();
SharedPreferences prefs = android.preference.PreferenceManager.getDefaultSharedPreferences(this);
String location = prefs.getString(getString(R.string.pref_location_key),getString(R.string.pref_location_default));
WeatherTask.execute(location);
}
#Override
public void onStart() {
super.onStart();
updateWeather();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
Action viewAction = Action.newAction(Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app URL is correct.
Uri.parse("android-app://app.com.example.administrator.sunshineapp/http/host/path"));
AppIndex.AppIndexApi.start(client, viewAction);
}
#Override
public void onStop() {
super.onStop();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
Action viewAction = Action.newAction(Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app URL is correct.
Uri.parse("android-app://app.com.example.administrator.sunshineapp/http/host/path"));
AppIndex.AppIndexApi.end(client, viewAction);
client.disconnect();
}
}
use ActivityName.this instead of mContext
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(ActivityName.this)
instead of
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext)
create a constructor and pass context through that constructor.

How do I return value from AsyncTask class to another class?

I have an option menu item that allows a user to see their current location (based on Zip Code) on Google Maps using an intent. Because Google Maps only accepts Lat/Lng, I am using the Geocoding API to return Lat/Lng in JSON format. Here is the code that executes once the user selects the menu item:
MainActivity.java
#Override public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
Intent in = new Intent(this, SettingsActivity.class);
startActivity(in);
return true;
}
if (id == R.id.action_map) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String location = prefs.getString(getString(R.string.pref_location_key),
getString(R.string.pref_location_default));
FetchZipTask fzt = new FetchZipTask();
fzt.execute(location);
loc = fzt.locale;
Uri geoLocation = Uri.parse("geo:"+ loc);
Log.d("Debug", geoLocation.toString());
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(geoLocation);
if (in.resolveActivity(getPackageManager()) != null) {
startActivity(in);
}
}
return super.onOptionsItemSelected(item);
}
I am currently trying to use a public String field in the AsyncTask class that is updated when the onPostExecute() method parses the JSON and formats the retrieved Lat/Lng string. I then access this public field from the MainActivity class whenever the user selects the menu item, but the field is always null. What am I doing wrong, and is it the most effective way to leverage AsyncTask? I'm thinking there must be a better way to return the value.
FetchZipTask.java
public class FetchZipTask extends AsyncTask<String, Void, String> {
public String locale = null;
#Override protected void onPostExecute(String result) {
locale = result;
}
#Override protected String doInBackground(String... params) {
if (params.length == 0) {
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//raw JSON response as a string
String locationJsonStr = null;
try {
final String BASE_LOCATION_URL =
"https://maps.googleapis.com/maps/api/geocode/json?";
final String ADDRESS_PARAM = "address";
final String APPID_PARAM = "key";
// URI.path vs URI.parse vs. URI Scheme
Uri builtUri = Uri.parse(BASE_LOCATION_URL)
.buildUpon()
.appendQueryParameter(ADDRESS_PARAM, params[0])
.appendQueryParameter(APPID_PARAM, BuildConfig.GOOGLE_GEOCODE_API_KEY)
.build();
//Log.d("Debug", builtUri.toString());
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// buffer for debugging.
line.concat(" Hello ");
line.concat("\n");
buffer.append(line);
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
locationJsonStr = buffer.toString();
Log.v("debug", "Location string: " + locationJsonStr);
} catch (IOException e) {
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("ForecastFragment", "Error closing stream", e);
}
}
}
try {
return getLocationDataFromJson(locationJsonStr);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private String getLocationDataFromJson(String forecastJsonStr) throws
JSONException {
// These are the names of the JSON objects that need to be extracted.
final String GEO_LIST = "results";
final String GEO_OBJ = "geometry";
final String GEO_LOC = "location";
final String GEO_LAT = "lat";
final String GEO_LNG = "lng";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray resultsArray = forecastJson.getJSONArray(GEO_LIST);
JSONObject resultsObj = resultsArray.getJSONObject(0);
JSONObject geoObj = resultsObj.getJSONObject(GEO_OBJ);
JSONObject latLng = geoObj.getJSONObject(GEO_LOC);
String lat = latLng.getString(GEO_LAT);
String lng = latLng.getString(GEO_LNG);
Log.d("location", "Lat:" + lat + "\n Lng:" + lng);
return lat + "," + lng;
}
}
AsyncTask is called async for a reason.
In the following code you execute your AsyncTask and then immediately try to access one of its fields:
FetchZipTask fzt = new FetchZipTask();
fzt.execute(location);
loc = fzt.locale;
That won't work because FetchZipTask may still be running when you're trying to access its locale variable.
onPostExecute() is called when the task is finished, so you should pass your result from there.
You could define an interface in FetchZipTask, pass an instance of it as a constructor param and call the appropriate method on that instance in onPostExecute():
public class FetchZipTask extends AsyncTask<String, Void, String> {
// declaring a listener instance
private OnFetchFinishedListener listener;
// the listener interface
public interface OnFetchFinishedListener {
void onFetchFinished(String result);
}
// getting a listener instance from the constructor
public FetchZipTask(OnFetchFinishedListener listener) {
this.listener = listener;
}
// ...
// calling a method of the listener with the result
#Override protected void onPostExecute(String result) {
listener.onFetchFinished(result);
}
}
In your Activity, pass an OnFetchFinishedListener when instantiating your AsyncTask:
new FetchZipTask(new FetchZipTask.OnFetchFinishedListener() {
#Override
public void onFetchFinished(String result) {
// do whatever you want with the result
Uri geoLocation = Uri.parse("geo:"+ result);
Log.d("Debug", geoLocation.toString());
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(geoLocation);
if (in.resolveActivity(getPackageManager()) != null) {
startActivity(in);
}
}
}).execute();
And that's it. Orientation change may still be a problem, so you could move your AsyncTask in a headless Fragment, or consider using a Service instead.

Android autocomplete Google Places suggestions taking delays too long

I implemented in my app google places autocomplete on autocomplete textview.
At first when i was working on that part predictions came up on start of typing but now there is a delay after i start typing. Usually 5 seconds but sometimes over a half of minute !!!
The strange thing is that after i try autocomplete for first time(and wait that delay) and then go back and to autocomplete again the results show WITHOUT THE DELAY !!
I've run trough my code a million times but i just can't see why is that happening.
I've cleaned my project, rebooted my device and did solution on this topic:
How to improve performance of google places autocomplete suggestions?
Here is my code:
onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog);
actvLocations = (AutocompleteTextViewCustom) findViewById(R.id.actvEnterLocation);
actvLocations.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable arg0) {
Log.e("dialog location after text changed", "AFTER");
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String input = "";
// get input text
try {
input = "input=" + URLEncoder.encode(s.toString(), "utf-8"); // !!! check text coding for different counties !!!
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
/**
* activate error screen
*/
}
// set parameters for parsing
String parameters = input + "&" + "types=geocode" + "&" + "sensor=false";
// start places task for getting results from google
placesTask = new PlacesTask(listenerForAutocompleteCompletedTask, "getPredictions");
placesTask.execute(parameters);
}
});
// populate listview with previously browsed locations
ListView listviewPreviouslyBrowsedLocations = (ListView) findViewById(R.id.lvPreviouslyBrowsedLocations);
final ListViewAdapter adapterListview= new ListViewAdapter(context, listPreviouslyBrowsedLocations);
listviewPreviouslyBrowsedLocations.setAdapter(adapterListview);
listviewPreviouslyBrowsedLocations.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View convertView, int position, long arg3) {
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
list.add(adapterListview.getParameters(position));
listenerForHeaderLocationChange.onLocationChangeExecuteThisMethod(list, false);
dismiss();
}
});
}
OnTaskCompleted listenerForAutocompleteCompletedTask = new OnTaskCompleted() {
#Override
public void onGetAutocompletePredictionsExecuteThisMethod( final List<HashMap<String, String>> listOfHashmapsForAutocompleteTextview) {
//making simple adapter for autocomplete textview
String[] from = new String[] { "description" };
int[] to = new int[] { android.R.id.text1 };
SimpleAdapter adapter = new SimpleAdapter(context, listOfHashmapsForAutocompleteTextview, android.R.layout.simple_dropdown_item_1line, from, to);
actvLocations.setAdapter(adapter);
/** autocomplete textview drop down items wouldn't show even after threshold set to 0 so .showDropDown() forces drop down items to show*/
actvLocations.showDropDown();
actvLocations.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View convertView, final int position, long arg3) {
dismiss();
final PlacesTask taskForLatLng = new PlacesTask(listenerForAutocompleteCompletedTask, "getPlaceLatLng");
#SuppressWarnings("unchecked")
HashMap<String, String> clickedItem = (HashMap<String, String>) parent.getItemAtPosition(position);
// set name of place for getting result back to header
nameOfSelectedPlace = clickedItem.get("description");
taskForLatLng.execute("placeid=" + clickedItem.get("place_id"));
}
});
}
Here is the async task where the delay happends.
I've marked where the delay happends
public class PlacesTask extends AsyncTask<String, Void, String>{
private OnTaskCompleted listener;
String typeOfResult;
String url = null;
public PlacesTask(OnTaskCompleted callerListener, String type) {
this.listener = callerListener;
this.typeOfResult = type;
switch (type) {
case "getPredictions":
url = "https://maps.googleapis.com/maps/api/place/autocomplete/";
break;
case "getPlaceLatLng":
url = "https://maps.googleapis.com/maps/api/place/details/";
break;
}
// this case is if we+re tying to get place name from latlng
if (type.contains(","))
url = "https://maps.googleapis.com/maps/api/geocode/";
}
#Override
protected String doInBackground(String... place) {
Log.e("places task", "usao je tu");
String data = "";
String APIkey = "key=AIzaSyC5gP63PPD8CQLCXqbkZZf6XvOhZPnoe-s";
/**
//place type to be searched
String types = "types=geocode";
// our app didn't use any sensor to determinate the location
String sensor = "sensor=false";
*/
String parameters, outputFormat;
// building paramters for search
parameters = place[0] + "&" + APIkey;
// output format
outputFormat = "json";
try {
// fetching the data from web service
data = downloadUrl(url + outputFormat + "?" + parameters);
} catch(Exception e) {
/**
* activate error screen
*/
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// create parser task to parse the gotten results
ParserTask parserTask = new ParserTask(listener, typeOfResult);
// start the parsing
parserTask.execute(result);
}
// private method used in the PlacesTask to download the data from the url
private String downloadUrl(String inputUrl) throws IOException{
String data = "";
InputStream is = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(inputUrl);
//creating http connection to comunicate eith url
urlConnection = (HttpURLConnection) url.openConnection();
Log.e("places task", "3");
/*
*
* HERE IS WHERE THE DELAY HAPPENDS
*/
**urlConnection.connect();**
// reading from url
is = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer sb = new StringBuffer();
String line = "";
while( (line = br.readLine()) != null ) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
e.printStackTrace();
/**
* activate error screen
*/
} finally {
is.close();
urlConnection.disconnect();
}
Log.e("places task data", data);
return data;
}
}
i didn't want to post ParserTask and GooglePlacesJSONParser so the question wouldn't be that long but if someone is intereested in those classes just add comment and i will update my question
Please try with this link..
http://wptrafficanalyzer.in/blog/android-autocompletetextview-with-google-places-autocomplete-api/
Onece I did used this Turorial... And Its working properly.
I'm not sure why you are experiencing a delay, possibly it is a network issue or something in the other classes. But if you would like to try a library that provides a GooglePlaceAutoComplete widget, you could take a look at Sprockets (I'm the developer).
After the library is configured with your Google API key, you can add a GooglePlaceAutoComplete element to your layout. For example:
<net.sf.sprockets.widget.GooglePlaceAutoComplete
android:id="#+id/place"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
And then you can get the Place that a user selects by setting an OnPlaceClickListener.
public void onPlaceClick(AdapterView<?> parent, Prediction place, int position) {
/* do something with the Place */
}

Android: how do i parse this mixed up json response

The only thing that's guaranteed to always be there is the messagesByDate obj.
The array and objects named such as "15 MAY 2012" are generated by a server(no control) based on rather or not messages are present for that date.
If u notice the first date represented is an array while the other dates are objects containing other objects that have been numbered.
QUESTION 1: how do i parse this without knowing what dates will be present?
QUESTION 2: Some messages are in an array instead of an object. how do I put them all together in one ArrayList. Rather its in an array or not because the array will not always been there.
Please any help would be appreciated as I'm down to my last hair
Thanks.
{
"messagesByDate":{
"15 May 2012":[
{
"id":"1383483367",
"conversation_id":"274618561",
"user_id":"4318264",
"message":"ok will do",
"date_sent":"1337133515",
"date_sent_ago":"7 mins ago"
},
{
"id":"1380222533",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"ok well hmu",
"date_sent":"1337085122",
"date_sent_ago":"13 hrs ago"
},
{
"id":"1380172978",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"superhead",
"date_sent":"1337083910",
"date_sent_ago":"13 hrs ago"
},
{
"id":"1380130860",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"you ready B",
"date_sent":"1337082797",
"date_sent_ago":"14 hrs ago"
},
{
"id":"1378841432",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"hit my cell tho",
"date_sent":"1337054524",
"date_sent_ago":"22 hrs ago"
},
{
"id":"1378836763",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"whats up baby",
"date_sent":"1337054475",
"date_sent_ago":"22 hrs ago"
}
],
"12 May 2012":{
"6":{
"id":"1362948558",
"conversation_id":"274618561",
"user_id":"4318264",
"message":"ok ima text u",
"date_sent":"1336819668",
"date_sent_ago":"3 days ago"
}
},
"11 May 2012":{
"7":{
"id":"1361356267",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"yea thats cool",
"date_sent":"1336790738",
"date_sent_ago":"3 days ago"
},
"8":{
"id":"1357783913",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"sorry im here. would u like to exchange numebers instead?",
"date_sent":"1336722533",
"date_sent_ago":"4 days ago"
},
"9":{
"id":"1357759262",
"conversation_id":"274618561",
"user_id":"5159567",
"message":"hello?",
"date_sent":"1336721851",
"date_sent_ago":"4 days ago"
}
}
}
}
THE ANSWER SORTA-KINDA
JSONObject dateHolder = r.getJSONObject("messagesByDate");
Iterator holderItr = dateHolder.keys();
while(holderItr.hasNext()){
String thisdate = holderItr.next().toString();
Object date = dateHolder.get(thisdate);
if (date instanceof JSONArray) {
System.out.println(thisdate+" is an ARRAY.");
JSONArray jarray = (JSONArray) date;
for(int x=0;x<jarray.length();x++){
String msgId = jarray.getJSONObject(x).getString("id");
String msgConvoId = jarray.getJSONObject(x).getString("conversation_id");
String msgUserId = jarray.getJSONObject(x).getString("user_id");
String msgBody = jarray.getJSONObject(x).getString("message");
String msgDateSent = jarray.getJSONObject(x).getString("date_sent");
String msgDateSentAgo = jarray.getJSONObject(x).getString("date_sent_ago");
HashMap<String,String> temp = new HashMap<String,String>();
temp.put("msgId",msgId);
temp.put("msgUserId", msgUserId);
temp.put("msgBody", msgBody);
temp.put("msgDateSent", msgDateSent);
temp.put("msgDateSentAgo", msgDateSentAgo);
messages.add(temp);
}
} else {
System.out.println(thisdate+" is an OBJECT.");
JSONObject jobj = (JSONObject) date;
Iterator insideDate = jobj.keys();
while(insideDate.hasNext()){
String number = insideDate.next().toString();
System.out.println(number);
String msgId = jobj.getJSONObject(number).getString("id");
String msgConvoId = jobj.getJSONObject(number).getString("conversation_id");
String msgUserId =jobj.getJSONObject(number).getString("user_id");
String msgBody = jobj.getJSONObject(number).getString("message");
String msgDateSent = jobj.getJSONObject(number).getString("date_sent");
String msgDateSentAgo = jobj.getJSONObject(number).getString("date_sent_ago");
HashMap<String,String> temp = new HashMap<String,String>();
temp.put("msgId",msgId);
temp.put("msgUserId", msgUserId);
temp.put("msgBody", msgBody);
temp.put("msgDateSent", msgDateSent);
temp.put("msgDateSentAgo", msgDateSentAgo);
messages.add(temp);
}
}
}
This gives me all the messages in a HashMap and adds it to an ArrayList called messages like I want but its out of order by date. the json is listed by date...anyone know if there is a way to direct json reading? OR are my WHILE and FOR loops out of order? can i sort hashmaps by a key? I'll google that...
First create a class like this:
import java.util.LinkedList;
import android.util.Log;
public class Message{
private LinkedList<String> id = new LinkedList<String>();
private LinkedList<String> conversation_id = new LinkedList<String>();
private LinkedList<String> user_id = new LinkedList<String>();
private LinkedList<String> message = new LinkedList<String>();
private LinkedList<String> date_sent = new LinkedList<String>();
private LinkedList<String> date_sent_ago = new LinkedList<String>();
public LinkedList<String> getId() {
return id;
}
public void setId(String id) {
this.id.add(id);
}
.
.
.
// For checking response after you get info from server
public void printContent() {
for(String str : id)
Log.i("Id>>>", str);
.
.
.
}
}
Then you need to call server in onCreate() add this code:
if(Manager.isOnline(this)) // Check Internet connection and if you find it then
new MyAsyncTask().execute();
Now, you should add this class:
public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
Log.i(TAG, "MyAsyncTask is about to start...");
showProgressBar();
}
#Override
protected Boolean doInBackground(Void... params) {
boolean status = false;
// Get News items in json format
msg = getMessageItems(); // msg is an instance of Message class define it as global variable.
msg.printContent(); // Check result in logcat
if(msg != null)
status = true;
return status;
}
#Override
protected void onPostExecute(Boolean result) {
Log.i(TAG, "MyAsyncTask finished its task. Data returned to caller.");
if(result)
displayData();
hideProgressBar();
}
}
Here we will connect to server, get Json data and parse it.
private Menu getMenuItems() {
Message mMessage = new Message ();
String response = null;
String connection = **YOUR_URL**;
try {
URL url = new URL(connection);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
int responseCode = conn.getResponseCode();
Log.i(TAG, "Try to open: " + connection);
Log.i(TAG, "Response code is: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
if (in != null) {
StringBuilder strBuilder = new StringBuilder();
// Read character by character
int ch = 0;
while ((ch = in.read()) != -1)
strBuilder.append((char) ch);
// get returned message and show it
response = strBuilder.toString();
Log.i("JSON returned by server:", response);
JSONObject jObject = new JSONObject(response);
JSONArray contestantObjects = jObject.getJSONArray("**messagesByDate**");
for(int i=0; i<contestantObjects.length(); i++){
mMessage .setId(contestantObjects.getJSONObject(i).getString("id").toString());
// Repeat this to get all of other items
}
}
in.close();
} else
Log.e(TAG, "Couldn't open connection in getMenuItems()");
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return mMessage;
}
Now you have an object that each of its item is a list. You can do whatever you want in display method. you can pass it as an object to adapter to show its data.
private void displayData() {
messageAdapter.setData(msg);
listView.setAdapter(messageAdapter);
}
JSONObject json = service.getJunk();
JSONObject msgJson = json.getJSONObject("messagesByDate");
for( Iterator it = msgJson.keys(); it.hasNext(); ) {
Object obj = msgJson.get( (String)it.next() );
if( obj instanceof JSONObject ) {
JSONObject jobj = (JSONObject)obj;
// process json object
} else {
JSONArray arry = (JSONArray)obj;
// process array
}
}

Categories

Resources