[Android] Display images on the web in the info Window of Google Map

1. Project creation

Create a new project. Select Google Maps Activity and enter the project name to proceed. Replace the YOUR_KEY_HERE part of the automatically generated res / values / google_maps_api.xml with your own API key that you have obtained.

google_maps_api.xml


<resources>
<!--Abbreviation-->
    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">YOUR_KEY_HERE</string>
</resources>

At this point, start the program once and check that the map is displayed properly.

2. Write a layout file

Create a layout for infoWindow. This time, I will make it simple with only one ImageView in LinearLayout.

info_window_layout.xml


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

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

3. Description of InfoWindowAdapter

Implement InfoWindowAdapter in the onMapReady method of MapsActivity.java.

MapsActivity.java


    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
//~ Abbreviation ~
        mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
            Marker lastMarker;
            View infoWindow;

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

            @Override
            public View getInfoContents(Marker marker) {
//This time, describe the process here
                return null;
            }
        });

The infoWindowAdapter must override both the getInfoWindow () and getInfoContents () methods, and write the process in one and return null in the other. This time, describe the process in getInfoContents (). Also, for the convenience of processing, declare the variables lastMarker and infoWindow in the class of infoWindowAdapter.

4. Description of getInfoContents () method

            @Override
            public View getInfoContents(Marker marker) {
                if(lastMarker==null || !lastMarker.equals(marker)){
                    lastMarker = marker;
                    infoWindow = getLayoutInflater().inflate(R.layout.info_window_layout,null);
                    ImageView img = infoWindow.findViewById(R.id.img);
                    new DownloadImageTask(img,marker).execute(imgUrl);
//↑ Implemented after this
                }
                return infoWindow;
            }

As you can see if you follow the process in detail after implementing it to the end, if you try to display infoWindow by clicking the marker, the getInfoWindow () method will be called twice in total. The process of downloading the image runs the first time, and only return infoWindow; is executed the second time to prevent an infinite loop.

5. Describe the image download processing class

private class DownloadImageTask extends AsyncTask<String,Void, Bitmap>{
        ImageView img = null;
        Marker marker = null;

        DownloadImageTask(ImageView img, Marker marker){
            this.img = img;
            this.marker = marker;
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            Bitmap bmp = null;
            try{
                String urlStr = strings[0];
                URL url = new URL(urlStr);
                HttpURLConnection con = (HttpURLConnection)url.openConnection();
                con.setRequestMethod("GET");
                con.connect();
                int resp = con.getResponseCode();
                switch (resp){
                    case HttpURLConnection.HTTP_OK:
                        InputStream is = con.getInputStream();
                        bmp = BitmapFactory.decodeStream(is);
                        is.close();
                        break;
                    default:
                        break;
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (ProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bmp;
        }

        @Override
        protected void onPostExecute(Bitmap bmp){
            img.setImageBitmap(bmp);
            marker.showInfoWindow();
        }
    }

Describe DownladImageTask, which is a class for image download processing. Since the image download needs to be done asynchronously, it inherits AsyncTask. The URL of the image is passed as a String when called by execute (), and is received by strings [0] of doInbackground (). The image is set in ImageView by onPostExecute () which is called after the image download is completed, and then the image is displayed in infoWindow by calling marker.showInfoWindow ().

6. The whole MapsActivity.java

The marker is the default position in Sydney, and the image is the url of what you see when you search for Sydney on the web version of Google map.

MapsActivity.java


package com.example.test;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        final String imgUrl = "https://lh5.googleusercontent.com/p/AF1QipNUrZvzjGohRsYfuwIpCS2MjYdAq_3xruYM5imS=w408-h271-k-no";

        // Add a marker in Sydney and move the camera
        LatLng sydney = new LatLng(-34, 151);
        mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
        mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
            Marker lastMarker;
            View infoWindow;

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

            @Override
            public View getInfoContents(Marker marker) {
                if(lastMarker==null || !lastMarker.equals(marker)){
                    lastMarker = marker;
                    infoWindow = getLayoutInflater().inflate(R.layout.info_window_layout,null);
                    ImageView img = infoWindow.findViewById(R.id.img);
                    new DownloadImageTask(img,marker).execute(imgUrl);
                }
                return infoWindow;
            }
        });
    }

    private class DownloadImageTask extends AsyncTask<String,Void, Bitmap>{
        ImageView img = null;
        Marker marker = null;

        DownloadImageTask(ImageView img, Marker marker){
            this.img = img;
            this.marker = marker;
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            Bitmap bmp = null;
            try{
                String urlStr = strings[0];
                URL url = new URL(urlStr);
                HttpURLConnection con = (HttpURLConnection)url.openConnection();
                con.setRequestMethod("GET");
                con.connect();
                int resp = con.getResponseCode();
                switch (resp){
                    case HttpURLConnection.HTTP_OK:
                        InputStream is = con.getInputStream();
                        bmp = BitmapFactory.decodeStream(is);
                        is.close();
                        break;
                    default:
                        break;
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (ProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bmp;
        }

        @Override
        protected void onPostExecute(Bitmap bmp){
            img.setImageBitmap(bmp);
            marker.showInfoWindow();
        }
    }
}

reference

https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter https://stackoverflow.com/questions/36335004/how-to-get-image-in-infowindow-on-google-maps-with-picasso-android

Recommended Posts

[Android] Display images on the web in the info Window of Google Map
Display "Hello World" created in the local environment on the web
Display the address entered using Rails gem'geocoder' on Google Map
Display multiple markers on Google Map
How to display the regional mesh of the official statistics window (eStat) in a web browser
Display the graph of tensorBoard on jupyter
Let's automatically display the lyrics of the song being played on iTunes in Python
Fix the argument of the function used in map
I tried to display the infection condition of coronavirus on the heat map of seaborn
Implement Sign In With Google on the backend side
How to display multiple images of galaxies in tiles
[Golang] Specify an array in the value of map
Difference in results depending on the argument of multiprocess.Process
Execute the command on the web server and display the result
Display the weather forecast on M5Stack + Google Cloud Platform
[Python] Save the result of web scraping the Mercari product page on Google Colab to Google Sheets and display the product image as well.
Let's automatically display the lyrics of the song being played on iTunes in Python (improved version)
Changed the default style (CSS) of pandas data frame output by display in Google Colab
A note on the default behavior of collate_fn in PyTorch
Test.py is not reflected on the web server in Python3.
About the camera change event of Google Maps Android API
Survey on the use of machine learning in real services
[Django] Google map display of GIS data and graphing of parameters
Count the number of characters in the text on the clipboard on mac
Display the timetable of the Morioka bus location system in Pythonista
Save images on the web to Drive with Python (Colab)
Google search for the last line of the file in Python
Display Google Maps on a web page (Spring Boot + Thymeleaf)
Display PIL images on Jupyter
Verification of the spread of hoaxes in the "State of Emergency Declaration on April 1"
Real-time display of server-side processing progress in the browser (implementation of progress bar)
[Python] I wrote the route of the typhoon on the map using folium
[Cloudian # 9] Try to display the metadata of the object in Python (boto3)
Display the image of the camera connected to the personal computer on the GUI.
Scraping the schedule of Hinatazaka46 and reflecting it in Google Calendar
Find the rank of a matrix in the XOR world (rank of a matrix on F2)
[Ruby on Rails] Display and pinning of GoolgeMAP using Google API
Get the number of readers of a treatise on Mendeley in Python
Download the images and videos included in the tweets you liked on Twitter and upload them to Google Drive
[Rails 6] Embed Google Map in the app and add a marker to the entered address. [Confirmation of details]