This post describes how to use weather data tile and how to add weather layer to google map. We want to add weather data to a map or in other words add to Android google map a tile so that the app; shows clouds, temperature, pressure and so on.
In the previous post we talked about how to get weather information and how to parse the data to create a UI, now we want to add other weather data tile to a map. To do it, we start creating a sample project that contains a map activity.
If we use Android Studio (as i suggest) it is very simple and fast.
Create Android Map project in Android Studio
The first step is creating a google map project in Android. As always, we select File->New project and after inserting some project information we land to this page:
Now select Google Map Activity. Android Studio will create all the things to handle google map in our project. The last thing to do is to add the key to use the map. If you look in the files inside the project you will find the way to create your debug key. Once you have the key, it is time to use the map.
Add weather data tile to Google Map
The next step is adding weather data tile to google map. To this purpose, we will use Open Weather Map as weather provider, but you could use other weather providers. We modify the setUpMap inside our MapsActivity (or the name of the class you used when you created the project) and add a new TileProvider. A Tile provider is essential an interface that we have to implement in our provider so that we fetch the image that covers the map. A tile is an image that is represented over the map. In the case of OWM, the URL we have to use to retrieve the image is:
http://tile.openweathermap.org/map/%s/%d/%d/%d.png
where %s represents the type of the map tile we want to use like clouds, temperature and so on while the other three integers (%d) represent the zoom and x, y coords.
In our case, we use a UrlTileProvider that can be used to retrieve tiles from an HTTP connection. Our implementation is very simple:
[java] private TileProvider createTilePovider() {TileProvider tileProvider = new UrlTileProvider(256, 256) {
@Override
public URL getTileUrl(int x, int y, int zoom) {
String fUrl = String.format(OWM_TILE_URL, tileType == null ? "clouds" :
tileType, zoom, x, y);
URL url = null;
try {
url = new URL(fUrl);
}
catch(MalformedURLException mfe) {
mfe.printStackTrace();
}
return url;
}
} ;
[/java]
Finally in our setUpMap() method we add our tile provider to the map:
[java]tileOver = mMap.addTileOverlay(new TileOverlayOptions(). tileProvider(createTransparentTileProvider()));[/java]
where tileOver is an instance of TileOverlay. Running the example we get:
Add weather data tiles
Now let’s add a Spinner over our map so that the user can select the type of information to add on top of the map like: temperature, wind, pressure and so on.
This is very simple, modify the activity_maps.xml and add our spinner:
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
android:id="@+id/tileType"/>
</RelativeLayout>
[/xml]
Finally in the onCreate() we add the code to handle the spinner:
[java] spinner = (Spinner) findViewById(R.id.tileType);String[] tileName = new String[]{"Clouds", "Temperature", "Precipitations", "Snow", "Rain", "Wind", "Sea level press."};
ArrayAdapter adpt = new ArrayAdapter(this, android.R.layout.simple_spinner_item, tileName);
spinner.setAdapter(adpt);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onNothingSelected(AdapterView parent) {
}
@Override
public void onItemSelected(AdapterView parent, View view, int position, long id) {
// Check click
switch (position) {
case 0:
tileType = "clouds";
break;
case 1:
tileType = "temp";
break;
case 2:
tileType = "precipitation";
break;
case 3:
tileType = "snow";
break;
case 4:
tileType = "rain";
break;
case 5:
tileType = "wind";
break;
case 6:
tileType = "pressure";
break;
}
if (mMap != null) {
tileOver.remove();
setUpMap();
}
}
});
[/java]
The Spinner simply list all the tile types and when the user selects one of them the app shows the relative images on top of the map. If we select for example the temperature map, the result is shown below:
Looking at the image, it is possible to notice that the tile has covered almost the map behind. This happens because the SDK doesn’t have an easy way to modify the transparency of the map.
[bctt tweet=”Add weather information to Google maps in #Android” username=”survivingwithan”]Add transparent tile to Google map
The last step, if we want that the weather data tile doesn’t cover the map that stands behind, is modifying our provider. This code shown below is derived from this post. We create, in other words, a custom provider so that we can change the opacity of the images we add over the map:
[java]public class TransparentTileOWM implements TileProvider {//private String url;
private Paint opacityPaint = new Paint();
private String tileType;
private static final String OWM_TILE_URL = "http://tile.openweathermap.org/map/%s/%d/%d/%d.png";
/**
* This constructor assumes the url parameter contains three placeholders for the x- and y-positions of
* the tile as well as the zoom level of the tile. The placeholders are assumed to be {x},
* {y}, and {zoom}. An example
* for an OpenWeatherMap URL would be: http://tile.openweathermap.org/map/precipitation/{zoom}/{x}/{y}.png
*
*/
public TransparentTileOWM(String tileType)
{
this.tileType = tileType;
setOpacity(50);
}
/**
* Sets the desired opacity of map {@link Tile}s, as a percentage where 0% is invisible and 100% is completely opaque.
* @param opacity The desired opacity of map {@link Tile}s (as a percentage between 0 and 100, inclusive)
*/
public void setOpacity(int opacity)
{
int alpha = (int)Math.round(opacity * 2.55); // 2.55 = 255 * 0.01
opacityPaint.setAlpha(alpha);
}
@Override
public Tile getTile(int x, int y, int zoom)
{
URL tileUrl = getTileUrl(x, y, zoom);
Tile tile = null;
ByteArrayOutputStream stream = null;
try
{
Bitmap image = BitmapFactory.decodeStream(tileUrl.openConnection().getInputStream());
image = adjustOpacity(image);
stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
tile = new Tile(256, 256, byteArray);
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(stream != null)
{
try
{
stream.close();
}
catch(IOException e) {}
}
}
return tile;
}
/**
* Helper method that returns the {@link URL} of the tile image for the given x/y/zoom location.
*
* This method assumes the URL string provided in the constructor contains three placeholders for the x-
* and y-positions as well as the zoom level of the desired tile; {x}, {y}, and
* {zoom}. An example for an OpenWeatherMap URL would be:
* http://tile.openweathermap.org/map/precipitation/{zoom}/{x}/{y}.png
*
* @param x The x-position of the tile
* @param y The y-position of the tile
* @param zoom The zoom level of the tile
*
* @return The {@link URL} of the desired tile image
*/
private URL getTileUrl(int x, int y, int zoom)
{
String tileUrl = String.format(OWM_TILE_URL, tileType, zoom, x, y);
try
{
return new URL(tileUrl);
}
catch(MalformedURLException e)
{
throw new AssertionError(e);
}
}
/**
* Helper method that adjusts the given {@link Bitmap}’s opacity to the opacity previously set via
* {@link #setOpacity(int)}. Stolen from Elysium’s comment at StackOverflow.
*
* @param bitmap The {@link Bitmap} whose opacity to adjust
* @return A new {@link Bitmap} with an adjusted opacity
*
* @see htp://stackoverflow.com/questions/14322236/making-tileoverlays-transparent#comment19934097_14329560
*/
private Bitmap adjustOpacity(Bitmap bitmap)
{
Bitmap adjustedBitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(adjustedBitmap);
canvas.drawBitmap(bitmap, 0, 0, opacityPaint);
return adjustedBitmap;
}
}
[/java]
Now running the code and using this new provider the result is:
Source code available @ github
Would you mind to share the source code?
Thanks
I agree with the above. Really need to see more to see how things are connected. To many holes for piecing together. Also, what is createTransparentTileProvider()?
you should share source code
Ok i will clean the code and share it using github
Can you give me the github link, please?
The link is available at the end of the post.
so long?, :((
I try to get data by tile.openweather… but it return null. Can you help me?
Sounds strange. Did you use the code shown in the post?
Loading in the tiles takes a very long time. Any recommendations on how improve it?
Yep it could be and it depends on the connection speed. You could try to cache it.
Can I ask you something why layer load on map so long? I have to wait to complete it about 20 minute
Hi ! I am an Android Beginner.Thanks for sharing the code, it was really helpful. I tried to run the code, it compiled smoothly and i was able to load the apk file to my phone. However i am not able to access Google Maps data. In the Logcat i get this error “Authentication failed. Timeout while trying to contact the server.” Sorry, i am not able to figure out what’s the problem. Please help me.
Hi thank you. I guess it is a network problem. You should verify if you have the right permission in the manifest file. If it is correct you should verify if your phone can be connected to the net. Let me know if you still have the same problem.
Thanks for the advice. I have updated the manifest file and now its working. Keep sharing the code so that beginners like me can learn android. You are truly an inspiration. Thanks again.
Sir i was able to run your code and its working. However i noticed that the data available on open Weather Map website and the data shown in the app are different. I checked open Weather Map website and these data are free, so why am i not able to access this data. Also it doesn’t show a scale at the bottom. Do i need a separate code for displaying the scale ? Please guide me where i am going wrong.
PS :- I really liked this website. You are a motivation for beginners like us.
im getting filenotfound exeption on get tile and conn time out
java.io.FileNotFoundException: http://tile.openweathermap.org/map/Precipitations/7/29/49.png
01-01 16:36:33.500 7802-10114/mhdjazmati.its.mdccpublicview W/System.err: at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:218)
01-01 16:36:33.500 7802-10114/mhdjazmati.its.mdccpublicview W/System.err: at mhdjazmati.its.mdccpublicview.TransparentTileOWM.getTile(TransparentTileOWM.java:63)
it is not working anymore ! ?
could you please confirm ?
i am getting timeout when using the url “http://tile.openweathermap.org/map/tileName/zoom/x/y.png”;
why it is not working ?
i think the link http://tile.openweathermap.org/map/precipitation/{zoom}/{x}/{y}.png
any ideas ?
I will try and i let youknow
hello , i don’t mean to disturb you , but did you find anything ?
hello , did you find anything ,,, please tell me ?
Instead of creating whole custome class u can use transperency function:
mTileOverlay = map.addTileOverlay(new TileOverlayOptions()
.tileProvider(new UrlTileProvider() {…})
.transparency(0.5f));
But also something wrong with link http://tile.openweathermap.org…{zoom}/{x}/{y}.png, because nothing is displaying on the map.
Thanks for sharing, nice tutorial
Hi guys, http://tile.openweathermap.org/map/precipitation/{zoom}/{x}/{y}.png this url not working, which is the correct url. Anyone got the solution?
Hey Guys, I got solution please use folllowing url
http://tile.openweathermap.org/map/{layer}/{z}/{x}/{y}.png?appid={api_key}
Instead of http://tile.openweathermap.org…{zoom}/{x}/{y}.png
hi ,
how show temp degrees and icon state on map ??
Has anyone find the solution to the weather tiles not displaying?