I have been trying to get the walking duration and distance between two locations using Distance Matrix API. I want to store this results (Distance and Duration) in variables that I will be able to access from other classes/activities.
I managed to get time and duration using AsyncTask, but when I try to store them in a variable in PostExecute method, they are always unassigned when accessing from a method or class outside of the PostExecute method. I now, understand how AsyncTask works and that is asynchronous. I tried to implement interfaces and then try to access the data but still I was not able to.
GeoTask is an inner class in my Map class.
public class GeoTask extends AsyncTask<String, Void, String> {
ProgressDialog pd;
Context mContext;
SelectTime selectTime;
//constructor is used to get the context.
public GeoTask(Context mContext) {
this.mContext = mContext;
}
public GeoTask() {
}
//This function is executed before before "doInBackground(String...params)" is executed to dispaly the progress dialog
#Override
protected void onPreExecute() {
super.onPreExecute();
selectTime=new SelectTime();
pd=new ProgressDialog(mContext);
pd.setMessage("Loading");
pd.setCancelable(false);
pd.show();
}
//This function is executed after the execution of "doInBackground(String...params)" to dismiss the dispalyed progress dialog and call "setDouble(Double)" defined in "MainActivity.java"
#Override
protected void onPostExecute(String aDouble) {
super.onPostExecute(aDouble);
if(aDouble!=null)
{
setDouble(aDouble);
}
else
Toast.makeText(mContext, "Error4!Please Try Again with proper values", Toast.LENGTH_SHORT).show();
}
#Override
protected String doInBackground(String... params) {
try {
URL url=new URL(params[0]);
HttpURLConnection con= (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.connect();
int statuscode=con.getResponseCode();
if(statuscode==HttpURLConnection.HTTP_OK)
{
BufferedReader br=new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuilder sb=new StringBuilder();
String line=br.readLine();
while(line!=null)
{
sb.append(line);
line=br.readLine();
}
String json=sb.toString();
Log.d("JSON",json);
JSONObject root=new JSONObject(json);
JSONArray array_rows=root.getJSONArray("rows");
Log.d("JSON","array_rows:"+array_rows);
JSONObject object_rows=array_rows.getJSONObject(0);
Log.d("JSON","object_rows:"+object_rows);
JSONArray array_elements=object_rows.getJSONArray("elements");
Log.d("JSON","array_elements:"+array_elements);
JSONObject object_elements=array_elements.getJSONObject(0);
Log.d("JSON","object_elements:"+object_elements);
JSONObject object_duration=object_elements.getJSONObject("duration");
JSONObject object_distance=object_elements.getJSONObject("distance");
Log.d("JSON","object_duration:"+object_duration);
return object_duration.getString("value")+","+object_distance.getString("value");
}
} catch (MalformedURLException e) {
Log.d("error", "error1");
} catch (IOException e) {
Log.d("error", "error2");
} catch (JSONException e) {
Log.d("error","error3");
}
return null;
}
}
In Map class, the setDouble method:
public void setDouble(String result) {
String res[] = result.split(",");
Double m = Double.parseDouble(res[0]) / 60;
Double d = Double.parseDouble(res[1])/1000;
minutes=m
distance=d
}
The minutes and distance variables initialisation
private double minutes;
public double getMinutes() {
return minutes;
}
private double distance;
public double getDistance() {
return distance;
}
and the execution:
LatLng destinationLatLng = getLatLngFromAddress(destinationPassed);
currentOrigin = getAddressFromLatLng(currentLat,currentLong);
String url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentOrigin + "&destinations=" + destinationPassed + "&mode=walking&language=fr-FR&avoid=tolls&key=API_KEY";
Log.d("url string",url);
geoTask.execute(url);
Furthermore, I try to access the minutes and distance variables using the get methods in another class and I get the value 0.0 returned all the time, even after the PostExecution is completed (I tested that it completed using Logs)
1)How can I achieve what I want? Access the distance and duration returned by the API in different classes? It is essential for the app that I am doing to achieve that.
2)If I cant achieve what I want using AsyncTask and this method, is there any way to use Distance Matrix API without using AsyncTask?
Probably you should replace in your
String url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentOrigin + "&destinations=" + destinationPassed + "&mode=walking&language=fr-FR&avoid=tolls&key=API_KEY";
line API_KEY characters by your valid Distance API key.
Take a look at this guide to get information how to obtain valid API key.
Related
I am developing an Android Application (Android Studio - Java) which includes a sign in and registration process. I took care of the sign in and registration processes by implementing a connection between PHP files and a MySQL database through http. In short, I just created an AsyncTask class in java --called from another class-- and used it to post data to a PHP file, from there I just used the appropriate SQL commands. This part works fine.
This first part with the login and registration is important because every user will see a slightly different layout once they login. The layout is a RecyclerView composed of detailed CardView elements. Each CardView has a few TextViews with some details. The details are held by an Object i created in a separate class. To fill in the CardView elements a fetched some JSON data using a separate PHP file (and one more http connection). Parsing the data from JSON into Strings and ints was a straightforward endeavor, as was adding them to the list of custom objects. There is some code below showing how I fetched the data and added it to the Object list.
This is the complete AsyncTask class:
public class ScheduleWorker extends AsyncTask<String, Void, String> {
Context context;
AlertDialog alertDialog;
ScheduleWorker (Context ctx) { context = ctx; }
#Override
protected void onPreExecute() { super.onPreExecute(); }
#Override
protected void onPostExecute (String s) {
super.onPostExecute(s);
Toast.makeText(context, s, Toast.LENGTH_SHORT).show();
try {
loadJSON(s);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(String... params) {
final String fetch_url = "http://192.168.1.70/newfetcher.php";
try {
String ussr_name = params[0];
URL url = new URL(fetch_url);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
OutputStream outputStream = con.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
String post_data = URLEncoder.encode("user_name", "UTF-8")+"="+URLEncoder.encode(ussr_name, "UTF-8");
bufferedWriter.write(post_data);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
StringBuilder sb = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String json;
while ((json = bufferedReader.readLine()) != null) {
sb.append(json + "\n");
}
return sb.toString().trim();
} catch (Exception e) {
return null;
}
}
private void loadJSON(String json) throws JSONException {
JSONArray jsonArray = new JSONArray(json);
Course course;
List<Course> courses = new ArrayList<Course>();
int len = jsonArray.length();
String[] titles = new String[len];
String[] types = new String[len];
String[] teachers = new String[len];
int[] pics = new int[len];
for (int i = 0; i < len; i++) {
JSONObject obj = jsonArray.getJSONObject(i);
titles[i] = obj.getString("title");
types[i] = obj.getString("type");
teachers[i] = obj.getString("teacher");
pics[i] = obj.getInt("pic");
course = new Course(titles[i], types[i], teachers[i], pics[i]);
courses.add(course);
}
}
}
Now, where I encountered problems is when I tried saving the List of Objects (and their details) to a Room Persistent Database. I based my code for the Room Database off an example from Google Developer CodeLabs. I adapted the code for my particular needs but I kept the underlying class structure. The structure includes: an Entity, a DAO, a RoomDatabase, a Repository, a ViewModel, a ViewHolder, an Adapter for the RecyclerView, and a class to populate the database. Everything seems fine except for the part where I populate the database. The example populates the database by using a callback and an AsyncTask within the RoomDatabase class.
Here is populating AsyncTask:
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
#Override
public void onOpen(#NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
// If you want to keep the data through app restarts,
// comment out the following line.
new PopulateDbAsync(INSTANCE).execute();
}
};
/**
* Populate the database in the background.
* If you want to start with more words, just add them.
*/
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
private final WordDao mDao;
PopulateDbAsync(WordRoomDatabase db) {
mDao = db.wordDao();
}
#Override
protected Void doInBackground(final Void... params) {
// Start the app with a clean database every time.
// Not needed if you only populate on creation.
Word word = new Word("Hello");
mDao.insert(word);
word = new Word("World");
mDao.insert(word);
return null;
}
}
My question is how do I populate the database with the detail arrays and/or the Object list? The example executes the callback every time a adding activity is called. I just want to populate the database when the user registers.
Below is my code, lat_val and long_val is not getting updated with received value from JSON response in btnShowLoc(), it is referencing to the default value which is 0,0. I want the global variable to keep updating when ever referenced and updated with JSON response.
public class MainActivity extends Activity {
public static String lat_val = "0";
public static String long_val = "0";
public String readJSONFeed(String urlStr) {
StringBuilder stringBuilder = new StringBuilder();
try {
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestProperty("SisApiKey", "4572c3c9-73cb-4958-9649-26c1e8df27e8");
urlConnection.setRequestProperty("SisSmartKey", "d1aebd25-774c-4e8a-b3a5-ee5a603cc603");
InputStream ins = urlConnection.getInputStream();
urlConnection.connect();
int statusCode = urlConnection.getResponseCode();
if (statusCode == 200) {
BufferedReader br = new BufferedReader(new InputStreamReader(ins));
String line;
while ((line = br.readLine()) != null) {
stringBuilder.append(line);
}
ins.close();
} else {
Log.d("JSON", "Failed to download file");
}
} catch (java.net.MalformedURLException e) {
e.printStackTrace();
} catch (java.io.IOException e) {
e.printStackTrace();
} catch (Exception e) {
Log.d("readJSONFeed", e.getLocalizedMessage());
}
return stringBuilder.toString();
}
public class ReadJSONFeedTask extends AsyncTask
<String, Void, String> {
protected String doInBackground(String... url) {
return readJSONFeed(url[0]);
}
protected void onPostExecute(String result) {
try {
JSONObject jsonObject = new JSONObject(result);
//JSONObject flags = new JSONObject(jsonObject.getString("flag"));
JSONObject locationItems = new JSONObject(jsonObject.getString("response"));
//Log.v("Location Details :", locationItems.toString());
String []dev_loc = locationItems.toString().split("[\\s*,\\s*]");
MainActivity.lat_val = dev_loc[0]; //"12.9934136";
MainActivity.long_val = dev_loc[1]; //"80.2464206";
} catch (Exception e) {
Log.d("ReadJSONFeedTask", e.getLocalizedMessage());
}
}
}
public void btnGetDevLoc(View view) {
String sp_val = String.valueOf(spinner1.getSelectedItem());
new ReadJSONFeedTask().execute(
"http://15.153.133.160:21743/sis/sie/api/v1/applications/bb9f05fb-a796-4b75-9db7-c999360ad185/virtualobjects/d77d3905-aa77-41b9-9034-b0052bfde405?secondString=HWE_ASSET_ANDROID"); // + sp_val);
}
public void btnShowLoc(View view) {
//lat_val = "12.9934136";
//long_val = "80.2464206";
Intent in = new Intent(MainActivity.this, MapActivity.class);
Bundle bundle = new Bundle();
bundle.putString("latitude", MainActivity.lat_val);
bundle.putString("longitude", MainActivity.long_val);
in.putExtras(bundle);
startActivity(in);
}
With the few information you have shared, and given that
btnGetDevLoc() and btnShowLoc()are the functions executed when clicked on buttons in the application defined in activity_main.xml
and that
First btnGetDevLoc() is called then btnShowLoc()
the first thing that pops out in my mind is that the AsyncTask has not yet finished updating the String values, when you call btnShowLoc().
So, if btnGetDevLoc() and btnShowLoc() are called sequentially, like
... onClick() {
btnGetDevLoc();
btnShowLoc();
}
then it's most likely due to what I said above. Remember that AsyncTask runs asynchronously (as the name says...).
You can test this really small program.
public static double var1 = 0.0;
public static void main(String[] args) {
new Thread(() -> {
var1 = 1.0;
}).start();
System.out.println(var1);
}
It will almost always print 0.0, because the value of var1 is not updated yet when the main thread prints it.
What you should do is place your btnShowLoc() call at the end of onPostExecute(String). This guarantees that your method is called only after you have updated the new values.
I can't Understand, when the btnGetDevLoc() and btnShowLoc() called? Can you post your whole MainActivity?
Edit :
It's seems like you call btnShowLoc() before your AsyncTask finish its proccess.
You can change your code this way to make sure your btnShowLoc() called after your AsyncTask :
public class ReadJSONFeedTask extends AsyncTask
<String, Void, String> {
protected String doInBackground(String... url) {
return readJSONFeed(url[0]);
}
protected void onPostExecute(String result) {
try {
JSONObject jsonObject = new JSONObject(result);
//JSONObject flags = new JSONObject(jsonObject.getString("flag"));
JSONObject locationItems = new JSONObject(jsonObject.getString("response"));
//Log.v("Location Details :", locationItems.toString());
String []dev_loc = locationItems.toString().split("[\\s*,\\s*]");
MainActivity.lat_val = dev_loc[0]; //"12.9934136";
MainActivity.long_val = dev_loc[1]; //"80.2464206";
btnShowLoc(dev_loc[0], dev_loc[1]);
} catch (Exception e) {
Log.d("ReadJSONFeedTask", e.getLocalizedMessage());
}
}
}
public void btnShowLoc(String latitude, String longitude) {
//lat_val = "12.9934136";
//long_val = "80.2464206";
Intent in = new Intent(MainActivity.this, MapActivity.class);
Bundle bundle = new Bundle();
bundle.putString("latitude", latitude);
bundle.putString("longitude", longitude);
in.putExtras(bundle);
startActivity(in);
}
I have this MainActivity which does two HTTP calls and return the JSON object back to the MainActivity class. I have seperately implemented the AsyncTask class and used the AsyncResponse interface to get the JSON object to the MainActivity by using the processFinish function call.
At first I came up with one HTTP call which worked perfectly.
Secondly I wanted to do another HTTP call in the same activity class. So I edit the code to cater the second HTTP call.
When I run the application, only the first HTTP call is working. When I call the second HTTP call it throws an exception saying reference to a null object
Then I checked by logging the onPostExecute method which calls the processFinish function. There I could see the JSON Object. So, that means the second JSON object doesn't get to the processFinish
How do I manage the second HTTP call? Please help me! I am new to Android.
Following is my AsyncTask class...
public class ServiceHandler extends AsyncTask<String, Void, JSONObject> {
String startStationID;
String endStationID;
String searchDate;
String startTime;
String endTime;
public ServiceHandler(String startStationID, String endStationID, String searchDate, String startTime, String endTime) {
this.startStationID = startStationID;
this.endStationID = endStationID;
this.searchDate = searchDate;
this.startTime = startTime;
this.endTime = endTime;
}
public interface AsyncResponse {
void processFinish(JSONObject output);
}
public AsyncResponse delegate=null;
public ServiceHandler(AsyncResponse delegate) {
this.delegate = delegate;
}
#Override
protected JSONObject doInBackground(String... params) {
String method = params[0];
JSONObject JSON_Object = null;
if (method.equals("getStations")) {
JSON_Object = Constants.apiCall("http://api.lankagate.gov.lk:8280/railway/1.0/station/getAll?lang=en");
} else if (method.equals("searchTrains")) {
JSON_Object = Constants.apiCall("http://api.lankagate.gov.lk:8280/railway/1.0/train/searchTrain?" +
"startStationID="+this.startStationID+"&" +
"endStationID="+this.endStationID+"&" +
"searchDate="+this.searchDate+"&" +
"startTime="+this.startTime+"&" +
"endTime="+this.endTime+"&" +
"lang=en");
}
return JSON_Object;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(JSONObject obj) {
try{
Log.d("onPostExecute",obj.toString());
delegate.processFinish(obj);
}catch (Exception e){
Log.e("onPostExecute",e.getMessage());
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
}
Following is my processFinish function...
#Override
public void processFinish(JSONObject output) {
Log.d("processFinish",output.toString());
if(!isSearchClicked) {
//Get all the stations...
if (output != null) {
Toast.makeText(MainActivity.this, "Successfully Connected!", Toast.LENGTH_SHORT).show();
try {
JSONObject obj = output.getJSONObject("RESULTS");
output = null;
JSONArray dataArray = obj.getJSONArray("stationList");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject object1 = dataArray.getJSONObject(i);
String stationID = object1.getString("stationID");
String stationName = object1.getString("stationName");
stationNames.add(stationName);
stationIDs.add(stationID);
// stations.put(stationID,stationName);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, " Connection Failed!", Toast.LENGTH_SHORT).show();
}
}else {
//search click action...
if (output != null) {
Toast.makeText(MainActivity.this, "Successfully Searched!", Toast.LENGTH_SHORT).show();
try {
JSONObject obj = output.getJSONObject("RESULTS");
JSONArray directTrains = obj.getJSONArray("directTrains");
// Log.d("array size",String.valueOf(directTrains.length()));
// for (int i = 0; i < directTrains.length(); i++) {
// JSONObject object1 = directTrains.getJSONObject(i);
//
// String stationID = object1.getString("stationID");
// String stationName = object1.getString("stationName");
// Log.d("JArr", stationID + " : " + stationName);
//
// stationNames.add(stationName);
// stationIDs.add(stationID);
//// stations.put(stationID,stationName);
// }
// Log.d("stationNames", stationNames.toString());
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, " Connection Failed!", Toast.LENGTH_SHORT).show();
Log.d("output",output.toString());
}
}
}
Following is my first HTTP call...
ServiceHandler sh = new ServiceHandler(this);
String method = "getStations";
sh.execute(method);
Following is my second HTTP call...
String method = "searchTrains"
ServiceHandler sh = new ServiceHandler(startStationID,endStationID,searchDate,startTime,endTime);
sh.execute(method);
Although I don't understand exactly what your problem is. There are few things I suggest you to do.
Here I go.
Don't use AsyncTask to make your http calls , use an intent services instead.
Use a OkHTTP library for your networking source
On your intent service send local broadcast with LocalBroadcastManager to broadcast your results from the http call.
Register broadcastsReceivers within your activities or fragments that will listen for those broadcasts that comes from the intent service
Why not to use AsyncTask: Because of configuration change - if you rotate your device you will lose that network calls-
Read about intent services here
I developing android app and now I have problem. Below is a part of my code, and it keeps skipping the "for" part. When I put a breakpoint inside for statement, it stops at the point, and executes the lines very well and makes an output that I want. When I just 'run' app, it skips that part so "String locations" value doesn't change. I googled and some say it's thread-related problem. So I put synchroinzed on the method, still not working. Any other suggestions?
UPDATE
I was trying to show code only related to the problem, but I think now showing the whole would be more useful for those who try to help so here's my entire code on showMapActivity. You can see I've tried some ways around and nothing worked. Saving path's information into String url is where I'm having problem. I tested, and other parts seem to work fine. I know my code is really massy, that was why I only posted parts of the code. TMap related classes are imported from .jar file.
public class showMapActivity extends Activity {
TMapData tmapdata=new TMapData();
TMapView tmapView;
TMapPoint origin, dest;
volatile ArrayList<TMapPoint> points=new ArrayList<>();
private TextView x;
private TextView y;
private HashMap<String,LatLng> coordinates;
private HashMap<LatLng,Double> finalpoint;
static private ConcurrentHashMap<Double,Double> path;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_map);
coordinates=new HashMap<>();
Intent intent=getIntent();
tmapView=new TMapView(this);
path=new ConcurrentHashMap<>();
coordinates=(HashMap<String,LatLng>)intent.getSerializableExtra("coordinate");
path=getPathPoints(coordinates);
int i=0;
String url=getUrl();
//String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
//String locations="";
/*
Iterator<Double> keys= path.keySet().iterator();
while(keys.hasNext()){
Double key=keys.next();
//String lat=String.valueOf(key);
//String lng=String.valueOf(path.get(key));
locations=locations+String.valueOf(key)+","+String.valueOf(path.get(key));
if(keys.hasNext())
locations=locations+"|";
}path.entrySet()
*/
/*
for(ConcurrentHashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
*/
//url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//String url=getUrl(path);
FetchUrl fetchUrl=new FetchUrl();
fetchUrl.execute(url);
}
private ConcurrentHashMap<Double,Double> getPathPoints(HashMap<String,LatLng> coordinates)
{
final ConcurrentHashMap<Double,Double> Path=new ConcurrentHashMap<>();
tmapView.setSKPMapApiKey("6bb5b7f3-1274-3c5e-ba93-790aee876673");
origin=new TMapPoint(coordinates.get("origin").latitude,coordinates.get("origin").longitude);
dest=new TMapPoint(coordinates.get("dest").latitude,coordinates.get("dest").longitude);
tmapdata.findPathData(origin, dest, new TMapData.FindPathDataListenerCallback() {
#Override
public void onFindPathData(TMapPolyLine polyLine) {
points=polyLine.getLinePoint();
for(TMapPoint point : points )
Path.put(point.getLatitude(),point.getLongitude());
}
});
return Path;
}
//ConcurrentHashMap<Double,Double> path
private synchronized String getUrl() {
int i=0;
String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
String locations="";
for(HashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//https://maps.googleapis.com/maps/api/elevation/json?locations=
// 39.7391536,-104.9847034|36.455556,-116.866667&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto
// Output format
return url;
}
private class FetchUrl extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... url) {
// For storing data from web service
String data = "";
try {
// Fetching the data from web service
//downloadURL
data = downloadUrl(url[0]);
Log.d("Background Task data", data.toString());
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//ParserTask
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
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();
Log.d("downloadUrl", data.toString());
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
private class ParserTask extends AsyncTask<String, Integer, ArrayList<Double>> {
// Parsing the data in non-ui thread
#Override
protected ArrayList<Double> doInBackground(String... jsonData) {
JSONObject jObject;
ArrayList<Double> altitude = null;
try {
jObject = new JSONObject(jsonData[0]);
Log.d("ParserTask",jsonData[0].toString());
//DataParser class 호출
DataParser parser = new DataParser();
Log.d("ParserTask", parser.toString());
// Starts parsing data
altitude = parser.parse(jObject);
Log.d("ParserTask","Getting Altitudes");
Log.d("ParserTask",altitude.toString());
} catch (Exception e) {
Log.d("ParserTask",e.toString());
e.printStackTrace();
}
return altitude;
}
// Executes in UI thread, after the parsing process
#Override
protected void onPostExecute(ArrayList<Double> result) {
finalpoint=new HashMap<>();
LatLng latLng;
int i=0;
for(HashMap.Entry<Double,Double> elem : path.entrySet() )
{
latLng=new LatLng(elem.getKey(),elem.getValue());
finalpoint.put(latLng,result.get(i++));
}
x = (TextView) findViewById(R.id.textView5);
y = (TextView) findViewById(R.id.textView6);
x.setText(String.valueOf(finalpoint.get(coordinates.get("origin"))));
y.setText(String.valueOf(finalpoint.get(coordinates.get("dest"))));
}
}
}
(Apologies for posting this as an answer - I don't yet have the required reputation to comment)
Simply adding synchronized to a method doesn't necessarily guarantee thread safety.
How and when is path being populated?
Update after additional information provided
The problem seems to be that the path points are being generated asynchronously, and you are trying to use them before the generation process has finished (or perhaps even started). This happens because the findPathData simply starts the generation process and returns immediately (i.e. before the generation process has finished). In your code, you then go on and build the URL which is supposed to contain the point data immediately. At this point the background point generation process may not have finished, and may not have even started. As a result the point map may be empty or incomplete, and your URL will not be generated as you expect.
You need to find a way to wait until all of the path point data has been returned by the asynchronous processing before creating the URL. This looks like it could be very difficult, if not impossible, with the version of the findPathData method you are using, because it returns points via the callback one at a time and you may not know how many will be generated.
I had a quick look at the API for TMapData and it has a findPathDataAll method which seems to generate all the points and return them in a single callback call rather than one by one. If this is indeed what it does (sorry, I can't read Korean), you could use this method and then generate the URL from the callback, because when it's called you know that the generation process has been completed. If you do this, be careful to make sure that you're on the main thread before interacting with the UI or Activity.
Hope that helps.
I have 3 markers in a map. I get marker data through a server and associate it through each marker. Due to data amount, I only get a subset of data for each marker (for development I have 3 markers, but there may be many more). So I associate an ID to each marker, and for the next activity, I get that ID and retrieve the complete data set for the next activity to be displayed.
Unfortunately all markers end up being associated with the same ID. What am I missing here?
Initially I was passing a final variable to the inner class in order to assign the ID. Finding this question: How to pass parameters to anonymous class? (kudos!) I introduced an initializer to the inner class, thinking the final attribute might have been the problem. But nope. Still getting the same ID on all markers.
private class Getter extends AsyncTask<String, Void, JSONArray> {
private Exception exception;
protected static final String TAG = "Getter";
protected JSONArray doInBackground(String... urls) {
try {
try {
//get JSON data from server
return json_objects.getJSONArray("objects");
} catch (JSONException jse) {
//more error handling
}
}catch(Exception e) {
this.exception = e;
return null;
}
}
protected void onPostExecute(JSONArray obj_arr) {
try {
if (this.exception != null) {
//some error handling
} else if (obj_arr != null) {
for (int i = 0; i < obj_arr.length(); i++) {
JSONObject obj = obj_arr.getJSONObject(i);
create_marker(obj);
}
}
} catch(JSONException jse) {
//error handling
}
}
private void create_marker(JSONObject obj) {
try {
JSONObject location = obj.getJSONObject("location");
double lat = location.getDouble("lat");
double lng = location.getDouble("lng");
String id = obj.getString("id");
LatLng pos = new LatLng(lat, lng);
mMap.addMarker(new MarkerOptions().position(
pos).title(obj.getString("name")).
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
String local_id;
public GoogleMap.OnMarkerClickListener init(String id) {
local_id = id;
return this;
}
#Override
public boolean onMarkerClick(Marker marker) {
Intent i = new Intent(MapActivity.this, NextActivity.class);
i.putExtra("obj_id", local_id);
startActivity(i);
return false;
};
}.init(id));
} catch (JSONException e) {
//error handling
}
}
}