دروس Android على خريطة Google: رسم المسارات بين نقطتين
نشرت: 2018-05-30في هذا المنشور ، سنناقش كيفية رسم الطريق على خرائط Google بين نقطتين.

أولاً ، نحتاج إلى تكامل خرائط Google على تطبيقنا. للقيام بذلك ، قم بزيارة
- https://developers.google.com/maps/documentation/android-api/signup
- انقر فوق الزر Get A Key
سترى مربع حوار مشابه للمربع أدناه.

قم بإنشاء مشروع جديد وانقر فوق التالي. سيتم تقديمك بمفتاح API مثل المفتاح أدناه.

لنفترض ، إذا اخترت تقييد استخدام هذا المفتاح ، فانقر فوق وحدة تحكم API. عدا ذلك ، انقر فوق تم.
في وحدة تحكم واجهة برمجة التطبيقات ، يمكنك تقييد استخدام المفتاح فقط لمواقع الويب وتطبيقات Android وتطبيقات IOS وما إلى ذلك.
عند النقر فوق وحدة تحكم واجهة برمجة التطبيقات ، ستتم إعادة توجيهك إلى صفحة أخرى بتاريخ الإنشاء ، تم الإنشاء بواسطة إلخ. اختر مفتاح واجهة برمجة التطبيقات حيث يجب تقييده ثم انقر فوق زر راديو تطبيقات Android.
لنفترض أنك تريد تقييد الاستخدام على تطبيقات Android ، وأضف اسم الحزمة وبصمة الإصبع.
يمكنك الحصول على اسم الحزمة من ملف Androidmanifest.xml .

لإضافة بصمة إصبع ، يجب أن تحصل على شهادة SHA-1. لذلك ، قم بزيارة Android Studio وافتح Gradle File في الزاوية اليمنى.
علاوة على ذلك ، انقر فوق تطبيق gradle >> المهام >> android >> تقرير التوقيع

انسخ شهادة SHA-1 والصقها في مربع بصمة SHA-1 كما هو موضح في الصورة أعلاه. أخيرًا ، انقر فوق الزر حفظ.
الآن قم بإنشاء مشروع Android جديد بالاسم ومجال الشركة وتفاصيل أخرى. اختر إصدار Android الخاص بك مثل Lollipop ، واختر مسار الرسم على نشاط خرائط Google كما هو موضح أدناه. الآن انقر فوق زر التالي والانتهاء.

بعد إنشاء المشروع يمكنك رؤية بعض الملفات مثل
- MapsActivity.java
- Activity_maps.xml
- google_maps-api.xml
أولاً ، قم بتغيير google_map_api.xml. في هذا الملف ، أضف مفتاح Google API الذي أنشأناه من قبل.
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">API Key</string>بعد ذلك ، قم بتغيير ملف Androidmanifest.xml
- اتصال الإنترنت - للتواصل مع API وللحصول على الموقع
- READ_GSERVICES - متى أراد أحد التطبيقات استخدام Google Service Framework
- ACCESS_COARSE_LOCATION - سيحدد موقع المستخدم باستخدام Wifi وبيانات الجوال. سيعطي الموقع التقريبي
- ACCESS_FINE_LOCATION- سيحدد موقع المستخدم باستخدام GPS. سوف يعطيك الموقع الدقيق.
- أضف أيضًا علامة البيانات الوصفية في علامة التطبيق التي تحتوي على قيمة مفتاح API
يبدو ملف Androidmanifest.xml كما يلي
<manifest xmlns:andro package="com.example.drawroutes"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <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"> <meta-data android:name="com.google.android.geo.API_KEY" android:value="@string/google_maps_key" /> <activity android:name=".MapsActivity" android:label="@string/title_activity_maps"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>الآن قم بتغيير ملف build.gradle. أثناء التغيير ، تأكد من إضافة التبعيتين ، وهما:
- التنفيذ "com.google.android.gms: play-services-maps: 11.8.0"
- التنفيذ "com.google.android.gms: play-services-location: 11.8.0"
بينما يتم استخدام التبعية الأولى لعرض خريطة google ، يتم استخدام التبعية الثانية للحصول على موقع Google والتعرف على النشاط.
لذا يبدو ملف build.gradle كما يلي
apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.example.drawroutes" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.google.android.gms:play-services-maps:11.8.0' implementation 'com.google.android.gms:play-services-location:11.8.0' }دعونا نبدأ مع MapsActivity. في هذا النشاط ، قمنا بتعيين ملف التخطيط المسمى Activity_maps
في ملف xml هذا ، حدد جزءًا ، وأعلن معرف واسم الجزء. أخيرًا ، يكون ملف xml كما هو موضح أدناه .
<fragment xmlns:andro xmlns:tools="schemas.android.com/tools" android: android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.drawroutes.MapsActivity" />أنت هنا تعلن عن android: name = "com.google.android.gms.maps.SupportMapFragment" لأننا نوسع النشاط من FragmentActivity. إذا كنت تريد استخدام MapFragment ، فيمكنك توسيع النشاط.
بعد ذلك ، قم بتوسيع MapsActivity حيث يتم تعريف المعرف بهذه الطريقة:
Final SupportMapFragment mapFragment =(SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map);دعونا نقسم الكود هنا ونناقش واحدًا تلو الآخر. في البداية ، تحتاج إلى إنشاء فئة خرائط Google.
أعلن الآن عن الخريطة انقر فوق Listner
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { // Already two locations if (MarkerPoints.size() > 1) { MarkerPoints.clear(); mMap.clear(); } // Adding new item to the ArrayList MarkerPoints.add(point); // Creating MarkerOptions MarkerOptions options = new MarkerOptions(); // Setting the position of the marker options.position(point); /** * For the start location, the color of marker is GREEN and * for the end location, the color of marker is RED. */ if (MarkerPoints.size() == 1) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); } else if (MarkerPoints.size() == 2) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)); } // Add new marker to the Google Map Android API V2 mMap.addMarker(options); // Checks, whether start and end locations are captured if (MarkerPoints.size() >= 2) { LatLng origin = MarkerPoints.get(0); LatLng dest = MarkerPoints.get(1); // Getting URL to the Google Directions API String url = getUrl(origin, dest); Log.d("onMapClick", url.toString()); FetchUrl FetchUrl = new FetchUrl(); // Start downloading json data from Google Directions API FetchUrl.execute(url); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(origin)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); } } });سيتم تنفيذ الكود الموضح أعلاه عندما ينقر المستخدم على شاشة Android. يستخدم هذا لوضع العلامة عند النقاط التي سيتم رسم المسار بينها.

يستخدم MarkerPoints.get () للوصول إلى إحداثيات النقطتين وتخزينهما . سيتم تخزينه في أصل ووجهة LatLng.
ويتم استخدام getUrl لجلب عنوان URL وتنفيذه باستخدام Async Task.
مهمة Async: Async Task هي فئة Abstract يقدمها Android ، مما يساعد على استخدام مؤشر ترابط واجهة المستخدم. تسمح لنا فئة Async Task بإجراء عمليات تشغيل طويلة أو عمليات في الخلفية وعرض النتائج على UI Thread دون التأثير على سلسلة المحادثات الرئيسية. تُستخدم المهام غير المتزامنة Async Task لتشغيل المهام / العمليات التي يجب إجراؤها في الخلفية بشكل غير متزامن. في فئة المهام غير المتزامن هناك طريقتان.
- doInbackground: سيتم تنفيذ المهمة بهذه الطريقة.
- onPostExecute: سيتم عرض النتيجة بهذه الطريقة.
private class FetchUrl extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... url) { // For storing data from web service String data = ""; try { // Fetching the data from web service data = downloadUrl(url[0]); Log.d("Background Task data", data.toString()); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); ParserTask parserTask = new ParserTask(); // Invokes the thread for parsing the JSON data parserTask.execute(result); } }downloadUrl: يستخدم هذا لجلب عنوان URL من خدمة الويب وسيتم تحليل نتائجه باستخدام ParserTask. هذه أيضًا مهمة غير متزامنة.
private String downloadUrl(String strUrl) throws IOException { String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try { URL url = new URL(strUrl); // Creating an http connection to communicate with url urlConnection = (HttpURLConnection) url.openConnection(); // Connecting to url urlConnection.connect(); // Reading data from url iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } data = sb.toString(); Log.d("downloadUrl", data.toString()); br.close(); } catch (Exception e) { Log.d("Exception", e.toString()); } finally { iStream.close(); urlConnection.disconnect(); } return data; }هنا سيتم إرجاع البيانات في شكل Json. الذي يمكن للمستخدم الحصول عليه باستخدام HttpURLConnection.
مهمة المحلل اللغوي: تحديد فئة جديدة باسم ParserTask الذي يمتد AsyncTask. تحليل بيانات Json التي تم إرجاعها بواسطة طريقة downloadUrl.
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { // Parsing the data in non-ui thread @Override protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) { JSONObject jObject; List<List<HashMap<String, String>>> routes = null; try { jObject = new JSONObject(jsonData[0]); Log.d("ParserTask",jsonData[0].toString()); DataParser parser = new DataParser(); Log.d("ParserTask", parser.toString()); // Starts parsing data routes = parser.parse(jObject); Log.d("ParserTask","Executing routes"); Log.d("ParserTask",routes.toString()); } catch (Exception e) { Log.d("ParserTask",e.toString()); e.printStackTrace(); } return routes; } // Executes in UI thread, after the parsing process @Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points; PolylineOptions lineOptions = null; // Traversing through all the routes for (int i = 0; i < result.size(); i++) { points = new ArrayList<>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(10); lineOptions.color(Color.RED); Log.d("onPostExecute","onPostExecute lineoptions decoded"); } // Drawing polyline in the Google Map for the i-th route if(lineOptions != null) { mMap.addPolyline(lineOptions); } else { Log.d("onPostExecute","without Polylines drawn"); } } }هنا ، سيقوم "doInBackround" بتحليل البيانات. في طريقة "onPostExecute" سنضيف الشكل متعدد الخطوط لرسم المسار على خريطة Google.
باتباع هذه الطرق ، نقوم بتحليل البيانات إلى فئة أخرى ، مثل DataParser
class DataParser { List<List<HashMap<String,String>>> parse(JSONObject jObject){ List<List<HashMap<String, String>>> routes = new ArrayList<>() ; JSONArray jRoutes; JSONArray jLegs; JSONArray jSteps; try { jRoutes = jObject.getJSONArray("routes"); /** Traversing all routes */ for(int i=0;i<jRoutes.length();i++){ jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs"); List path = new ArrayList<>(); /** Traversing all legs */ for(int j=0;j<jLegs.length();j++){ jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps"); /** Traversing all steps */ for(int k=0;k<jSteps.length();k++){ String polyline = ""; polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points"); List<LatLng> list = decodePoly(polyline); /** Traversing all points */ for(int l=0;l<list.size();l++){ HashMap<String, String> hm = new HashMap<>(); hm.put("lat", Double.toString((list.get(l)).latitude) ); hm.put("lng", Double.toString((list.get(l)).longitude) ); path.add(hm); } } routes.add(path); } } } catch (JSONException e) { e.printStackTrace(); }catch (Exception e){ } return routes; } /** * Method to decode polyline points * */ private List<LatLng> decodePoly(String encoded) { List<LatLng> poly = new ArrayList<>(); int index = 0, len = encoded.length(); int lat = 0, lng = 0; while (index < len) { int b, shift = 0, result = 0; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += dlng; LatLng p = new LatLng((((double) lat / 1E5)), (((double) lng / 1E5))); poly.add(p); } return poly; } }باستخدام طريقة التحليل ، تحصل على بيانات Json التي يمكنها تقسيم JSONArray باستخدام getJSONArray. اجتياز جميع المسارات والنقاط وما إلى ذلك وإضافة جميع نقاط العبور إلى القائمة.
المسارات. add (المسار) ؛
ارسم الطريق على خريطة جوجل باستخدام الخطوط المتعددة. يتم ذلك في طريقة onPostExecute حيث فئة ParseTask AsyncTask.
@Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points; PolylineOptions lineOptions = null; // Traversing through all the routes for (int i = 0; i < result.size(); i++) { points = new ArrayList<>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(10); lineOptions.color(Color.RED); Log.d("onPostExecute","onPostExecute lineoptions decoded"); } // Drawing polyline in the Google Map for the i-th route if(lineOptions != null) { mMap.addPolyline(lineOptions); } else { Log.d("onPostExecute","without Polylines drawn"); } }يتم جلب النقاط أعلاه من النتيجة ورسم طريق على خرائط جوجل. هنا يتم استخدام نقاط ArrayList لتخزين مواضع Latitude و Longitude على خريطة Google.
أخيرًا ، يتم رسم المسار على خريطة Google باستخدام polyLine: lineOptions.addAll (نقاط) ؛
أضف الشكل متعدد الخطوط لتعيينه مثل: mMap.addPolyline (lineOptions) ؛
أخيرًا قم بتشغيل التطبيق. سوف يعمل بنجاح. خرج الشاشة كما هو موضح أدناه.

