I'm working on an Android app that is going to call the DarkSky weather API (I have redacted my API key here for obvious reasons). My problem comes when I parse the JSON data and push it to a stack I named dataStack. At the time of pushing the stack I log its size and it shows correctly. However when my code reaches the buildGraph() method, the stack is now empty and all my data has disappeared. What causes the stack to empty?
EDIT: As of 30 minutes after posting I found a workaround. I am now returning the String and parsing it in my MainActivity Android class. However, I still do not know why the stack was being deleted. I would love to know :)
public class MainActivity extends AppCompatActivity {
Button button;
TextView progressLabel;
GraphView graph;
JSONObject jsonObject;
static Stack<DataPoint> dataStack = new Stack<>(); // stack for graph data points
static final String API_URL = "https://api.darksky.net/forecast/API_KEY/42.3611,-71.0570,"; // #TODO: delete API key before comitting to GitHub
static final String URL_TAIL = "?exclude=currently,flags,hourly"; // end of URL
static final long currTime = System.currentTimeMillis() / 1000L; // current UNIX time
static long unixTime = currTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
progressLabel = findViewById(R.id.progressLabel);
graph = findViewById(R.id.graph);
}
public void loadResults(View view) {
for (int x = 0; x < 2; x++) { // 7 API calls for each of 7 days
new APICall().execute();
unixTime -= 86400; // subtract 24 hours in UNIX time
dataStack.size();
}
buildGraph(); // after all data is gathered, build a graph using it
}
private void buildGraph() {
// #TODO: Method to build graph
Log.i("STACK pop", String.valueOf(dataStack.size()));
}
class APICall extends AsyncTask<Void, Void, String> { // Extend AsyncTask so we don't hijack the main UI thread
protected void onPreExecute() {
// Do stuff before executing the AsyncTask
progressLabel.setText("Fetching Data");
}
protected String doInBackground(Void... urls) {
// Execute background task here
try {
final String FULL_URL = API_URL + unixTime + URL_TAIL; // build the full URL with latest time
URL url = new URL(FULL_URL); // URL for the API call
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // connection to URL
try {
// tools for reading API results
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
// accumulate results
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close(); // always close buffered reader
return stringBuilder.toString(); // return results
}
finally {
// inside a finally block so that no matter what we always end a connection that has been started
urlConnection.disconnect(); // end the connection
}
}
catch(Exception ex) {
Log.e("ERROR", ex.getMessage(), ex);
return null;
}
}
protected void onPostExecute(String response) {
// Do stuff after we're finished executing
if (response == null) {
response = "AN ERROR HAS OCCURRED";
}
else {
try {
jsonObject = new JSONObject(response); // create object from our response
JSONArray arr = jsonObject.getJSONObject("daily").getJSONArray("data"); // get data Array
String arrString = arr.getString(0); // full String
String[] splitString = arrString.split(","); // split String into array by comma
String time = splitString[0].substring(8); // time is the first index of the array, use substring to cutout unecessary info
String temp = splitString[11].substring(18);
dataStack.push(new DataPoint(Integer.valueOf(time), Float.valueOf(temp))); // push our data onto the stack as a DataPoint
Log.i("STACK push", String.valueOf(dataStack.toString()));
response = "Data received"; // display this to user
}
catch(Exception ex) {
response = "ERROR DURING JSON PARSING";
}
}
progressLabel.setText(response);
// parse data here
Log.i("INFO", response);
}
}
}
The stack is empty because result isn't in yet. The issue is with your loadResults().
public void loadResults(View view) {
for (int x = 0; x < 2; x++) { // 7 API calls for each of 7 days
new APICall().execute();
unixTime -= 86400; // subtract 24 hours in UNIX time
dataStack.size();
}
buildGraph(); // after all data is gathered, build a graph using it
}
You issued the new APICall().execute(); to request data and update the dataStack and you expect to get the dataStack results 'immediately' inside the same function loadResults()? It's not possible.
One solution is to remove the buildGraph() in loadResults() to inside onPostExecute().
Related
This question already has answers here:
Android 8: Cleartext HTTP traffic not permitted
(37 answers)
Closed 2 years ago.
I'm building an application on Android Studio that retrieves weather information in real time thanks to OpenWeatherMap and the API they offer.
The problem is, I'm using two phones with different SDKs. One is SDK 23 / Android 6.0 and the other is SDK 28 / Android 9.0.
Currently on the phone with SDK 23 I have no problem. However on the phone with SDK 28 I have a NullPointerException error. My second activity allows me to display information for city X and its weather information. So, finally the error I'm encountering on the phone with SDK 28 is this one :
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
I've looked into a lot of things to see where that could have come from, if it wasn't my AsyncTask or whatever, but I really don't see it.
Knowing that on the phone with the oldest version of Android it retrieves well the information from my editText that on the most recent version it doesn't retrieve it at all and the nullpointerException must come from there.
Do you know where this might be coming from?
Here is my AsyncTask :
public class ExecuteTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
HttpURLConnection con = null ;
InputStream is = null;
try {
con = (HttpURLConnection) ( new URL(strings[0])).openConnection();
con.setRequestMethod("GET");
con.setDoInput(true);
con.setDoOutput(true);
con.connect();
// Let's read the response
StringBuffer buffer = new StringBuffer();
is = con.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ( (line = br.readLine()) != null )
buffer.append(line + "\r\n");
is.close();
con.disconnect();
return buffer.toString();
}
catch(Throwable t) {
t.printStackTrace();
}
finally {
try { is.close(); } catch(Throwable t) {}
try { con.disconnect(); } catch(Throwable t) {}
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
String message = "";
String degre="";
String idMeteo="";
JSONObject jsonObject = new JSONObject(s);
String infoWeatherToday = jsonObject.getString("weather");
JSONObject WeatherTemperature = jsonObject.getJSONObject("main");
Integer deg = WeatherTemperature.getInt("temp");
deg = deg - 273;
JSONArray array = new JSONArray(infoWeatherToday);
int tablongueur=array.length();
for (int i = 0; i < tablongueur; i++) {
JSONObject jsonSecondary = array.getJSONObject(i);
String main = "";
//Integer id;
main = jsonSecondary.getString("main");
// id = jsonSecondary.getInt("id");
switch (main) {
case "Clouds":
main = "Nuageux";
PhotoMeteo.setImageResource(R.drawable.cloud);
break;
case "Clear":
main = "Ensoleillé";
PhotoMeteo.setImageResource(R.drawable.sun);
break;
case "Rain":
main = "Pluie";
PhotoMeteo.setImageResource(R.drawable.rain);
break;
case "Snow":
main = "Neige";
PhotoMeteo.setImageResource(R.drawable.snow);
break;
case "Smoke":
main = "Brouillard";
PhotoMeteo.setImageResource(R.drawable.smoke);
break;
case "Drizzle":
main = "Brumeux";
PhotoMeteo.setImageResource(R.drawable.drizzle);
break;
default:
main = "Météo introuvable !";
PhotoMeteo.setImageResource(R.drawable.ic_warning);
}
if (main != "" /*&& id != null*/) {
message += main + "\r\n";
degre += deg + "°C";
//idMeteo += "L'id de la météo est" + id;
}
}
if (message != "") {
resultWeather.setText(message);
resultDegre.setText(degre);
//resultIdMeteo.setText(idMeteo);
} else {
Toast.makeText(AccueilActivity.this, "Une erreur a eu lieu ", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
And here is the intent that I keep from my first activity called RegisterActivity to give it as a parameter for the "name" of the city
Intent intent = new Intent(RegisterActivity.this, AccueilActivity.class);
intent.putExtra(EXTRA_TEXT,cityField.getText().toString());
startActivity(intent);
In my 2nd activity called "AccueilActivity"
Intent intent = getIntent();
if(intent!=null)
{
textViewVille.setText(intent.getStringExtra(EXTRA_TEXT));
ville = intent.getStringExtra(EXTRA_TEXT);
FindWeather();
}
And my final function called FindWeather which execute the AsyncTask
public void FindWeather() {
cityToFind = ville;
try {
ExecuteTask tasky = new ExecuteTask();
tasky.execute("http://api.openweathermap.org/data/2.5/weather?q=" + cityToFind + "&APPID={MYAPKKEY}&LANG=fr&UNITS=metric");
} catch (Exception e) {
e.printStackTrace();
}
}
Just I don't give you the value of my APK Key because it isn't something interesting but the value is present in the initial code.
If I have a last things to add, ville is a simple TextView and cityToFind the value of my editText on the first activity.
If you need anything of my source code I can give you more.
Thank you.
doInBackground is going to return null if there is any exception in your HTTP code.
That is passed to onPostExecute as the parameter.
You then try to constuct a JSONObject(null), which is an invalid argument
All in all, please pick a higher level HTTP library with fault tolerance built in
Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley
I also suggest writing unit tests outside of that class and running them from the IDE rather than a device, so you verify the network calls actually work.
Application fetches data from OpenWeatherMap API and works correctly when I indicate a city, e.g. "London". There is an error when I replace "London" with a variable "place".. Underneath you can find the code.
Can anyone help me?
**MAIN ACTIVITY**
public class MainActivity extends AppCompatActivity {
//create the fields on the Activity
private TextView cityName;
private TextView temp;
private TextView description;
private TextView humidity;
private TextView pressure;
private TextView wind;
private TextView sunrise;
private TextView sunset;
private TextView updated;
private Exception error;
Weather weather = new Weather();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up all the resources for the Views here
cityName = (TextView)findViewById(R.id.cityText);
temp = (TextView)findViewById(R.id.tempText);
description = (TextView)findViewById(R.id.CloudText);
humidity = (TextView)findViewById(R.id.HumidText);
pressure = (TextView)findViewById(R.id.PressureText);
wind = (TextView)findViewById(R.id.WindText);
sunrise = (TextView)findViewById(R.id.RiseText);
sunset = (TextView)findViewById(R.id.SetText);
updated = (TextView)findViewById(R.id.UpdateText);
//instantiate a CityPreference object from the MainActivity that
carries the city with it..
//render the data based on the city you get through the parsing
CityPreference cityPreference = new CityPreference(MainActivity.this);
renderWeatherData(cityPreference.getCity());
}
public void renderWeatherData (String city){
// we want to do all of our tasks in the background, use AsyncTask for this
WeatherTask weatherTask = new WeatherTask();
weatherTask.execute(new String[]{city} + "&units=metric");
}
//last parameter is Weather, this is what we will be populating
private class WeatherTask extends AsyncTask<String, Void, Weather>{
//AsyncTask <PARAMETERS, TASK, RESULT>
#Override
protected Weather doInBackground(String... params) {
//background computation
//data variable holds all the data that we have got..
//instantiate the weather client and get the weather data..
//getWeatherData gets all necessary data from HTTPClient
//getWeather parses all the data from the JSONParser
try {
String data = ((new WeatherHTTPClient().getWeatherData(params[0])));
weather = JSONWeatherParser.getWeather(data);
//create a log to test if everything is working
Log.v("Data:",weather.currentCondition.getDescription());
return weather;
} catch (Exception e) {
error = e;
}
return null;
}
//here you will populate the data so you can show it to the user
#Override
protected void onPostExecute(Weather weather) {
super.onPostExecute(weather);
try {
//gets time and decimal formats and applies it to the data underneath
DateFormat df = DateFormat.getTimeInstance();
String sunriseDate = df.format(new Date(Weather.place.getSunrise()));
String sunsetDate = df.format(new Date(Weather.place.getSunset()));
String updateDate = df.format(new Date(Weather.place.getLastupdate()));
DecimalFormat decimalFormat = new DecimalFormat("#.#");
String tempFormat = decimalFormat.format(weather.currentCondition.getTemperature());
//gets the value from the JSON and parses it in the view of the activity
cityName.setText(weather.place.getCity() + "," + weather.place.getCountry());
temp.setText("" + tempFormat + "C");
humidity.setText("Humidity" + weather.currentCondition.getHumidity() + "%");
pressure.setText("Pressure" + weather.currentCondition.getPressure() + "hPa");
wind.setText("Wind" + weather.wind.getSpeed() + "mps");
sunrise.setText("Sunrise" + sunriseDate);
sunset.setText("Sunset" + sunsetDate);
updated.setText("Updated" + updateDate);
description.setText("Condition" + weather.currentCondition.getCondition() + "(" + weather.currentCondition.getDescription() + ")");
} catch(Exception e) {
error = e;
}
}
}
//create an alert dialog to put in the city you want to parse the data for - A subclass of Dialog that can display one, two or three buttons.
private void showInputDialog () {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Change City");
final EditText cityInput = new EditText(MainActivity.this);
cityInput.setInputType(InputType.TYPE_CLASS_TEXT);
cityInput.setHint("put down city name");
builder.setView(cityInput);
builder.setPositiveButton("Submit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which){
CityPreference cityPreference = new CityPreference(MainActivity.this);
cityPreference.setCity(cityInput.getText().toString());
String newCity = cityPreference.getCity();
renderWeatherData(newCity);
}
});
builder.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//inflate the menu, this adds items to the action bar if it is present
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.change_cityId){
showInputDialog();
}
return super.onOptionsItemSelected(item);
}
}
**HTTP CLIENT**
public class WeatherHTTPClient {
public String getWeatherData (String place) throws IOException {
// setting things up.., create connection between application and the web, everything we get from the web comes as an inputstream
HttpURLConnection connection = null;
InputStream inputStream = null;
// api.openweathermap.org/data/2.5/weather?q=London
// errors may occur when you connect to the internet, build this in the model with try...catch
WHEN I REPLACE "place" by "London" in the next statement, the application works. THERE MUST BE AN ERROR WITH THIS PART, BUT I CANNOT FIND IT.. I NEED HELP..
try {
connection = (HttpURLConnection) (new URL(Utils.BASE_URL + place +"&APPID=f77c39703fb6be71e2c5a96e58edc077")).openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
//read the response, buffer "bucket" where you are going to put your data
StringBuffer stringBuffer = new StringBuffer();
//you get a stream of bits and data to your device - everything comes in as an inputstream
inputStream = connection.getInputStream();
//BufferedReader is the only thing that can read the stream of data - hold it and start reading
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
//line is set as the data read by the BufferedReader, Stringbuffer reads the Buffer and goes to the next one
while ((line = bufferedReader.readLine()) != null){
stringBuffer.append(line + "\r\n");
}
inputStream.close();
connection.disconnect();
return stringBuffer.toString();
} catch (IOException e) {e.printStackTrace();}
return null;
}
}
**WEATHER DATA MODEL JSON**
public class Weather {
public static Place place;
public String IconData;
public CurrentCondition currentCondition = new CurrentCondition();
public Temperature temperature = new Temperature();
public Wind wind = new Wind();
public Snow snow = new Snow();
public Clouds clouds = new Clouds();
}
**PLACE DATA MODEL, left out getters and setters**
**LEFT OUT THE FULL DATA MODEL**
public class Place {
private float lon ;
private float lat ;
private long sunset;
private long sunrise;
private String country;
private String city;
private long lastupdate;
**THE WEATHER PARSER**
public class JSONWeatherParser {
public static Weather getWeather(String data){
//we call the top JSON object weather
Weather weather = new Weather();
//create JSONObject that holds all of the data you get from the web
//place is the parameter you use to get all the data for
//the rest of the variables you have to "calculate" from your data model
//tagName needs to be EXACTLY as it is in the JSON
try {
JSONObject jsonObject = new JSONObject(data);
Place place = new Place();
//for each "header" in JSON you create a JSONObject or a JSONArray
JSONObject coorObj = Utils.getObject("coord", jsonObject);
//you set the latitude by getting the "lat" variable from the coorObj from the top JSON Object weather
place.setLat(Utils.getFloat("lat",coorObj));
place.setLon(Utils.getFloat("lon",coorObj));
//get the sys object
JSONObject sysObj = Utils.getObject("sys", jsonObject);
place.setCountry(Utils.getString("country", sysObj));
//dt Lastupdate is found directly under the jsonObject, hence ...
place.setLastupdate(Utils.getInt("dt", jsonObject));
place.setSunrise(Utils.getInt("sunrise",sysObj));
place.setSunset(Utils.getInt("sunset",sysObj));
place.setCity(Utils.getString("name",jsonObject));
weather.place = place;
//get the weather info, it is a JSONArray of the main jsonObject (the whole thing) - starts with square brackets
JSONArray jsonArray = jsonObject.getJSONArray("weather");
//get the underlying Jsonobject from the jsonarray
JSONObject jsonWeather = jsonArray.getJSONObject(0);
weather.currentCondition.setWeatherId(Utils.getInt("id",jsonWeather));
weather.currentCondition.setDescription(Utils.getString("description", jsonWeather));
weather.currentCondition.setCondition(Utils.getString("main",jsonWeather));
weather.currentCondition.setIcon(Utils.getString("icon",jsonWeather));
JSONObject mainObj = Utils.getObject("main", jsonObject);
weather.currentCondition.setHumidity(Utils.getInt("humidity",mainObj));
weather.currentCondition.setPressure(Utils.getInt("pressure",mainObj));
weather.currentCondition.setMin_temp(Utils.getFloat("temp_min",mainObj));
weather.currentCondition.setMax_temp(Utils.getFloat("temp_max", mainObj));
weather.currentCondition.setTemperature(Utils.getDouble("temp",mainObj));
JSONObject windObj = Utils.getObject("wind", jsonObject);
weather.wind.setSpeed(Utils.getFloat("speed", windObj));
weather.wind.setDeg(Utils.getFloat("deg",windObj));
JSONObject cloudObj = Utils.getObject("clouds", jsonObject);
weather.clouds.setPrecipitation(Utils.getInt("all", cloudObj));
return weather;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
If you look at the URL
https://api.openweathermap.org/data/2.5/weather?q=[Ljava.lang.String;#34e4306&units=metric&APPID=f77c39703fb6be71e2c5a96e58edc077
The value for the query field (q) is [Ljava.lang.String;#34e4306, which is invalid. Ensure that you are sending a proper string value in this place.
Can this line be modified from:
weatherTask.execute(new String[]{city} + "&units=metric");
to the code below:
weatherTask.execute(city + "&units=metric");
Hope this would help.
I've got this code with fetches the "rate" data from an API, along with "rate", I need to get the "name". If I get "name" it often binds it below the "rate".
I need it to join on the same row of the List View, so it is like [Rate Name].
I need to get two objects of a JSON Array and bind it to the array adapter so I can display two objects in the same row of a List View so it is more user friendly.
The code below is of the AsyncTask, the code works fine but I need to add one more object and make sure it is displayed as one rate - one name and then iterating through the loop and adding more as needed in the same order.
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
// the url of the web service to call
String yourServiceUrl = "eg: URL";
#Override
protected void onPreExecute() {
}
String filename = "bitData";
#Override
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// parse returned json string into json array
JSONArray jsonArray = new JSONArray(json);
// loop through json array and add each currency to item in arrayList
//Custom Loop Initialise
for (int i = 1; i < 8; i++) {
JSONObject json_message = jsonArray.getJSONObject(i);
// The second JSONObject which needs to be added
JSONObject json_name = jsonArray.getJSONObject(i);
if (json_message != null) {
//add each currency to ArrayList as an item
items.add(json_message.getString("rate"));
String bitData = json_message.getString("rate");
String writeData = bitData + ',' +'\n';
FileOutputStream outputStream;
File file = getFileStreamPath(filename);
// first check if file exists, if not create it
if (file == null || !file.exists()) {
try {
outputStream = openFileOutput(filename, MODE_PRIVATE);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// if file already exists then append bit data to it
else if (file.exists()) {
try {
outputStream = openFileOutput(filename, Context.MODE_APPEND);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
// below method will run when service HTTP request is complete, will then bind text in arrayList to ListView
#Override
protected void onPostExecute(String strFromDoInBg) {
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
}
}
Just Create Custom Class Messsage:
public class Item{
private String name;
private String rate;
public void Message(String n, String r){
this.name=n;
this.rate=r;
}
// create here getter and setter
}
Now in your background, you have to add name and rate in Message class
Public class MainAcitity extends Activity{
public static List<Item> items= new ArrayList<>();// define in inside the class
// this has to be down on background
Item i=new Item(json_message.getString("name"),json_message.getString("rate"));
items.add(i);
Now pass this listmessge onPostExecute :
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
Is that any helpful for you.
Follow this link.You will get my point.
https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/
I have a AsyncTask for downloading a route from API Google Directions. The task starts at first Activity, where I show the time and the distance of the user to a point, but my map is in the second activity where I need draw the line of the route. My question is how to maintain a unique download task between two tasks (If the download has not completed in first activity), and access the data of the task on two activities.
public class DownloadDirections {
String urlDownload;
PolylineOptions lineOptions = null;
Context context;
String mTime;
String mDistance;
public DownloadDirections (Context context, String urlDownload){
this.urlDownload = urlDownload;
this.context = context;
new DownloadDirectionsTask().execute(urlDownload);
}
// Fetches data from url passed
private class DownloadDirectionsTask extends AsyncTask<String, Void, String> {
// Downloading data in non-ui thread
#Override
protected String doInBackground(String... url) {
// For storing data from web service
String data = "";
try {
// Fetching the data from web service
data = downloadUrl(url[0]);
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
// Executes in UI thread, after the execution of
// doInBackground()
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
/**
* A method to download json data from url
*/
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
/**
* A class to parse the Google Places in JSON format
*/
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
// Parsing the data in non-ui thread
#Override
protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {
JSONObject jObject;
List<List<HashMap<String, String>>> routes = null;
try {
jObject = new JSONObject(jsonData[0]);
DirectionsJSONParser parser = new DirectionsJSONParser();
// Starts parsing data
routes = parser.parse(jObject);
} catch (Exception e) {
e.printStackTrace();
}
return routes;
}
// Executes in UI thread, after the parsing process
#Override
protected void onPostExecute(List<List<HashMap<String, String>>> result) {
ArrayList<LatLng> points = null;
MarkerOptions markerOptions = new MarkerOptions();
String distance = "";
String duration = "";
if(result != null) {
if (result.size() < 1) {
Toast.makeText(context, "No Points", Toast.LENGTH_SHORT).show();
return;
}
}
if(result != null) {
// Traversing through all the routes
for (int i = 0; i < result.size(); i++) {
points = new ArrayList<LatLng>();
lineOptions = new PolylineOptions();
// Fetching i-th route
List<HashMap<String, String>> path = result.get(i);
// Fetching all the points in i-th route
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
if (j == 0) { // Get distance from the list
distance = (String) point.get("distance");
continue;
} else if (j == 1) { // Get duration from the list
duration = (String) point.get("duration");
continue;
}
double lat = Double.parseDouble(point.get("lat"));
double lng = Double.parseDouble(point.get("lng"));
LatLng position = new LatLng(lat, lng);
points.add(position);
}
// Adding all the points in the route to LineOptions
lineOptions.addAll(points);
lineOptions.width(2);
lineOptions.color(Color.RED);
mTime = duration;
mDistance = distance;
}
}
}
}
}
There are lots of options.
Download the entire item in the first activity, pass it to the second as intent data and access in the second activity. You may store the data in the internal storage (Preference, DB or Files depending on the size) if you want, and access accordingly.
You want to execute the task multiple times (one after another):
Keep a reference to the task object, and from the second activity call, make a wait call to the first one.
Want to use a service? No prob. Call the service, download the data, store them if very large. If the data is small, pass them via broadcast. Access them in the activity.
Is that what you wanted?
Currently in my application I execute a JSONDownloader, then tell my application to wait for a set period of time before updating fields with the retrieved data. How do I go about making the application wait for the JSONDownloader to finish its' task before I update the fields?
The JSONDowloader class is written (abridged) as follows and is run as an asynchronous activity. This class is called when needed and sets global variables which, after a set amount of time after being called are updated. I'd like the fields to be updated as soon as the class has finished running.
public class JSONDownloader extends AsyncTask<Object, Object, Object>{
#Override
protected Object doInBackground(Object... params) {
if(JSONstate == false){
try {
final URL url = new URL("https://irrelevant");
final URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
urlConnection.connect();
final InputStream inputStream = urlConnection.getInputStream();
final StringBuilder sb = new StringBuilder();
while (inputStream.available() > 0) {
sb.append((char) inputStream.read());
}
System.out.println("up to setting string");
String result = sb.toString();
JSONObject jsonOrg = new JSONObject(result);
String ok = "ok";
Response = jsonOrg.getString("response");
System.out.println(Response);
if(Response.equals(ok)){
Settingsresponse = true;
orgName = jsonOrg.getString("orgName");
System.out.println("orgName" + orgName);
accessPointName = jsonOrg.getString("accessPointName");
System.out.println("accessPointName" + accessPointName);
lat = jsonOrg.getString("latitude");
System.out.println("lat" + lat);
longi = jsonOrg.getString("longitude");
System.out.println("longi" + longi);
floor = jsonOrg.getString("floor");
System.out.println("floor" + floor);
orgId = jsonOrg.getString("orgId");
System.out.println("orgId" + orgId);
}
else{
System.out.println("Data sent was erroneous");
Settingsresponse = false;
}
} catch (Exception e) {
System.err.print(e);
}
}
return null;
}
protected void onPostExecute(Void result){
}
}
The JSONDownloader is called within whatever method it is needed and then immediately after this is called; currently a set time is used before updating fields as thus:
public void waitthencall()
{
long t0,t1;
t0=System.currentTimeMillis();
do{
t1=System.currentTimeMillis();
}
while (t1-t0<2000);
setfields();
}
you need a Callback listener to update your UI. Example
Create a callback listener and implement it inside your activity or from where you are updating the UI.
By using asynchronous task!
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
May help!
Dude, the method onPostExecute is call once doInBackGround has completed processing call your method from there, it will assure you that doInBackGround has finished its execution