بروز خطا
   [message]
اشتراک در سوال
رای ها
[dataList]
پرسش و پاسخ

مسیریابی بر روی نقشه گوگل از داخل اپلیکیشن + سورس (آموزش)

مدیریت گفتگو
کاشی زاده 12 سال پیش
آخرین تغییر: 9 سال پیش

خُب من خیلی دنبال این قضیه بودم و برام خیلی مهم بود ، بعد از چند وقت روش این کار رو پیدا کردم .

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

از اونجا که این روش یکم پیچیده هست من فقط بعضی از قسمت ها رو توضیح میدم بقیش رو خودتون در حین کار یاد میگیرید. 


 

اول از همه یه اکتیویتی میسازید به اسم NavigationActivity و از FragmentActivity اکستندز میکنید .

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

یه دکمه برای مسیر یابی میسازید و برای متد onClick رو Override میکنید.

داخل متد کلیک از این کد استفاده کنید :

findDirections( TEHRAN.latitude, TEHRAN.longitude,MASHAD.latitude, MASHAD.longitude, GMapV2Direction.MODE_DRIVING );

فقط یه توضیح میدم ما مختصات تهران و مشهد رو به صورت فیلدی از جنس LatLng (موقعیت جغرافی) در میاریم به شکل زیر :

 private static final LatLng TEHRAN = new LatLng(35.7014396, 51.3498186);
 private static final LatLng MASHAD = new LatLng(36.3164008, 59.5493205);

خب متد findDirections :

 public void findDirections(double fromPositionDoubleLat, double fromPositionDoubleLong,
double toPositionDoubleLat, double toPositionDoubleLong, String mode) { Map<String, String> map = new HashMap<String, String>(); map.put(GetDirectionsAsyncTask.USER_CURRENT_LAT, String.valueOf(fromPositionDoubleLat)); map.put(GetDirectionsAsyncTask.USER_CURRENT_LONG, String.valueOf(fromPositionDoubleLong)); map.put(GetDirectionsAsyncTask.DESTINATION_LAT, String.valueOf(toPositionDoubleLat)); map.put(GetDirectionsAsyncTask.DESTINATION_LONG, String.valueOf(toPositionDoubleLong)); map.put(GetDirectionsAsyncTask.DIRECTIONS_MODE, mode); GetDirectionsAsyncTask asyncTask = new GetDirectionsAsyncTask(this); asyncTask.execute(map); }

از HashMap استفاده میکنیم که قبلا در آموزش های استاد توضیحاتش داده شده و مقادیری که در کلاس AsyncTask که بعدا میسازیم وجود داره رو داخل این HashMap ذخیره میکنیم.

و در آخر هم کلاس GetDirectionsAsyncTask  رو اجرا میکنیم .

یک کلاس جدید میسازیم به نام GetDirectionsAsyncTask  و از AsyncTask اکستندز میکنیم .

داخلش فیلد های زیر رو میسازیم :

 public static final String USER_CURRENT_LAT = "user_current_lat";
 public static final String USER_CURRENT_LONG = "user_current_long";
 public static final String DESTINATION_LAT = "destination_lat";
 public static final String DESTINATION_LONG = "destination_long";
 public static final String DIRECTIONS_MODE = "directions_mode";

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

داخل این کلاس ما چند فیلد دیگه هم معرفی میکنیم :

  private NavigationActivity activity;
  private Exception exception;
  private ProgressDialog progressDialog;

این فیلد ها مربوط به کانتکست اکتیویتی ، دیالاگ و اکسپشن هستن .

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

 public GetDirectionsAsyncTask(NavigationActivity activity)
    {
        super();
        this.activity = activity;
    }

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

  public void onPreExecute()
    {
        progressDialog = new ProgressDialog(activity);
        progressDialog.setMessage("Calculating directions");
        progressDialog.show();
    }

داخل متد onPostExecute  دیالاگ رو در صورتی که خطایی وجود نداشته باشه میبندیم و متدی رو که در اصلی یا همون 

NavigationActivity هست رو صدا میزنیم . 

توضیحات متد handleGetDirectionsResult رو بعدا میدم، الان فقط در همین حد بدونید که یک متدی با این نام داخل اکتیویتیNavigationActivity وجود داره.

نکته ای که اینجا هست متد onPostExecute  هم داخل ترد مین اجرا میشه .

  public void onPostExecute(ArrayList result)
    {
        progressDialog.dismiss();
        if (exception == null)
        {
            activity.handleGetDirectionsResult(result);
        }
        else
        {
            processException();
        }
    }

میریم سراغ متد doInBackground ، توجه داشته باشید که این متد داخل ترد مین صدا زده نمیشه و ما نمیتونیم در UI اعمال تغییرات کنیم .

 

 protected ArrayList<LatLng> doInBackground(Map<String, String>... params)
    {
        Map<String, String> paramMap = params[0];
        try
        {
            LatLng fromPosition = new LatLng(Double.valueOf(paramMap.get(USER_CURRENT_LAT))
, Double.valueOf(paramMap.get(USER_CURRENT_LONG))); LatLng toPosition = new LatLng(Double.valueOf(paramMap.get(DESTINATION_LAT)) ,
Double.valueOf(paramMap.get(DESTINATION_LONG))); GMapV2Direction md = new GMapV2Direction(); Document doc = md.getDocument(fromPosition, toPosition, paramMap.get(DIRECTIONS_MODE)); ArrayList<LatLng> directionPoints = md.getDirection(doc); return directionPoints; } catch (Exception e) { exception = e; return null; } }

داخل این متد ما مختصاتی که قبلا براش در یک HashMap ذخیره کردیم رو فراخونی میکنیم و داخل یک متغیر از جنس LatLng (موقعیت جغرافیایی) میریزیم .

حالا اینجا یک کلاس جدید داریم به اسم GMapV2Direction که بهتون میگم این کلاس چیه در واقع.

غیر از این کلاس ما بایک کلاس جدید از کتابخانه اندروید آشنا میشیم به اسم Document که در واقع این کلاس برای نمایش xml , html به کار میره . توضیحات بیشتر رو میتونید در مستندات گوگل بخونید : لینک

 

 

کلاس GMapV2Direction  همه این داسان زیر سر این کلاس هست و نکات خیلی ریزی هم داره که نمیشه همش رو توضیح بدم یکم روش کار کنید متوجه میشید .

داخل این کلاس ما 2 فیلد تعریف میکنیم برای مشخص کردن نوع حرکت که پیاده هستید یا با ماشین :

  public final static String MODE_DRIVING = "driving";
  public final static String MODE_WALKING = "walking";

متدی داریم با نام getDocument  که کارش گرفتن اطلاعات مسیریابی از سرور گوگل هست . 

کد زیر کاملا واضح هست و توضیحی نداره ، اطلاعات بیشتر در مورد کلاس های لایبری اندروید و متد هاشون  میتونید در اسناد گوگل پیدا کنید .

  public Document getDocument(LatLng start, LatLng end, String mode) {
        String url = "http://maps.googleapis.com/maps/api/directions/xml?" 
                + "origin=" + start.latitude + "," + start.longitude  
                + "&destination=" + end.latitude + "," + end.longitude 
                + "&sensor=false&units=metric&mode=driving";

        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpContext localContext = new BasicHttpContext();
            HttpPost httpPost = new HttpPost(url);
            HttpResponse response = httpClient.execute(httpPost, localContext);
            InputStream in = response.getEntity().getContent();
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.parse(in);
            return doc;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

خوب حالا متدی داریم شامل این دستورات :

 public ArrayList<LatLng> getDirection (Document doc) {
        NodeList nl1, nl2, nl3;
        ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
        nl1 = doc.getElementsByTagName("step");
        if (nl1.getLength() > 0) {
            for (int i = 0; i < nl1.getLength(); i++) {
                Node node1 = nl1.item(i);
                nl2 = node1.getChildNodes();

                Node locationNode = nl2.item(getNodeIndex(nl2, "start_location"));
                nl3 = locationNode.getChildNodes();
                Node latNode = nl3.item(getNodeIndex(nl3, "lat"));
                double lat = Double.parseDouble(latNode.getTextContent());
                Node lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                double lng = Double.parseDouble(lngNode.getTextContent());
                listGeopoints.add(new LatLng(lat, lng));

                locationNode = nl2.item(getNodeIndex(nl2, "polyline"));
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item(getNodeIndex(nl3, "points"));
                ArrayList<LatLng> arr = decodePoly(latNode.getTextContent());
                for(int j = 0 ; j < arr.size() ; j++) {
                    listGeopoints.add(new LatLng(arr.get(j).latitude, arr.get(j).longitude));
                }

                locationNode = nl2.item(getNodeIndex(nl2, "end_location"));
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item(getNodeIndex(nl3, "lat"));
                lat = Double.parseDouble(latNode.getTextContent());
                lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                lng = Double.parseDouble(lngNode.getTextContent());
                listGeopoints.add(new LatLng(lat, lng));
            }
        }

        return listGeopoints;
    }

توضیحات این متد یکم زیاده خودتون مطالعه کنید فقط در این حد بهتون بگم که این متد مجموعه ای از موقعیت های جغرافیایی یا Geopoint رو به ما میده .

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

برمیگردیم سراغ متد handleGetDirectionsResult که داخل اکتیویتی اصلی ما قرار داره (NavigationActivity)  که کدش به صورت زیر هست :

 public void handleGetDirectionsResult(ArrayList<LatLng> directionPoints) {
		PolylineOptions rectLine = new PolylineOptions().width(5).color(Color.RED);

		for(int i = 0 ; i < directionPoints.size() ; i++) 
		{          
			rectLine.add(directionPoints.get(i));
		}
		if (newPolyline != null)
		{
			newPolyline.remove();
		}
		newPolyline = map.addPolyline(rectLine);
		latlngBounds = createLatLngBoundsObject(TEHRAN, MASHAD);
	        map.animateCamera(CameraUpdateFactory.newLatLngBounds(latlngBounds,
width, height, 150)); }

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

 

یکم سخت و پیچیده هست و شما با استفاده از این پروژه میتونید برای خودتون یک اپلیکیشن حرفه ای برای مسیریابی بسازید.

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

 

متاسفانه سورس اصلاح شده توسط در دسترس نیست

از این لینک میتونید سورس رو دریافت کنید

 

موفق و سربلند باشید :)

نظرات

Mr7 12 سال پیش
ممنون داداش دمت گرم
RojaDev 12 سال پیش
سورس رو تو اکلیپس امپورت کردم خطای زیر رو بهم میده..ممنون میشم راهنمایم کنید : [2014-09-30 2208 - NavigationApplication] Unable to resolve target 'Google Inc.:Google APIs (x86 System Image):19'
کاشی زاده 12 سال پیش
من در پروژه از google Api 19 استفاده کردم شما هم این Api رو دانلود کنید مشکل حل میشه
RojaDev 12 سال پیش
تو این لینک استاد یه سری فایل واسه جنی موشن واسه دانلود گذاشتن که واسه هر یه api داره از همونا دانلود کنم حل میشه؟!
کاشی زاده 12 سال پیش
اره از همون استفاده کنید و در قسمت تنظیمات و منی فست کتابخانه خودتون رو اضافی کنید
Eminent 12 سال پیش
من یه سوال دارم ربطی هم به اینجا نداره اما دیگه میپرسم genymotion شما هم به sdcard دسترسی نداره ؟
کاشی زاده 12 سال پیش
به sd card دسترسی داره و میتونید فایل هارو ازش خارج کنید ولی به data/data دسترسی نداره
nomad811 11 سال پیش
ببخشید اینو میگم پررو پررو ، امکان دانلود سرس کد نیست ، میشه یه چک بکنی ؟ شاید مشکل از سمته منه .
کاشی زاده 11 سال پیش
شرمنده رفتم دیدم نیستش فایل تو سرور گشتم پیدا نکردم آخه یکم خونه تکونی داشتیمم تو ویندوز پیدا کردم برات میذارم
سپهر 11 سال پیش
این لینک سورس پروژه هست اما کدی که محمد حسین گذاشته کامل تر و شسته رفته تره
atf 11 سال پیش
کد اصلی رو میشه بزارید من خیلی نیاز دارم البته اگه پیدا شده باشه
کاشی زاده 11 سال پیش
لینکی که سپهر گذاشته همون سورس اصلی هست من فقط توش بعضی از مشکلات و چیزای اضافیش رو حل و حذف کرده بودم .
Amin 11 سال پیش
در متد ArrayList getDirection خطای The method getTextContent() is undefined for the type Node رو میده!
Amin 11 سال پیش
برای اینکه بخواهیم وقتی مسیر یابی کرد فاصله و زمان بین دو مکان را بدست بیاوریم چه کار باید کرد؟!
کاشی زاده 11 سال پیش
برای محاسبه فاصله بین دونقطه یک فرمول ریاضی داره که باید برید و سرچ کنید در استک وجود داره . زمان هم باید بررسی کنید سرعت اون فرد چقدر هست و مسافت رو تقسیم بر سرعت کنید .
h_uk2009 11 سال پیش
سلام سورسش کجاست !؟
amirhossein1376 10 سال پیش
سلام آقای کاشی زاده میشه لطف کنید بگید چجوری میشه بخشی از نقشه رو جهت مشاهده آفلاین روی حافظه گوشی ذخیره کرد؟
کاشی زاده 10 سال پیش
خود Google Map اتوماتیک این کارو انجام میده و هر قسمتی که یکبار لود بشه به صورت آفلاین هم قابل مشاهده است .
amirhossein1376 10 سال پیش
ممنون یه سوال دیگه اینکه بعضی نرم افزار ها قابلیت دانلود یه شهر خاص یا یه کشور خاص رو میزارن میشه بگید اون چطوریه؟ممنون
کاشی زاده 10 سال پیش
اطلاعی ندارم باید برید API گوگل رو مطالعه کنید ببنید چه ویژگی هایی داره .
ameri 9 سال پیش
The method getTextContent() is undefined for the type Node سلام اگر میشه بگید که این خطا رو چطور برطرف کنم؟

هنوز پاسخی ثبت نشده است


پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .