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.
Related
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();
}
}
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.
The problem is i can't figure out why the grid won't filled with the images, the first time i run the app. If i do refresh or change to landscape mode the images load and the app works fine. I assume it has to be the List that i gave to the Adapter, somehow i lost his reference the first time and when the onCreateView calls again(refresh/landscape) it gets fixed. i tried to change the places where i define the adaptor, the list, etc and some methods too like setGridData but it doesn't work. Maybe you can help me
This is the code of the Fragment and the asynkTask(by the way it works fine).
public class MovieFragment extends Fragment {
private GridViewAdapter mGridViewAdapter;
private ArrayList<Movie> mMovieList = new ArrayList<Movie>();
public MovieFragment() {
}
#Override
public void onStart() {
super.onStart();
FetchMoviesTask movieTask = new FetchMoviesTask();
movieTask.execute("popular");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.moviefragment, 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();
if (id == R.id.action_refresh) {
FetchMoviesTask movieTask = new FetchMoviesTask();
movieTask.execute("popular");
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.moviefragment, container, false);
mGridViewAdapter = new GridViewAdapter(getActivity(),R.layout.movie_list_item, mMovieList);
GridView movieGrid= (GridView) rootView.findViewById(R.id.gridview_movie);
movieGrid.setAdapter(mGridViewAdapter);
return rootView;
}
public class FetchMoviesTask extends AsyncTask<String, Void, Movie[]> {
private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();
private Movie[] getMoviesDataFromJson(String moviesJsonStr) throws JSONException{
final String OMDB_RESULTS="results";
final String OMBD_POSTER_PATH="poster_path";
final String OMBD_RELEASE_DATE="release_date";
final String OMBD_OVERVIEW="overview";
final String OMBD_ORIGINAL_TITLE="original_title";
final String OMBD_VOTE_AVERAGE="vote_average";
final String url= "http://image.tmdb.org/t/p/";
final String imageSize="w185";
JSONObject moviesJson = new JSONObject(moviesJsonStr);
JSONArray moviesArray = moviesJson.getJSONArray(OMDB_RESULTS);
Movie[] results = new Movie[moviesArray.length()];
//CUIDADO ACA NO SE SI SE PASA POR UNO
for (int i=0; i<moviesArray.length();i++){
JSONObject movie=moviesArray.getJSONObject(i);
Movie index=new Movie();
index.setPoster_path(url+imageSize+movie.getString(OMBD_POSTER_PATH));
index.setOriginalTitle(movie.getString(OMBD_ORIGINAL_TITLE));
index.setOverview(movie.getString(OMBD_OVERVIEW));
index.setReleaseDate(movie.getString(OMBD_RELEASE_DATE));
index.setVoteAverage(movie.getDouble(OMBD_VOTE_AVERAGE));
results[i]=index;
}
return results;
}
#Override
protected Movie[] doInBackground(String... params) {
Movie[] imageMovies;
// If there's no zip code, there's nothing to look up. Verify size of params.
if (params.length == 0) {
return null;
}
// 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 moviesJsonStr = 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 MOVIE_BASE_URL =
"https://api.themoviedb.org/3/movie/"+params[0];
final String APPID_PARAM = "api_key";
Uri builtUri = Uri.parse(MOVIE_BASE_URL).buildUpon()
.appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_MOVIEDB_API_KEY)
.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();
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) {
// 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;
}
moviesJsonStr = buffer.toString();
imageMovies = getMoviesDataFromJson(moviesJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} catch (JSONException e) {
Log.e(LOG_TAG, "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(LOG_TAG, "Error closing stream", e);
}
}
}
return imageMovies;
}
#Override
protected void onPostExecute(Movie[] movies) {
if(movies!=null){
mGridViewAdapter.setGridData(Arrays.asList(movies));
}
}
}
}
And this is the code of the Adapter:
public class GridViewAdapter extends ArrayAdapter {
private static final String LOG_TAG = GridViewAdapter.class.getSimpleName();
private Context mContext;
private int mLayoutResourceId;
private ArrayList<Movie> mGridData;
/**
* This is our own custom constructor (it doesn't mirror a superclass constructor).
* The context is used to inflate the layout file, and the List is the data we want
* to populate into the lists
*
* #param context The current context. Used to inflate the layout file.
* #param movieList A List of AndroidFlavor objects to display in a list
*/
public GridViewAdapter(Activity context, int layoutResourceId, ArrayList<Movie> movieList) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, layoutResourceId, movieList);
mContext=context;
mLayoutResourceId=layoutResourceId;
mGridData=movieList;
}
/**
* Updates grid data and refresh grid items.
*/
public void setGridData(List<Movie> movies) {
mGridData.clear();
mGridData.addAll(movies);
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ImageView imageView;
if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(mLayoutResourceId, parent, false);
imageView = (ImageView) row.findViewById(R.id.list_item_movie_imageview);
row.setTag(imageView);
} else {
imageView = (ImageView) row.getTag();
}
Movie movie = mGridData.get(position);
Picasso.with(mContext).load(movie.getPoster_path()).into(imageView);
Log.d(LOG_TAG,movie.getOriginalTitle());
return row;
}
}
The movie class is a simple class with the data. The log in the getView() method pop up only once in the first run, but it has to be 20 times.
I had a similar issue with this project as well. Try the following:
mGridViewAdapter.notifyDataSetChanged()
Currently. you're not calling it on any object. If that doesn't work, try this method instead:
mGridViewAdapter.notifyDataSetInvalidated()
Further reading: How to refresh Android listview?
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()
I am getting a compile time errors:
The method replace(int, Fragment, String) in the type FragmentTransaction is not applicable for the arguments (int, VideoListFragment, String) at Line 91
VideoActivity.java:
package com.sit.loco.activity;
import android.support.v4.app.Fragment;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.loco.android.R;
import com.sit.loco.frgment.VideoListFragment;
public class VideoActivity extends SherlockFragmentActivity
implements ActionBar.OnNavigationListener, VideoListFragment.OnVideoSelectedListener{
// create object of ActionBar and VideoListFragment
ActionBar actionbar;
VideoListFragment videoListFrag;
int selectedItem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
}
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
selectedItem = itemPosition;
// create object of VideoListFragment and send data position to that fragment
videoListFrag = new VideoListFragment();
Bundle bundle = new Bundle();
bundle.putInt("position", itemPosition);
videoListFrag.setArguments(bundle);
// call video list fragment with new data
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, videoListFrag, "VIDEO_LIST_FRAGMENT")
.commit(); ---->Error at Line 91
return true;
}
}
MyFragmentPagerAdapter.java:
Type mismatch: cannot convert from VideoListFragment to Fragment at Line 68
package com.sit.loco.provider;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 6;
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
/** This method will be invoked when a page is requested to create */
#Override
public Fragment getItem(int arg0) {
Bundle data = new Bundle();
switch (arg0) {
case 4:
VideoListFragment videoList = new VideoListFragment();
data.putInt("position", arg0);
videoList.setArguments(data);
return videoList; ---->Error at Line 68
}
return null;
}
/** Returns the number of pages */
#Override
public int getCount() {
return PAGE_COUNT;
}
}
EDIT:
VideoListFragment.java:
package com.sit.loco.frgment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.loco.android.R;
import com.sit.loco.provider.VideoListAdapter;
public class VideoListFragment extends SherlockFragmentActivity {
OnVideoSelectedListener mCallback;
boolean loadingMore = false;
// create string variables
String YOUTUBE_USERNAME = "";
private String YOUTUBE_API = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_USERNAME+"/uploads?alt=jsonc" +
"&v=2"+
"&start-index=1"+
"&max-results=10";
// create object of views
ListView list;
ProgressBar prgLoading;
Button btnRefresh;
Button btnLoadMore;
// create variable to get position, connection status, resources, and channel username
int position;
boolean isConnect = true;
Resources res;
String[] ChannelUsername;
// create object of custom adapter
VideoListAdapter vla;
// create arraylist variables
ArrayList<HashMap<String, String>> menuItems;
ProgressDialog pDialog;
// flag for current page
int current_page = 1;
int previous_page;
static final String KEY_ID = "id";
static final String KEY_TITLE = "title";
static final String KEY_THUMBNAIL = "thumbnail";
static final String KEY_DURATION = "duration";
// create interface listener
public interface OnVideoSelectedListener{
public void onVideoSelected(String ID);
}
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_list);
// connect view objects and view id on xml
list = (ListView)findViewById(R.id.list);
// prgLoading = (ProgressBar) v.findViewById(R.id.prgLoading);
btnRefresh = (Button)findViewById(R.id.btnRefresh);
menuItems = new ArrayList<HashMap<String, String>>();
// get value that passed from previous page
Bundle bundle = this.getArguments();
position = bundle.getInt("position", 0);
// get channel username and put selected channel to youtube api
res = getActivity().getResources();
ChannelUsername = res.getStringArray(R.array.channel_username);
YOUTUBE_USERNAME = ChannelUsername[position];
YOUTUBE_API = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_USERNAME+"/uploads?alt=jsonc" +
"&v=2"+
"&start-index=1"+
"&max-results=10";
// create LoadMore button
btnLoadMore = new Button(getActivity());
btnLoadMore.setBackgroundResource(R.drawable.btn_default_holo_light);
btnLoadMore.setText(getString(R.string.load_more));
// adding load more button to lisview at bottom
list.addFooterView(btnLoadMore);
new loadFirstListView().execute();
// listener to handle load more buttton when clicked
btnLoadMore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Starting a new async task
isConnect = true;
new loadMoreListView().execute();
}
});
// listener to handle list when clicked
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
HashMap<String, String> item = new HashMap<String, String>();
item = menuItems.get(position);
mCallback.onVideoSelected(item.get("id"));
list.setItemChecked(position, true);
}
});
// listener to handle refresh button when clicked
btnRefresh.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
isConnect = true;
new loadFirstListView().execute();
}
});
}
private Bundle getArguments() {
// TODO Auto-generated method stub
return null;
}
private Context getActivity() {
// TODO Auto-generated method stub
return null;
}
public void onAttach(Fragment activity) {
super.onAttachFragment(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (OnVideoSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
// load first 10 videos
private class loadFirstListView extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
pDialog = new ProgressDialog(
getActivity());
pDialog.setMessage("Please wait..");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
pDialog.show();
}
private Context getActivity() {
// TODO Auto-generated method stub
return null;
}
protected Void doInBackground(Void... unused) {
try {
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 15000);
HttpConnectionParams.setSoTimeout(client.getParams(), 15000);
// Perform a GET request to YouTube for a JSON list of all the videos by a specific user
HttpUriRequest request = new HttpGet(YOUTUBE_API);
// Get the response that YouTube sends back
HttpResponse response = client.execute(request);
// Convert this response into an inputstream for the parser to use
InputStream atomInputStream = response.getEntity().getContent();
BufferedReader in = new BufferedReader(new InputStreamReader(atomInputStream));
//BufferedReader in = new BufferedReader(new InputStreamReader(tc.getInputStream()));
String line;
String str = "";
while ((line = in.readLine()) != null){
str += line;
}
JSONObject json = new JSONObject(str);
JSONObject dataObject = json.getJSONObject("data"); // this is the "data": { } part
JSONArray items = dataObject.getJSONArray("items"); // this is the "items: [ ] part
for (int i = 0; i < items.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject youtubeObject = items.getJSONObject(i);
map.put(KEY_ID, youtubeObject.getString("id")); // id not using any where
map.put(KEY_TITLE, youtubeObject.getString("title"));
map.put(KEY_THUMBNAIL, youtubeObject.getJSONObject("thumbnail").getString("hqDefault"));
String duration = secondToTime(youtubeObject.getInt("duration"));
map.put(KEY_DURATION, duration);
// adding HashList to ArrayList
menuItems.add(map);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
isConnect = false;
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (null);
}
protected void onPostExecute(Void unused) {
// closing progress dialog
pDialog.dismiss();
if(isAdded()){
if(isConnect){
btnRefresh.setVisibility(View.GONE);
// Getting adapter
vla = new VideoListAdapter(getActivity(), menuItems);
list.setAdapter(vla);
}else{
btnRefresh.setVisibility(View.VISIBLE);
Toast.makeText(getActivity(), getString(R.string.no_connection), Toast.LENGTH_SHORT).show();
}
}
}
}
// load more videos
private class loadMoreListView extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
pDialog = new ProgressDialog(
getActivity());
pDialog.setMessage("Please wait..");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
pDialog.show();
}
protected Void doInBackground(Void... unused) {
// store previous value of current page
previous_page = current_page;
// increment current page
current_page += 10;
YOUTUBE_API = "http://gdata.youtube.com/feeds/api/users/"+YOUTUBE_USERNAME+"/uploads?alt=jsonc" +
"&v=2"+
"&start-index="+current_page+
"&max-results=10";
try {
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 15000);
HttpConnectionParams.setSoTimeout(client.getParams(), 15000);
// Perform a GET request to YouTube for a JSON list of all the videos by a specific user
HttpUriRequest request = new HttpGet(YOUTUBE_API);
// Get the response that YouTube sends back
HttpResponse response = client.execute(request);
// Convert this response into an inputstream for the parser to use
InputStream atomInputStream = response.getEntity().getContent();
BufferedReader in = new BufferedReader(new InputStreamReader(atomInputStream));
//BufferedReader in = new BufferedReader(new InputStreamReader(tc.getInputStream()));
String line;
String str = "";
while ((line = in.readLine()) != null){
str += line;
}
JSONObject json = new JSONObject(str);
JSONObject dataObject = json.getJSONObject("data"); // this is the "data": { } part
JSONArray items = dataObject.getJSONArray("items"); // this is the "items: [ ] part
for (int i = 0; i < items.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject youtubeObject = items.getJSONObject(i);
map.put(KEY_ID, youtubeObject.getString("id")); // id not using any where
map.put(KEY_TITLE, youtubeObject.getString("title"));
map.put(KEY_THUMBNAIL, youtubeObject.getJSONObject("thumbnail").getString("hqDefault"));
String duration = secondToTime(youtubeObject.getInt("duration"));
map.put(KEY_DURATION, duration);
// adding HashList to ArrayList
menuItems.add(map);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
isConnect = false;
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (null);
}
protected void onPostExecute(Void unused) {
// closing progress dialog
pDialog.dismiss();
if(isConnect){
// get listview current position - used to maintain scroll position
int currentPosition = list.getFirstVisiblePosition();
btnRefresh.setVisibility(View.GONE);
// Appending new data to menuItems ArrayList
vla = new VideoListAdapter(
getActivity(),
menuItems);
list.setAdapter(vla);
// Setting new scroll position
list.setSelectionFromTop(currentPosition + 1, 0);
}else{
if(menuItems != null){
current_page = previous_page;
btnRefresh.setVisibility(View.GONE);
}else{
btnRefresh.setVisibility(View.VISIBLE);
}
Toast.makeText(getActivity(), getString(R.string.no_connection), Toast.LENGTH_SHORT).show();
}
}
private Context getActivity() {
// TODO Auto-generated method stub
return null;
}
}
// method to convert second to hours, minutes, and seconds
String secondToTime(int duration){
String time = "";
String Hours = "";
String Minutes = "";
String Seconds = "";
double hours = 0.0;
double minutes = 0.0;
double seconds = 0.0;
DecimalFormat df = new DecimalFormat("#.####");
hours = duration / 3600;
minutes = (duration % 3600) /60;
seconds = duration % 60;
if((hours < 10) && (hours > 0)){
Hours = "0" + df.format(hours);
}else if(hours == 0){
Hours = "00";
}else{
Hours = df.format(hours);
}
if((minutes < 10) && (minutes > 0)){
Minutes = "0" + df.format(minutes);
}else if(minutes == 0){
Minutes = "00";
}else{
Minutes = df.format(minutes);
}
if((seconds < 10) && (seconds > 0)){
Seconds = "0" + df.format(seconds);
}else if(seconds == 0){
Seconds = "00";
}else{
Seconds = df.format(seconds);
}
time = Hours +":"+Minutes+":"+Seconds;
return time;
}
public boolean isAdded() {
// TODO Auto-generated method stub
return false;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
vla.imageLoader.clearCache();
Log.d("clear cache", "clear cache");
}
public void setArguments(Bundle data) {
// TODO Auto-generated method stub
}
}
I am spending lot of time to solve this errors.But I don't know how to solve this compile time errors.Anybody can help me with this.Thank you.
Your VideoListFragment extends the SherlockFragmentActivity class but should extends Fragment instead.
import android.support.v4.app.Fragment;
public class VideoListFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.fragment_list, container, false);
list = (ListView)view .findViewById(R.id.list);
btnRefresh = (Button)view .findViewById(R.id.btnRefresh);
return view;
}