Статьи

Расположение Android с Google Maps — часть 2

В первой части мы проанализировали наши требования и имеющиеся в нашем распоряжении инструменты, чтобы получить первоначальный дизайн приложения.

Эта часть начнет реализацию с класса более низкого уровня, LocatorOverlay , и ответит на следующий вопрос:  Какие функции мы хотим предоставить поверх карты местоположений телефона? Простое отображение местоположения на экране телефона — это мило … около десяти секунд. Поэтому нам нужно подумать о добавленной функциональности.

Здесь мы реализуем функцию «отправить местоположение контакту»: пользователь может просто нажать на точку местоположения своего телефона на карте и поделиться ею с любым количеством контактов посредством SMS.

Для наложения элементов Google Карты предоставляют нам несколько вариантов выбора в качестве базовых классов, которые могут быть расширены для наследования функциональности:

  1. Overlay  абстрактный класс
  2. ItemizedOverlay  подкласс Overlay, который мы можем использовать в качестве списка наложения элементов.
  3. MyLocationOverlay  подкласс Overlay, который рисует местоположение пользователя на карте.

Второй вариант — хороший выбор, если мы намереваемся отобразить несколько элементов поверх карты. Давайте начнем писать первый черновик нашего класса LocatorOverlay :

 

//...package statement and other imports go here
//...
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.OverlayItem;

/**
 * Custom overlay class
 */
public class LocatorOverlay extends ItemizedOverlay<OverlayItem> {

   private List<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
   private Context context;

   public LocatorOverlay(Drawable defaultMarker) {
        super(boundCenterBottom(defaultMarker));
   }

   public LocatorOverlay(Drawable defaultMarker, Context context) {
        this(defaultMarker);
        this.context = context;
   }
   public void addOverlay(OverlayItem overlay) {
      mapOverlays.add(overlay);
       this.populate();
   }

   @Override
   protected OverlayItem createItem(int i) {
      return mapOverlays.get(i);
   }

   @Override
   public int size() {
      return mapOverlays.size();
   }

   @Override
   protected boolean onTap(int index) {
      // TODO
      return true;
   }

}

 

Пока ничего необычного. У нас есть список элементов наложения и ссылка на контекст приложения. Последний метод  onTap (int index)   — то, где вещи становятся интересными. Давайте реализуем диалоговое окно отправки-размещения-через-SMS, которое всплывает, когда пользователь нажимает на точку расположения телефона:

 

 /**
     * Show some info and send location via SMS
     *
     * @param index
     * @return
     */
   @Override
   protected boolean onTap(int index) {
       // Items to display in the dialog
      OverlayItem item = mapOverlays.get(index); //? see Part 3

      AlertDialog.Builder dialog = new AlertDialog.Builder(context);
      dialog.setTitle(item.getTitle());
      dialog.setMessage(item.getSnippet());

       // get location in the format "latitude,longitude"
      final String address =  item.routableAddress();

      // dialog to send location via SMS
      dialog.setCancelable(false);
      dialog.setPositiveButton("Send Location",
       new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int id) {
              // call SMS program
              Intent sendIntent = new Intent(Intent.ACTION_VIEW);
              sendIntent.putExtra("sms_body", "My location: " + address);
              sendIntent.setType("vnd.android-dir/mms-sms");
              context.startActivity(sendIntent);
          }
      }) ;
      dialog.setNegativeButton("Cancel", 
       new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int id) {
              dialog.dismiss();
          }
      });
      dialog.show();
      return true;
   }

 

То, что мы сделали, было:

  1. Получить список элементов для наложения (здесь отображаются как часть заголовка и сообщения диалога)
  2. Создайте диалог, чтобы включить отправку местоположения с помощью SMS
  3. Включить местоположение в тексте сообщения SMS

Но откуда список элементов наложения mapOverlays  получает элементы OverlayItem ? Мы увидим это в части 3. А пока, вот как он будет выглядеть в конце, когда пользователь нажмет на точку расположения на первом снимке экрана:

 

Мы закончили с отображением местоположения по SMS? Не совсем. Видите, «адрес», который мы получаем из OverlayItem .routableAddress (), содержит только пару широта и долгота и имеет ограниченное практическое использование. Однако ничто не мешает нам создать URL-адрес карты Google с этими координатами, чтобы наши получатели SMS могли щелкнуть ссылку и визуализировать наше местоположение в своем браузере. Например, мы могли бы сделать это:

 
String latLong =  item.routableAddress();
final String locationURL = "https://maps.google.com/maps?q=" +
                           URLEncoder.encode(latLong);
// code ....
// send locationURL instead of initial address
sendIntent.putExtra("sms_body", locationURL);
// code ...

 

Мы могли бы стать еще более изощренными и использовать API URL Shortener Google для нашего URL местоположения. Если, с другой стороны, мы предпочитаем отправлять адрес улицы, соответствующий (более или менее) паре широта-долгота, нам нужно использовать обратное геокодирование  :

 
// new imports:
import android.location.Address; 
import android.location.Geocoder;

//...

// inside onTap() method
//get street address estimate                     
 GeoPoint point = item.getPoint();
 String streetAddr = "";                            
 Geocoder geoCoder = new Geocoder(context, Locale.getDefault()); 
 try {   
   // point's coordinates are stored in micro-degrees... 
   List<Address> addrList = 
        geoCoder.getFromLocation( point.getLatitudeE6()  / 1E6,
                                  point.getLongitudeE6() / 1E6,
                                  1);  // max result = 1     
   if ( addrList != null && addrList .size() > 0)  {
     // first addr in the list is closest estimate 
      Address addr1 =  addrList.get(0);
      streetAddr = addr1.getAddressLine(0) 
                      + ", " + addr1.getLocality(); 
   }                                                   
 }                                     
 catch (IOException e) {
   e.printStackTrace();
   streetAddr = "Not Available (Network connection)";  
 }

final String address = streetAddr;

//code ...
sendIntent.putExtra("sms_body", "My location: \n" + address);
//code ...

Конечно, ничто не мешает нам отправлять получателю SMS и адрес местоположения, и адрес улицы . Однако имейте в виду, что в общем случае поиск в обратном геокодировании заметно замедляет время отклика приложения , и в этом случае время, необходимое для всплывающего диалогового окна в ответ на событие касания.

Мы закончили с LocatorOverlay . В третьей части мы реализуем класс Locator .

 

Из блога Тони .