Jacob Platin Jacob Platin - 4 months ago 58
JSON Question

Using JSON for Android Maps API: Markers not Showing up

I am attempting to use

JSON
in order to create markers on my Google map for my app, but, for some reason, they are not showing up. The logcat has no errors or warnings, but the markers aren't showing up.

My JSON is hosted here: https://api.myjson.com/bins/4jb09

Here's my Java:

package com.example.toshiba.jsonmap;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
* @author saxman
*/
public class MainActivity extends FragmentActivity {
private static final String LOG_TAG = "ExampleApp";

private static final String SERVICE_URL = "https://api.myjson.com/bins/4jb09";

protected GoogleMap map;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpMapIfNeeded();
}

@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}

private void setUpMapIfNeeded() {
if (map == null) {
MapFragment mapFragment = (MapFragment) getFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMap();
if (map != null) {
setUpMap();
}
}
}

private void setUpMap() {
// Retrieve the city data from the web service
// In a worker thread since it's a network operation.
new Thread(new Runnable() {
public void run() {
try {
retrieveAndAddCities();
} catch (IOException e) {
Log.e(LOG_TAG, "Cannot retrive cities", e);
return;
}
}
}).start();
}

protected void retrieveAndAddCities() throws IOException {
HttpURLConnection conn = null;
final StringBuilder json = new StringBuilder();
try {
// Connect to the web service
URL url = new URL(SERVICE_URL);
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(conn.getInputStream());

// Read the JSON data into the StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
json.append(buff, 0, read);
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error connecting to service", e);
throw new IOException("Error connecting to service", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}

// Create markers for the city data.
// Must run this on the UI thread since it's a UI operation.
runOnUiThread(new Runnable() {
public void run() {
try {
createMarkersFromJson(json.toString());
} catch (JSONException e) {
Log.e(LOG_TAG, "Error processing JSON", e);
}
}
});
}

void createMarkersFromJson(String json) throws JSONException {
// De-serialize the JSON string into an array of city objects
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
// Create a marker for each city in the JSON data.
JSONObject jsonObj = jsonArray.getJSONObject(i);
map.addMarker(new MarkerOptions()
.title(jsonObj.getString("name"))
.snippet(Integer.toString(jsonObj.getInt("population")))
.position(new LatLng(
jsonObj.getJSONArray("latlng").getDouble(0),
jsonObj.getJSONArray("latlng").getDouble(1)
))
);
}
}
}

Answer

I see one issue that could be causing the problem.

You never assign GoogleMap map a value, so map will always be null.

Try assigning it properly and see if it fixes your issue:

private void setUpMapIfNeeded() {
        if (map == null) {
            MapFragment mapFragment = (MapFragment) getFragmentManager()
                    .findFragmentById(R.id.map);
            map = mapFragment.getMap(); //added assignment to map
            if (map != null) {
                setUpMap();
            }
        }
    }

Edit: I went ahead an got your code working using an AsyncTask.

Here is how you invoke it in onCreate():

private void setUpMapIfNeeded() {
    if (map == null) {
        MapFragment mapFragment = (MapFragment) getFragmentManager()
                .findFragmentById(R.id.map);
        map = mapFragment.getMap();
        if (map != null) {
            //setUpMap();
            new MarkerTask().execute();
        }
    }
}

Here is the AsyncTask, note that I went ahead and made the markers blue just as an example:

private class MarkerTask extends AsyncTask<Void, Void, String> {

        private static final String LOG_TAG = "ExampleApp";

        private static final String SERVICE_URL = "https://api.myjson.com/bins/4jb09";

        // Invoked by execute() method of this object
        @Override
        protected String doInBackground(Void... args) {

            HttpURLConnection conn = null;
            final StringBuilder json = new StringBuilder();
            try {
                // Connect to the web service
                URL url = new URL(SERVICE_URL);
                conn = (HttpURLConnection) url.openConnection();
                InputStreamReader in = new InputStreamReader(conn.getInputStream());

                // Read the JSON data into the StringBuilder
                int read;
                char[] buff = new char[1024];
                while ((read = in.read(buff)) != -1) {
                    json.append(buff, 0, read);
                }
            } catch (IOException e) {
                Log.e(LOG_TAG, "Error connecting to service", e);
                //throw new IOException("Error connecting to service", e); //uncaught
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }

            return json.toString();
        }

        // Executed after the complete execution of doInBackground() method
        @Override
        protected void onPostExecute(String json) {

            try {
                // De-serialize the JSON string into an array of city objects
                JSONArray jsonArray = new JSONArray(json);
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObj = jsonArray.getJSONObject(i);

                    LatLng latLng = new LatLng(jsonObj.getJSONArray("latlng").getDouble(0),
                            jsonObj.getJSONArray("latlng").getDouble(1));

                    //move CameraPosition on first result
                    if (i == 0) {
                        CameraPosition cameraPosition = new CameraPosition.Builder()
                                .target(latLng).zoom(13).build();

                        map.animateCamera(CameraUpdateFactory
                                .newCameraPosition(cameraPosition));
                    }

                    // Create a marker for each city in the JSON data.
                    map.addMarker(new MarkerOptions()
                            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
                            .title(jsonObj.getString("name"))
                            .snippet(Integer.toString(jsonObj.getInt("population")))
                            .position(latLng));
                }
            } catch (JSONException e) {
                Log.e(LOG_TAG, "Error processing JSON", e);
            }

        }
    }

Result:

enter image description here

Also, if you want customized info windows, you can look at the documentation here.

I went ahead and got a simple example working for this as well.

Code to set up the InfoWindowAdapter:

map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {

            @Override
            public View getInfoWindow(Marker arg0) {
                return null;
            }

            @Override
            public View getInfoContents(Marker arg0) {

                View v = getLayoutInflater().inflate(R.layout.customlayout, null);

                TextView tLocation = (TextView) v.findViewById(R.id.location);

                TextView tSnippet = (TextView) v.findViewById(R.id.population);

                tLocation.setText(arg0.getTitle());

                tSnippet.setText(arg0.getSnippet());

                return v;

            }
        });

customlayout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    android:orientation="vertical"
    android:background="#000000">

    <TextView
        android:id="@+id/location"
        android:textColor="#D3649F"
        android:textStyle="bold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/population"
        android:textColor="#D3649F"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Result:

custom InfoWindowAdapter

Comments