انتخابگر مکان فعلی خود را برای Android (جاوا) بسازید

1. قبل از شروع

با نحوه استفاده از Google Maps Platform و Places SDK برای Android برای ارائه لیستی از مکان ها برای شناسایی مکان های فعلی به کاربران خود آشنا شوید.

bd07a9ad2cb27a06.png

پیش نیازها

  • مهارت های پایه جاوا

کاری که خواهی کرد

  • یک نقشه به برنامه اندروید اضافه کنید.
  • از مجوزهای موقعیت مکانی برای تعیین موقعیت جغرافیایی کاربر استفاده کنید.
  • مکان‌های نزدیک به مکان فعلی کاربر را واکشی کنید.
  • مکان‌های احتمالی را برای شناسایی مکان فعلی کاربر به کاربر ارائه دهید.

چیزی که خواهی ساخت

شما برنامه اندروید خود را از ابتدا می سازید، اما می توانید کد نمونه را برای مقایسه در هنگام اشکال زدایی دانلود کنید. کد نمونه را از GitHub دانلود کنید، یا اگر Git را برای استفاده از خط فرمان تنظیم کرده اید، موارد زیر را وارد کنید:

git clone https://github.com/googlecodelabs/current-place-picker-android.git

اگر در حین کار با این کد با مشکلاتی (اشکالات کد، خطاهای دستوری، عبارت نامشخص یا چیز دیگری) مواجه شدید، لطفاً مشکل را از طریق پیوند گزارش یک اشتباه در گوشه سمت چپ پایین صفحه کد گزارش دهید.

2. شروع کنید

قبل از شروع این کد لبه، باید موارد زیر را تنظیم کنید:

اندروید استودیو

اندروید استودیو را از https://developer.android.com/studio دانلود کنید.

اگر قبلاً Android Studio دارید، با کلیک روی Android Studio > Check for Updates... مطمئن شوید که آخرین نسخه را دارید.

1f36bae83b64e33.png

این آزمایشگاه با استفاده از اندروید استودیو 3.4 نوشته شده است.

Android SDK

در اندروید استودیو، می توانید SDK های مورد نظر خود را با استفاده از SDK Manager پیکربندی کنید. این آزمایشگاه از Android Q SDK استفاده می کند.

  1. از صفحه خوش آمدگویی Android Studio، روی Configure > SDK Manager کلیک کنید.

d3fa03c269ec231c.png

  1. کادر انتخاب SDK مورد نظر خود را انتخاب کنید، سپس روی Apply کلیک کنید.

اگر هنوز SDK را ندارید، با این کار دانلود SDK در دستگاه شما آغاز می شود.

884e0aa1314f70d.png

خدمات گوگل پلی

از مدیر SDK، همچنین باید خدمات Google Play را نصب کنید.

  1. روی برگه ابزار SDK کلیک کنید و کادر خدمات Google Play را انتخاب کنید.

در صورت خواندن وضعیت به‌روزرسانی موجود ، به‌روزرسانی کنید.

ad6211fd78f3b629.png

3. شبیه ساز را آماده کنید

برای اجرای برنامه، می توانید دستگاه خود را متصل کنید یا از شبیه ساز اندروید استفاده کنید.

اگر از دستگاه خود استفاده می‌کنید، به دستورالعمل‌های دستگاه واقعی بروید: خدمات Google Play را در انتهای این صفحه به‌روزرسانی کنید.

یک شبیه ساز اضافه کنید

  1. از صفحه خوش آمدگویی Android Studio، روی Configure > AVD Manager کلیک کنید.

5dd2d14c9c56d3f9.png

با این کار کادر گفتگوی مدیریت دستگاه مجازی اندروید باز می شود.

  1. روی Create Virtual Device... کلیک کنید تا لیستی از دستگاه هایی که می توانید انتخاب کنید باز شود.

2d44eada384f8b35.png

  1. دستگاهی را با Play انتخاب کنید d5722488d80cd6be.png در ستون Play Store کلیک کنید و روی Next کلیک کنید.

e0248f1c6e85ab7c.png

مجموعه ای از تصاویر سیستم را می بینید که می توانید نصب کنید. اگر Q که Android 9.+ (Google Play) را هدف قرار می دهد کلمه Download را در کنار خود دارد، روی دانلود کلیک کنید.

316d0d1efabd9f24.png

  1. روی Next کلیک کنید تا به دستگاه مجازی خود یک نام بدهید، سپس روی Finish کلیک کنید.

شما به لیست دستگاه های مجازی خود باز می گردید.

  1. روی Start کلیک کنید ba8adffe56d3b678.png در کنار دستگاه جدید شما:

7605864ed27f77ea.png

پس از چند لحظه، شبیه ساز باز می شود.

دستورالعمل‌های شبیه‌ساز — خدمات Google Play را به‌روزرسانی کنید

  1. پس از راه اندازی شبیه ساز، روی ... در نوار پیمایش که ظاهر می شود کلیک کنید **.**

2e1156e02643d018.png

با این کار کادر گفتگوی Extended Controls باز می شود.

  1. در منو روی Google Play کلیک کنید.

اگر به‌روزرسانی در دسترس است، روی به‌روزرسانی کلیک کنید.

5afd2686c5cad0e5.png

  1. با یک حساب Google وارد شبیه ساز شوید.

می توانید از حساب کاربری خود استفاده کنید یا یک حساب کاربری جدید به صورت رایگان ایجاد کنید تا آزمایش خود را جدا از اطلاعات شخصی خود نگه دارید.

سپس Google Play به خدمات Google Play باز می شود.

  1. برای دریافت آخرین نسخه خدمات Google Play روی Update کلیک کنید.

f4bc067e80630b9c.png

اگر از شما خواسته شد راه‌اندازی حساب خود را تکمیل کنید و یک گزینه پرداخت اضافه کنید، روی Skip کلیک کنید.

مکان را در شبیه ساز تنظیم کنید

  1. هنگامی که شبیه ساز راه اندازی شد، "maps" را در نوار جستجو در صفحه اصلی تایپ کنید تا نماد برنامه Google Maps را بالا بکشید.

2d996aadd53685a6.png

  1. برای راه اندازی روی نماد کلیک کنید.

یک نقشه پیش فرض می بینید.

  1. در سمت راست پایین نقشه، روی مکان شما کلیک کنید c5b4e2fda57a7e71.png .

از شما خواسته می شود به تلفن اجازه استفاده از موقعیت مکانی را بدهید.

f2b68044eabca151.png

  1. روی ... کلیک کنید تا منوی Extended Controls باز شود.
  2. روی تب Location کلیک کنید.
  3. طول و عرض جغرافیایی را وارد کنید.

هر چیزی را که دوست دارید اینجا وارد کنید، اما مطمئن شوید که در منطقه‌ای با مکان‌های زیاد است.

(از Latitude 20.7818 و Longitude -156.4624 برای شهر Kihei در Maui در هاوایی استفاده کنید تا نتایج این آزمایشگاه کد را تکرار کنید.)

  1. روی ارسال کلیک کنید و نقشه با این مکان به روز می شود.

f9576b35218f4187.png

شما آماده اجرای برنامه خود و آزمایش آن با مکان هستید.

دستورالعمل‌های واقعی دستگاه - خدمات Google Play را به‌روزرسانی کنید

اگر از یک دستگاه اندروید واقعی استفاده می‌کنید، موارد زیر را انجام دهید:

  1. از نوار جستجو در صفحه اصلی برای جستجو و باز کردن خدمات Google Play استفاده کنید.
  2. روی جزئیات بیشتر کلیک کنید.

در صورت موجود بودن، روی Update کلیک کنید.

ad16cdb975b5c3f7.pngbaf0379ef8a9c88c.png

4. پوسته برنامه را با یک فعالیت Google Maps ایجاد کنید

  1. در صفحه خوش آمدگویی Android Studio، شروع یک پروژه جدید Android Studio را انتخاب کنید.
  2. در تب Phone and Tablet ، Google Maps Activity را انتخاب کنید.

c9c80aa8211a8761.png

کادر گفتگوی Configure your project باز می شود. اینجا جایی است که نام برنامه خود را می گذارید و بسته را بر اساس دامنه خود ایجاد می کنید.

در اینجا تنظیمات برنامه ای به نام Current Place است که با بسته com.google.codelab.currentplace مطابقت دارد.

37f5b93b94ee118c.png

  1. جاوا را به عنوان زبان انتخاب کرده و Use androidx را انتخاب کنید. مصنوعات *.

تنظیمات پیش فرض را برای بقیه تنظیمات حفظ کنید.

  1. روی Finish کلیک کنید.

5. وابستگی های Google Services را به فایل ساخت Gradle اضافه کنید

برای دسترسی به مجوزهای مکان در Android، به API مکان Google و Activity Recognition از سرویس‌های Google Play نیاز دارید. برای اطلاعات بیشتر در مورد افزودن این و سایر APIهای خدمات Google Play، به تنظیم خدمات Google Play مراجعه کنید.

پروژه های Android Studio معمولا دارای دو فایل build.gradle هستند. یکی برای پروژه کلی و یکی برای برنامه است. اگر Android Studio Project Explorer را در نمای اندروید دارید، هر دوی آنها را در پوشه Gradle Scripts می بینید. برای افزودن خدمات Google باید فایل build.gradle (Module: app) را ویرایش کنید.

f3043429cf719c47.png

  1. دو خط به بخش dependencies اضافه کنید تا سرویس‌های Google برای مکان و Places API ( کد نمونه در زمینه ) اضافه شود.

build.gradle (ماژول: برنامه)

plugins {
  id 'com.android.application'
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.google.codelab.currentplace"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'com.google.android.gms:play-services-location:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}

6. API های پلتفرم نقشه های گوگل را فعال کنید و یک کلید API دریافت کنید

برای مرحله فعال سازی زیر، باید Maps SDK for Android و Places API را فعال کنید.

پلتفرم نقشه های گوگل را راه اندازی کنید

اگر قبلاً حساب Google Cloud Platform و پروژه‌ای با صورت‌حساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورت‌حساب و یک پروژه ببینید.

  1. در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید.

  1. APIها و SDKهای پلتفرم Google Maps مورد نیاز برای این لبه کد را در Google Cloud Marketplace فعال کنید. برای انجام این کار، مراحل این ویدئو یا این مستند را دنبال کنید.
  2. یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواست‌ها به پلتفرم نقشه‌های Google به یک کلید API نیاز دارند.

کلید API را که ایجاد کردید کپی کنید. به Android Studio برگردید و فایل google_maps_api.xml را در زیر Android > app > res > value s پیدا کنید.

YOUR_KEY_HERE را با کلید API که کپی کردید جایگزین کنید.

aa576e551a7a1009.png

اکنون برنامه شما پیکربندی شده است.

7. فایل طرح بندی را ویرایش کنید

  1. در کاوشگر پروژه خود، فایل activity_maps.xml را در Android > app > res > layout باز کنید.

4e0d986480c57efa.png

  1. رابط کاربری اصلی را در سمت راست صفحه باز می‌بینید، با زبانه‌هایی در پایین که به شما امکان می‌دهد ویرایشگر طراحی یا متن را برای طرح‌بندی خود انتخاب کنید. Text را انتخاب کنید و کل محتوای فایل layout را با این جایگزین کنید:

activity_maps.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:titleTextColor="@android:color/white"
        android:background="@color/colorPrimary" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="349dp"
            tools:context=".MapsActivity" />

        <ListView
            android:id="@+id/listPlaces"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

این یک رابط کاربری به شما می دهد که به شکل زیر است:

1bf786808a4697ce.png

8. نوار برنامه را تنظیم کنید

برای اینکه به کاربر دکمه‌ای بدهید تا وقتی می‌خواهد مکان فعلی خود را انتخاب کند، یک نوار برنامه با نمادی اضافه کنید که مکان فعلی کاربر را پیدا کرده و مکان‌های احتمالی نزدیک را نشان می‌دهد. شبیه این خواهد شد:

3a17c92b613a26c5.png

در تلفن، فقط نماد نشان داده می شود. در تبلت با فضای بیشتر، متن نیز گنجانده شده است.

نماد را ایجاد کنید

  1. در کاوشگر پروژه، روی Android > app کلیک کنید، سپس روی پوشه res راست کلیک کرده و New > Image Asset را انتخاب کنید.

Asset Studio باز می شود.

  1. در منوی Icon Type ، روی Action Bar and Tab Icons کلیک کنید.
  2. دارایی خود را ic_geolocate کنید.
  3. Clip Art را به عنوان نوع دارایی انتخاب کنید**.**
  4. روی گرافیک کنار Clip Art کلیک کنید.

با این کار پنجره Select Icon باز می شود.

  1. یک تصویر انتخاب کن.

می توانید از نوار جستجو برای یافتن نمادهای مرتبط با هدف خود استفاده کنید.

  1. مکان را جستجو کنید و نماد مربوط به location را انتخاب کنید.

نماد موقعیت مکانی من همان نمادی است که در برنامه Google Maps زمانی که کاربر می خواهد دوربین را به مکان فعلی خود ببرد استفاده می شود.

  1. روی OK > Next > Finish کلیک کنید و تأیید کنید که پوشه جدیدی به نام drawable وجود دارد که حاوی فایل‌های نماد جدید شما است.

b9e0196137ed18ae.png

منابع رشته را اضافه کنید

  1. در کاوشگر پروژه، روی Android > app > res > values ​​کلیک کنید و فایل strings.xml را باز کنید.
  2. خطوط زیر را بعد از <string name="title_activity_maps">Map</string> اضافه کنید:

strings.xml

    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>

هنگامی که فضایی برای اضافه کردن یک برچسب متنی در کنار نماد وجود دارد، از خط اول در نوار برنامه استفاده می‌شود. بقیه برای نشانگرهایی که به نقشه اضافه می کنید استفاده می شود.

حالا کد داخل فایل به شکل زیر است:

<resources>
    <string name="app_name">Current Place</string>
    <string name="title_activity_maps">Map</string>
    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>
</resources>

نوار برنامه را اضافه کنید

  1. در کاوشگر پروژه، روی Android > app کلیک کنید، سپس روی پوشه res کلیک راست کرده و New > Directory را انتخاب کنید تا یک زیر شاخه جدید در app/src/main/res ایجاد کنید.
  2. menu فهرست را نامگذاری کنید.
  3. روی پوشه menu کلیک راست کرده و New > File را انتخاب کنید.
  4. نام فایل را menu.xml .
  5. در این کد قرار دهید:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- "Locate me", should appear as action button if possible -->
    <item
        android:id="@+id/action_geolocate"
        android:icon="@drawable/ic_geolocate"
        android:title="@string/action_geolocate"
        app:showAsAction="always|withText" />

</menu>

سبک نوار برنامه را به روز کنید

  1. در کاوشگر پروژه، Android > app > res > values گسترش دهید و فایل styles.xml را در داخل باز کنید.
  2. در تگ <style> ، ویژگی والد را به عنوان "Theme.AppCompat.NoActionBar" ویرایش کنید.
  3. به ویژگی name که در مرحله بعد از آن استفاده می کنید توجه کنید.

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">

تم برنامه را در AndroidManifest.xml به روز کنید

  1. روی Android > app > manifests کلیک کنید و فایل AndroidManifest.xml را باز کنید.
  2. خط android:theme را پیدا کنید و مقدار را به @style/AppTheme ویرایش یا تأیید کنید.

AndroidManifest.xml

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

اکنون آماده شروع کدنویسی هستید!

9. برنامه را راه اندازی کنید

  1. در کاوشگر پروژه خود، فایل MapsActivity.java را پیدا کنید.

این در پوشه مربوط به بسته ای است که برای برنامه خود در مرحله 1 ایجاد کرده اید.

8b0fa27d417f5f55.png

  1. فایل را باز کنید و در ویرایشگر کد جاوا هستید.

Places SDK و سایر وابستگی ها را وارد کنید

این خطوط را در بالای MapsActivity.java کنید، و جایگزین دستورات واردات موجود شوید.

آنها واردات موجود را در بر می گیرند و بسیاری از موارد مورد استفاده در کدهای این کد را اضافه می کنند.

MapsActivity.java

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
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.MarkerOptions;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;

import java.util.Arrays;
import java.util.List;

امضای کلاس را به روز کنید

Places API از اجزای AndroidX برای پشتیبانی سازگار با عقب استفاده می کند، بنابراین باید آن را برای گسترش AppCompatActivity تعریف کنید. جایگزین پسوند FragmentActivity می شود که به طور پیش فرض برای یک فعالیت نقشه تعریف شده است.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

اضافه کردن متغیرهای کلاس

سپس، متغیرهای کلاس مختلف مورد استفاده در متدهای کلاس مختلف را اعلام کنید. اینها شامل عناصر UI و کدهای وضعیت هستند. اینها باید درست زیر اعلان متغیر برای GoogleMap mMap باشند.

    // New variables for Current Place picker
    private static final String TAG = "MapsActivity";
    ListView lstPlaces;
    private PlacesClient mPlacesClient;
    private FusedLocationProviderClient mFusedLocationProviderClient;

    // The geographical location where the device is currently located. That is, the last-known
    // location retrieved by the Fused Location Provider.
    private Location mLastKnownLocation;

    // A default location (Sydney, Australia) and default zoom to use when location permission is
    // not granted.
    private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
    private static final int DEFAULT_ZOOM = 15;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
    private boolean mLocationPermissionGranted;

    // Used for selecting the Current Place.
    private static final int M_MAX_ENTRIES = 5;
    private String[] mLikelyPlaceNames;
    private String[] mLikelyPlaceAddresses;
    private String[] mLikelyPlaceAttributions;
    private LatLng[] mLikelyPlaceLatLngs;

متد onCreate را به روز کنید

باید روش onCreate را به‌روزرسانی کنید تا مجوزهای کاربر در زمان اجرا برای سرویس‌های مکان، راه‌اندازی عناصر UI و ایجاد کلاینت Places API را مدیریت کنید.

خطوط کد زیر را در رابطه با نوار ابزار اقدام، تنظیمات views و سرویس گیرنده Places به انتهای onCreate() موجود اضافه کنید.

MapsActivity.java onCreate()

   @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);

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //
        
        // Set up the action toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Set up the views
        lstPlaces = (ListView) findViewById(R.id.listPlaces);

        // Initialize the Places client
        String apiKey = getString(R.string.google_maps_key);
        Places.initialize(getApplicationContext(), apiKey);
        mPlacesClient = Places.createClient(this);
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    }

کد را برای منوی نوار برنامه خود اضافه کنید

این دو روش منوی نوار برنامه را اضافه می‌کنند (با یک آیتم، نماد Pick Place) و کلیک کاربر روی نماد را کنترل می‌کنند.

این دو روش را بعد از onCreate در فایل خود کپی کنید.

MapsActivity.java onCreateOptionsMenu() و onOptionsItemSelected()

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
           case R.id.action_geolocate:
                
                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the current place picker
                // pickCurrentPlace();
                return true;

            default:
                // If we got here, the user's action was not recognized.
                // Invoke the superclass to handle it.
                return super.onOptionsItemSelected(item);

        }
    }

امتحانش کن

  1. از Android Studio، روی Run یا Run menu > Run 'app' کلیک کنید.

28bea91c68c36fb2.png

  1. از شما خواسته می شود که هدف استقرار خود را انتخاب کنید. شبیه ساز در حال اجرا باید در این لیست ظاهر شود. آن را انتخاب کنید و Android Studio برنامه را برای شما در شبیه ساز مستقر می کند.

f44658ca91f6f41a.png

پس از چند لحظه، برنامه راه اندازی می شود. نقشه را در مرکز سیدنی، استرالیا، با دکمه واحد و لیست مکان‌های خالی مشاهده می‌کنید.

68eb8c70f4748350.png

تمرکز نقشه به مکان کاربر منتقل نمی شود مگر اینکه برای دسترسی به مکان دستگاه درخواست مجوز کنید.

10. درخواست و رسیدگی به مجوزهای مکان

پس از آماده شدن نقشه، مجوزهای مکان را درخواست کنید

  1. روشی به نام getLocationPermission تعریف کنید که مجوزهای کاربر را درخواست می کند.

این کد را در زیر متد onOptionsSelected که ایجاد کرده اید قرار دهید.

MapsActivity.java getLocationPermission()

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        mLocationPermissionGranted = false;
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
  1. برای فعال کردن کنترل‌های بزرگ‌نمایی و درخواست مجوزهای مکان از کاربر، دو خط به انتهای روش موجود onMapReady اضافه کنید.

MapsActivity.java onMapReady()

   @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // 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));

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //

        // Enable the zoom controls for the map
        mMap.getUiSettings().setZoomControlsEnabled(true);

        // Prompt the user for permission.
        getLocationPermission();

    }

نتیجه مجوزهای درخواستی را مدیریت کنید

هنگامی که کاربر به گفتگوی مجوز درخواست پاسخ می دهد، این تماس توسط Android فراخوانی می شود.

این کد را بعد از متد getLocationPermission() قرار دهید:

MapsActivity.java onRequestPermissionsResult()

   /**
     * Handles the result of the request for location permissions
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
    }

11. مکان فعلی را دریافت کنید و مکان های احتمالی را واکشی کنید

هنگامی که کاربر بر روی Pick Place در نوار برنامه کلیک می کند، برنامه متد pickCurrentPlace() را فراخوانی می کند که متد pickCurrentPlace() getDeviceLocation() که قبلاً تعریف کرده اید فراخوانی می کند. متد getDeviceLocation پس از بازیابی آخرین مکان دستگاه، روش دیگری به نام getCurrentPlaceLikelihoods, را فراخوانی می کند.

با findCurrentPlace API تماس بگیرید و پاسخ را مدیریت کنید

getCurrentPlaceLikelihoods یک findCurrentPlaceRequest می سازد و Places API را findCurrentPlace می کند. اگر کار موفقیت آمیز باشد، findCurrentPlaceResponse را برمی گرداند که حاوی لیستی از اشیاء placeLikelihood است. هر کدام از اینها تعدادی ویژگی دارند، از جمله نام و آدرس مکان، و احتمال اینکه شما در آن مکان هستید (مقدار دو برابر از 0 تا 1). این روش پاسخ را با ساخت لیستی از جزئیات مکان از placeLikelihoods می کند.

این کد در پنج مکان محتمل‌تر تکرار می‌شود و مواردی که احتمال رنده آن‌ها بیشتر از 0 است را به فهرستی اضافه می‌کند که سپس نمایش داده می‌شود. اگر می خواهید بیشتر یا کمتر از پنج نمایش داده شود، ثابت M_MAX_ENTRIES را ویرایش کنید.

این کد را بعد از متد onMapReady قرار دهید.

MapsActivity.java getCurrentPlaceLikelihoods()

   private void getCurrentPlaceLikelihoods() {
        // Use fields to define the data types to return.
        List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                Place.Field.LAT_LNG);

        // Get the likely places - that is, the businesses and other points of interest that
        // are the best match for the device's current location.
        @SuppressWarnings("MissingPermission") final FindCurrentPlaceRequest request =
                FindCurrentPlaceRequest.builder(placeFields).build();
        Task<FindCurrentPlaceResponse> placeResponse = mPlacesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(this,
                new OnCompleteListener<FindCurrentPlaceResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                        if (task.isSuccessful()) {
                            FindCurrentPlaceResponse response = task.getResult();
                            // Set the count, handling cases where less than 5 entries are returned.
                            int count;
                            if (response.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                                count = response.getPlaceLikelihoods().size();
                            } else {
                                count = M_MAX_ENTRIES;
                            }

                            int i = 0;
                            mLikelyPlaceNames = new String[count];
                            mLikelyPlaceAddresses = new String[count];
                            mLikelyPlaceAttributions = new String[count];
                            mLikelyPlaceLatLngs = new LatLng[count];

                            for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                                Place currPlace = placeLikelihood.getPlace();
                                mLikelyPlaceNames[i] = currPlace.getName();
                                mLikelyPlaceAddresses[i] = currPlace.getAddress();
                                mLikelyPlaceAttributions[i] = (currPlace.getAttributions() == null) ?
                                        null : TextUtils.join(" ", currPlace.getAttributions());
                                mLikelyPlaceLatLngs[i] = currPlace.getLatLng();

                                String currLatLng = (mLikelyPlaceLatLngs[i] == null) ?
                                        "" : mLikelyPlaceLatLngs[i].toString();

                                Log.i(TAG, String.format("Place " + currPlace.getName()
                                        + " has likelihood: " + placeLikelihood.getLikelihood()
                                        + " at " + currLatLng));

                                i++;
                                if (i > (count - 1)) {
                                    break;
                                }
                            }


                            // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                            // Populate the ListView
                            // fillPlacesList();
                        } else {
                            Exception exception = task.getException();
                            if (exception instanceof ApiException) {
                                ApiException apiException = (ApiException) exception;
                                Log.e(TAG, "Place not found: " + apiException.getStatusCode());
                            }
                        }
                    }
                });
    }

دوربین نقشه را به مکان فعلی دستگاه منتقل کنید

اگر کاربر اجازه دهد، برنامه آخرین مکان کاربر را واکشی می‌کند و دوربین را به مرکز آن مکان می‌برد.

اگر کاربر اجازه را رد کند، برنامه به سادگی دوربین را به مکان پیش فرض تعریف شده در بین ثابت های ابتدای این صفحه (در کد نمونه، سیدنی، استرالیا) منتقل می کند.

این کد را بعد از getPlaceLikelihoods() :

MapsActivity.java getDeviceLocation()

    private void getDeviceLocation() {
        /*
         * Get the best and most recent location of the device, which may be null in rare
         * cases when a location is not available.
         */
        try {
            if (mLocationPermissionGranted) {
                Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
                locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        if (task.isSuccessful()) {
                            // Set the map's camera position to the current location of the device.
                            mLastKnownLocation = task.getResult();
                            Log.d(TAG, "Latitude: " + mLastKnownLocation.getLatitude());
                            Log.d(TAG, "Longitude: " + mLastKnownLocation.getLongitude());
                            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                    new LatLng(mLastKnownLocation.getLatitude(),
                                            mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                        } else {
                            Log.d(TAG, "Current location is null. Using defaults.");
                            Log.e(TAG, "Exception: %s", task.getException());
                            mMap.moveCamera(CameraUpdateFactory
                                    .newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        }

                       getCurrentPlaceLikelihoods();
                    }
                });
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }

هنگامی که کاربر بر روی انتخاب مکان کلیک می کند، مجوزهای مکان را بررسی کنید

هنگامی که کاربر بر روی " انتخاب مکان " ضربه می‌زند، این روش مجوزهای مکان را بررسی می‌کند و در صورت عدم اعطای مجوز از کاربر درخواست می‌کند.

اگر کاربر اجازه داده باشد، متد getDeviceLocation را فراخوانی می‌کند تا فرآیند دریافت مکان‌های احتمالی فعلی را آغاز کند.

  1. این متد را بعد از getDeviceLocation() اضافه کنید:

MapsActivity.java pickCurrentPlace()

   private void pickCurrentPlace() {
        if (mMap == null) {
            return;
        }

        if (mLocationPermissionGranted) {
            getDeviceLocation();
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");

            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));

            // Prompt the user for permission.
            getLocationPermission();
        }
    }
  1. اکنون که pickCurrentPlace تعریف شده است، خطی را در onOptionsItemSelected() بیابید که pickCurrentPlace را فراخوانی می کند و آن را از نظر خارج کنید.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the Current Place picker
                pickCurrentPlace();
                return true;

امتحانش کن

اگر اکنون برنامه را اجرا کنید و روی « انتخاب مکان » ضربه بزنید، باید مجوزهای مکان را درخواست کند.

  • اگر اجازه دهید، آن اولویت ذخیره می‌شود و از شما خواسته نمی‌شود. اگر مجوز را رد کنید، دفعه بعد که روی دکمه ضربه می زنید از شما خواسته می شود.
  • اگرچه getPlaceLikelihoods مکان های احتمالی فعلی را دریافت کرده است، ListView هنوز آنها را نمایش نمی دهد. در Android Studio، می‌توانید روی ⌘6 کلیک کنید تا گزارش‌های Logcat را برای عباراتی که دارای برچسب MapsActivity هستند بررسی کنید تا مطمئن شوید که روش‌های جدید شما به درستی کار می‌کنند.
  • اگر مجوز داده اید، گزارش ها شامل یک عبارت برای Latitude: و یک بیانیه برای Longitude: مکان شناسایی شده دستگاه را نشان می دهد. اگر قبلاً از Google Maps و منوی توسعه‌یافته شبیه‌ساز برای تعیین مکانی برای شبیه‌ساز استفاده کرده‌اید، این عبارات آن مکان را نشان می‌دهند.
  • اگر فراخوانی برای findCurrentPlace موفقیت آمیز بود، گزارش ها شامل پنج عبارت است که نام و مکان پنج مکان محتمل را چاپ می کند.

d9896a245b81bf3.png

12. انتخابگر مکان فعلی را پر کنید

یک کنترل کننده برای مکان های انتخاب شده تنظیم کنید

بیایید به این فکر کنیم که وقتی کاربر روی یک مورد در ListView کلیک می‌کند، می‌خواهیم چه اتفاقی بیفتد. برای تأیید انتخاب کاربر در مورد مکانی که در حال حاضر در آن قرار دارد، می توانید یک نشانگر به نقشه آن مکان اضافه کنید. اگر کاربر روی آن نشانگر کلیک کند، یک پنجره اطلاعاتی ظاهر می شود که نام مکان و آدرس را نشان می دهد.

این کنترل کننده کلیک را بعد از متد pickCurrentPlace قرار دهید.

MapsActivity.java listClickedHandler

    private AdapterView.OnItemClickListener listClickedHandler = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // position will give us the index of which place was selected in the array
            LatLng markerLatLng = mLikelyPlaceLatLngs[position];
            String markerSnippet = mLikelyPlaceAddresses[position];
            if (mLikelyPlaceAttributions[position] != null) {
                markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[position];
            }

            // Add a marker for the selected place, with an info window
            // showing information about that place.
            mMap.addMarker(new MarkerOptions()
                    .title(mLikelyPlaceNames[position])
                    .position(markerLatLng)
                    .snippet(markerSnippet));

           // Position the map's camera at the location of the marker.
            mMap.moveCamera(CameraUpdateFactory.newLatLng(markerLatLng));
        }
    };

ListView را پر کنید

اکنون که فهرست محتمل‌ترین مکان‌هایی را دارید که کاربر در حال حاضر از آنها بازدید می‌کند، می‌توانید آن گزینه‌ها را در ListView به کاربر ارائه دهید. همچنین می توانید شنونده کلیک ListView را برای استفاده از کنترل کننده کلیکی که به تازگی تعریف کرده اید تنظیم کنید.

این روش را بعد از کنترل کننده کلیک قرار دهید:

MapsActivity.java fillPlacesList()

    private void fillPlacesList() {
        // Set up an ArrayAdapter to convert likely places into TextViews to populate the ListView
        ArrayAdapter<String> placesAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mLikelyPlaceNames);
        lstPlaces.setAdapter(placesAdapter);
        lstPlaces.setOnItemClickListener(listClickedHandler);
    }

اکنون که fillPlacesList تعریف شده است، خط انتهای findPlaceLikelihoods را پیدا کنید که fillPlacesList را فراخوانی می کند و آن را از نظر خارج کنید.

MapsActivity.java fillPlaceLikelihoods()

               // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Populate the ListView
                fillPlacesList();

این تمام کد مورد نیاز برای انتخاب کننده مکان فعلی است!

13. برنامه را اجرا کنید

تست انتخاب مکان

  1. دوباره برنامه را اجرا کنید.

این بار وقتی روی « انتخاب مکان » ضربه می‌زنید، برنامه فهرست را با مکان‌های نام‌گذاری شده نزدیک به مکان پر می‌کند. در نزدیکی این مکان در مائوئی، مکان‌هایی مانند یخ‌های هاوایی Shave Ice و Sugar Beach Bake Shop Ululani وجود دارد. از آنجایی که چندین مکان به مختصات مکان بسیار نزدیک هستند، این لیستی از مکان‌های احتمالی است که ممکن است در آن باشید.

  1. روی نام مکان در ListView .

شما باید یک نشانگر اضافه شده به نقشه را ببینید.

  1. روی نشانگر ضربه بزنید.

می توانید جزئیات مکان را ببینید.

e52303cc0de6a513.png864c74342fb52a01.png

مکان دیگری را تست کنید

اگر می‌خواهید مکان خود را تغییر دهید و از شبیه‌ساز استفاده می‌کنید، وقتی مختصات مکان را در منوی توسعه‌یافته شبیه‌ساز به‌روزرسانی می‌کنید، مکان دستگاه به‌طور خودکار به‌روزرسانی نمی‌شود.

برای رفع این مشکل، این مراحل را دنبال کنید تا از برنامه بومی Google Maps برای به‌روزرسانی‌های مکان شبیه‌ساز استفاده کنید:

  1. Google Maps را باز کنید.
  2. برای تغییر طول و عرض جغرافیایی به مختصات جدید روی ... > مکان ضربه بزنید، سپس روی ارسال ضربه بزنید.
  3. به عنوان مثال، می توانید از Latitude: 49.2768 و Longitude: -123.1142 برای تنظیم مکان در مرکز شهر ونکوور، کانادا استفاده کنید.
  4. بررسی کنید که Google Maps مختصات جدید شما را تازه‌سازی کرده است. ممکن است لازم باشد روی دکمه موقعیت مکانی من در برنامه Google Maps ضربه بزنید تا دوباره درخواست کنید.
  5. به برنامه مکان فعلی خود برگردید و روی انتخاب مکان ضربه بزنید تا نقشه را روی مختصات جدید دریافت کنید و لیست جدیدی از مکان‌های احتمالی فعلی را ببینید.

9adb99d1ce25c184.png

و بس! شما یک برنامه ساده ساخته اید که مکان های موجود در مکان فعلی را بررسی می کند و به شما امکان می دهد در کدام مکان هستید. لذت بردن!

حالا پیش بروید و برنامه را با تغییراتی که برای تکمیل این مرحله جایزه انجام دادید اجرا کنید!

14. مراحل بعدی

برای جلوگیری از سرقت کلید API خود، باید آن را ایمن کنید تا فقط برنامه اندروید شما بتواند از کلید استفاده کند. اگر بدون محدودیت باقی بماند، هر کسی که کلید شما را داشته باشد می‌تواند از آن برای تماس با APIهای پلتفرم Google Maps استفاده کند و باعث شود صورت‌حساب دریافت کنید.

گواهی SHA-1 خود را دریافت کنید

بعداً وقتی کلیدهای API خود را محدود می کنید به این نیاز خواهید داشت. در زیر مجموعه ای از دستورالعمل ها برای دریافت گواهی اشکال زدایی آمده است.

برای لینوکس یا macOS، یک پنجره ترمینال را باز کنید و موارد زیر را وارد کنید:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

برای ویندوز ویستا و ویندوز 7، دستور زیر را اجرا کنید:

keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

شما باید خروجی مشابه این را ببینید:

Alias name: androiddebugkey
Creation date: Jan 01, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 4aa9b300
Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033
Certificate fingerprints:
     MD5:  AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9
     SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75
     Signature algorithm name: SHA1withRSA
     Version: 3

خطی که SHA1 شروع می شود حاوی اثر انگشت SHA-1 گواهی است. اثر انگشت دنباله ای از 20 عدد هگزادسیمال دو رقمی است که با دو نقطه از هم جدا شده اند.

هنگامی که آماده انتشار یک برنامه هستید، از دستورالعمل های این اسناد برای بازیابی گواهی انتشار خود استفاده کنید.

محدودیت هایی را به کلید API خود اضافه کنید

  1. در Cloud Console، به APIs & Services > Credentials بروید.

کلیدی که برای این برنامه استفاده کردید باید در زیر کلیدهای API فهرست شود.

  1. کلیک 6454a04865d551e6.png برای ویرایش تنظیمات کلیدی

316b052c621ee91c.png

  1. در صفحه کلید API، پس از کلید محدودیت ها ، محدودیت های برنامه را با انجام موارد زیر تنظیم کنید:
  2. برنامه های اندروید را انتخاب کنید و دستورالعمل ها را دنبال کنید.
  3. روی افزودن یک مورد کلیک کنید.
  4. نام بسته و اثر انگشت گواهی SHA-1 خود را وارد کنید (بازیابی شده در بخش قبلی).

مثلا:

com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
  1. برای محافظت بیشتر، محدودیت های API را با انجام موارد زیر تنظیم کنید.
  2. پس از محدودیت‌های API، Restrict key را انتخاب کنید.
  3. Maps SDK for Android and Places API را انتخاب کنید.
  4. روی Done و Save کلیک کنید.

15. تبریک می گویم

شما یک برنامه ساده ساخته‌اید که محتمل‌ترین مکان‌ها را در مکان فعلی بررسی می‌کند و نشانگر مکانی را که کاربر انتخاب می‌کند به نقشه اضافه می‌کند.

بیشتر بدانید