شروع دوره پایتون از پنجشنبه 1 خرداد ، مقدماتی تا پیشرفته، بدون پیش نیاز شروع دوره پایتون از پنجشنبه 1 خرداد ، مقدماتی تا پیشرفته، بدون پیش نیاز
🎯 ثبت نام

مکان یابی در Xamarin.Android

کلیه حقوق مادی و معنوی این مقاله متعلق به آموزشگاه تحلیل داده می باشد و هر گونه استفاده غیر قانونی از آن پیگرد قانونی دارد .

کار با GPS و مکان یابی در Xamarin.Android

چند ماهی هست که من کار با برنامه نویسی موبایل با استفاده از Xamarin شروع کرده ام. در ابتدا یک برنامه ساده ساختم که می توانست داده را بین دستگاه های  پوشیدنی (wearable) و دستی (handheld) همگام سازی کند و با سایر دستگاه های اندرویدی کار کند. جالب بود، اما با مشکلات زیادی در زمان یادگیری مواجه شدم.

این مقاله برای برنامه نویسانی نوشته شده است که به برنامه نویسی موبایل علاقه مند هستند و قصد دارند کار با ویژگی های GPS و مکان یابی آن را یاد بگیرند. در این مثال ویژه به شما نشان خواهم داد چطور موقعیت فعلی دستگاه را بدست آورید و مشخص کنید که از یک موقعیت خاص چند مایل فاصله دارید.

قبل از شروع مطمئن شوید حداقل نیازمندی ها در سیستم شما برآورده شده باشد و محیط برنامه نویسی شما به درستی تنظیم شده باشد. برای آماده سازی محیط برنامه نویسی لطفاً به مقاله " شروع به کار Android Wearable با استفاده از Xamarin و Visual Studio " مراجعه نمائید.

برای این مثال از Visual Studio 2015 به همراه آخرین نسخه از Xamarin استفاده میکنم.

شروع کار

ابتدا Visual Studio 2015 را اجرا کرده و با انتخاب File>New>Project، یک پروژه جدید ایجاد کنید:

آموزش Xamarin

در پنجره باز شده، در قسمت Templates، گزینه Visual c#> Android> Blanck App(Android) را انتخاب کنید. یک نام برای برنامه خود انتخاب و وارد کنید. من نام این برنامه را " MyFirstGPSApp" گذاشتم. حالا بر روی OK کلیک کنید تا فایل های لازم برای برنامه تولید شوند. پس از آن با صفحه زیر مواجه خواهید شد:


آموزش Xamarin

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

آموزش Xamarin

ساخت کلاس های Latitute و Longitude 

ابتدا یک کلاس ایجاد کنید و خصوصیات زیر را برای آن تعریف کنید:

namespace MyFirstGPSApp 

{ 

    public class LatLng 

    { 

        public double Latitude { get; set; } 

        public double Longitude { get; set; } 

        public LatLng(double lat, double lng) 

        { 

            this.Latitude = lat; 

            this.Longitude = lng; 

        } 

    } 

} 

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

ساخت کلاس Helper

در مرحله بعد باید یک کلاس helper بسازیم تا از یکسری کدهای متداول استفاده کنیم. کلاس Helper به شکل زیر خواهد بود:

using System; 

 

namespace MyFirstGPSApp 

{ 

    static class Utils 

    { 

        public enum DistanceUnit { Miles, Kilometers }; 

        public static double ToRadian(this double value) 

        { 

            return (Math.PI / 180) * value; 

        } 

        public static double HaversineDistance(LatLng coord1, LatLng coord2, DistanceUnit unit) 

        { 

            double R = (unit == DistanceUnit.Miles) ? 3960 : 6371; 

            var lat = (coord2.Latitude - coord1.Latitude).ToRadian(); 

            var lng = (coord2.Longitude - coord1.Longitude).ToRadian(); 

 

            var h1 = Math.Sin(lat / 2) * Math.Sin(lat / 2) + 

                     Math.Cos(coord1.Latitude.ToRadian()) * Math.Cos(coord2.Latitude.ToRadian()) * 

                     Math.Sin(lng / 2) * Math.Sin(lng / 2); 

 

            var h2 = 2 * Math.Asin(Math.Min(1, Math.Sqrt(h1))); 

 

            return R * h2; 

        } 

    } 

} 

متد ToRadian()، یک متد Extension است که مقادیر Double را به رادیان تبدیل می کند. متد HaversineDistance() نیز یک متد است که فاصله ی بین دو نقطه در مختصات را به شعاع بر می گرداند.

ساخت سرویس مکان یابی (Location Service)

دو گزینه برای پیاده سازی ویژگی سرویس مکان یابی در برنامه های اندروید وجود دارد. ساده ترین گزینه این است که کد مستقیماً در Main Activity پیاده سازی شود. یعنی پیاده سازی ILocationListener. گزینه ی دیگر، ساخت یک سرویس است که ILocationListener را پیاده سازی کند. من گزینه دوم را انتخاب کرده ام تا کد ما انعطاف پذیر تر و قابل استفاده تر شود تا در صورت نیاز مورد استفاده برنامه های دیگر نیز قرار  گیرد. در ادامه قطعه کد زیر برای سرویس مکان یابی مشاهده می کنید:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

using Android.App;

using Android.Content;

using Android.OS;

using Android.Locations;

 

namespace MyFirstGPSApp

{

 

    [Service]

    public class GPSService : Service, ILocationListener

    {

        private const string _sourceAddress = "TGU Tower, Cebu IT Park, Jose Maria del Mar St,Lahug, Cebu City, 6000 Cebu";

        private string _location = string.Empty;

        private string _address = string.Empty;

        private string _remarks = string.Empty;

 

        public const string LOCATION_UPDATE_ACTION = "LOCATION_UPDATED";

        private Location _currentLocation;

        IBinder _binder;

        protected LocationManager _locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(LocationService);

        public override IBinder OnBind(Intent intent)

        {

            _binder = new GPSServiceBinder(this);

            return _binder;

        }

 

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)

        {

            return StartCommandResult.Sticky;

        }

 

        public void StartLocationUpdates()

        {

            Criteria criteriaForGPSService = new Criteria

            {

                //A constant indicating an approximate accuracy 

                Accuracy = Accuracy.Coarse,

                PowerRequirement = Power.Medium

            };

 

            var locationProvider = _locationManager.GetBestProvider(criteriaForGPSService, true);

            _locationManager.RequestLocationUpdates(locationProvider, 0, 0, this);

 

        }

 

        public event EventHandler<LocationChangedEventArgs> LocationChanged = delegate { };

        public void OnLocationChanged(Location location)

        {

            try

            {

                _currentLocation = location;

 

                if (_currentLocation == null)

                    _location = "Unable to determine your location.";

                else

                {

                    _location = String.Format("{0},{1}", _currentLocation.Latitude, _currentLocation.Longitude);

 

                    Geocoder geocoder = new Geocoder(this);

 

                    //The Geocoder class retrieves a list of address from Google over the internet 

                    IList<Address> addressList = geocoder.GetFromLocation(_currentLocation.Latitude, _currentLocation.Longitude, 10);

 

                    Address addressCurrent = addressList.FirstOrDefault();

 

                    if (addressCurrent != null)

                    {

                        StringBuilder deviceAddress = new StringBuilder();

 

                        for (int i = 0; i < addressCurrent.MaxAddressLineIndex; i++)

                            deviceAddress.Append(addressCurrent.GetAddressLine(i))

                                .AppendLine(",");

 

                        _address = deviceAddress.ToString();

                    }

                    else

                        _address = "Unable to determine the address.";

 

                    IList<Address> source = geocoder.GetFromLocationName(_sourceAddress, 1);

                    Address addressOrigin = source.FirstOrDefault();

 

                    var coord1 = new LatLng(addressOrigin.Latitude, addressOrigin.Longitude);

                    var coord2 = new LatLng(addressCurrent.Latitude, addressCurrent.Longitude);

 

                    var distanceInRadius = Utils.HaversineDistance(coord1, coord2, Utils.DistanceUnit.Miles);

 

                    _remarks = string.Format("Your are {0} miles away from your original location.", distanceInRadius);

 

                    Intent intent = new Intent(this, typeof(MainActivity.GPSServiceReciever));

                    intent.SetAction(MainActivity.GPSServiceReciever.LOCATION_UPDATED);

                    intent.AddCategory(Intent.CategoryDefault);

                    intent.PutExtra("Location", _location);

                    intent.PutExtra("Address", _address);

                    intent.PutExtra("Remarks", _remarks);

                    SendBroadcast(intent);

                }

            }

            catch (Exception ex)

            {

                _address = "Unable to determine the address.";

            }

 

        }

 

        public void OnStatusChanged(string provider, Availability status, Bundle extras)

        {

            //TO DO: 

        }

 

        public void OnProviderDisabled(string provider)

        {

            //TO DO: 

        }

 

        public void OnProviderEnabled(string provider)

        {

            //TO DO: 

        }

    }

    public class GPSServiceBinder : Binder

    {

        public GPSService Service { get { return this.LocService; } }

        protected GPSService LocService;

        public bool IsBound { get; set; }

        public GPSServiceBinder(GPSService service) { this.LocService = service; }

    }

    public class GPSServiceConnection : Java.Lang.Object, IServiceConnection

    {

 

        GPSServiceBinder _binder;

 

        public event Action Connected;

        public GPSServiceConnection(GPSServiceBinder binder)

        {

            if (binder != null)

                this._binder = binder;

        }

 

        public void OnServiceConnected(ComponentName name, IBinder service)

        {

            GPSServiceBinder serviceBinder = (GPSServiceBinder)service;

 

            if (serviceBinder != null)

            {

                this._binder = serviceBinder;

                this._binder.IsBound = true;

                serviceBinder.Service.StartLocationUpdates();

                if (Connected != null)

                    Connected.Invoke();

            }

        }

        public void OnServiceDisconnected(ComponentName name) { this._binder.IsBound = false; }

    }

}

 

فایل GPSService.cs شامل کلاس های زیر است:

·         GPSService

·         GPSServiceBinder

·         GPSServiceConnection

GPSService یک کلاس است که Service و ILocationService را پیاده سازی می کند. این قسمت مربوط به زمانی است که موقعیت دستگاه تغییر می کند و باید یکسری کارها براساس نتیجه انجام شود. رویداد OnLocationChanged براساس تنضیماتی که در زمان ثبت موقعیت وارد کرده اید، عمل می کند و متد StartLocationUpdates() کنترل آن را برعهده دارد.

در رویداد OnLocationChanged، منطق دریافت آدرس، موقعیت و سایر ملاحظات قرار می گیرد. علاوه بر این از متد SendBroadcast() جهت ارسال بخشی از داده ها با بکارگیری Intent، استفاده شده است. سپس مقادیر ارسال شده بوسیله BroadcastReciever بازیابی می شوند. اندروید هنگام برقراری ارتباط با یک سرویس، بسته به محل اجرای سرویس، سه گزینه فراهم میکند. برای مثال من از سرویس Service Binding استفاده کرده ام. به این دلیل که سرویس مورد نظر ما (GPSService) بخشی از برنامه ما است. به این ترتیب client با اتصال (binding) به آن می تواند مستقیماً با آن ارتباط برقرار کند. سرویس که به Client متصل شود، متدهای چرخه حیات Bound Service را Override (لغو) می کند و با استفاده از یک Binder (GPSServiceBinder) و یک ServiceConnection (GPSServiceConnection)  با Client ارتباط برقرار می کند.

اتصال UI

بروزرسانی Main.axml در پوشه Resources > Layout به شکل زیر:

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:orientation="vertical" 

    android:layout_width="fill_parent" 

    android:layout_height="fill_parent"> 

    <TextView 

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content" 

        android:id="@+id/txtLocation" 

        android:width="200dp" 

        android:layout_marginRight="0dp" 

        android:layout_gravity="right" 

        android:gravity="left" 

        android:layout_alignParentRight="true" /> 

    <TextView 

        android:text="Location :" 

        android:layout_width="60.2dp" 

        android:layout_height="wrap_content" 

        android:id="@+id/textView1" 

        android:layout_toLeftOf="@id/txtLocation" 

        android:layout_alignTop="@id/txtLocation" 

        android:width="100dp" 

        android:layout_marginTop="0dp" 

        android:layout_alignParentLeft="true" /> 

    <TextView 

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content" 

        android:layout_below="@id/txtLocation" 

        android:id="@+id/txtAddress" 

        android:width="200dp" 

        android:layout_alignParentRight="true" /> 

    <TextView 

        android:text="Address :" 

        android:layout_width="60.2dp" 

        android:layout_height="wrap_content" 

        android:id="@+id/textView2" 

        android:layout_toLeftOf="@id/txtAddress" 

        android:layout_below="@id/txtLocation" 

        android:width="100dp" 

        android:layout_marginTop="0dp" 

        android:layout_alignParentLeft="true" /> 

    <TextView 

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content" 

        android:layout_below="@id/txtAddress" 

        android:id="@+id/txtRemarks" 

        android:width="200dp" 

        android:layout_alignParentRight="true" /> 

    <TextView 

        android:text="Remarks :" 

        android:layout_width="60.2dp" 

        android:layout_height="wrap_content" 

        android:id="@+id/textView3" 

        android:layout_toLeftOf="@id/txtRemarks" 

        android:layout_below="@id/txtAddress" 

        android:width="100dp" 

        android:layout_marginTop="0dp" 

        android:layout_alignParentLeft="true" /> 

</RelativeLayout>

 

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

Main Activity

حالا باید با اضافه کردن قطعه کد زیر فایل MainActivity.cs را بروزرسانی کنیم:

using Android.App;

using Android.Content;

using Android.Widget;

using Android.OS;

 

namespace MyFirstGPSApp

{

    [Activity(Label = "MyFirstGPSApp", MainLauncher = true, Icon = "@drawable/icon")]

    public class MainActivity : Activity

    {

        TextView _locationText;

        TextView _addressText;

        TextView _remarksText;

 

        GPSServiceBinder _binder;

        GPSServiceConnection _gpsServiceConnection;

        Intent _gpsServiceIntent;

        private GPSServiceReciever _receiver;

 

        public static MainActivity Instance;

        protected override void OnCreate(Bundle bundle)

        {

            base.OnCreate(bundle);

 

            Instance = this;

            SetContentView(Resource.Layout.Main);

 

            _addressText = FindViewById<TextView>(Resource.Id.txtAddress);

            _locationText = FindViewById<TextView>(Resource.Id.txtLocation);

            _remarksText = FindViewById<TextView>(Resource.Id.txtRemarks);

 

            RegisterService();

        }

 

        private void RegisterService()

        {

            _gpsServiceConnection = new GPSServiceConnection(_binder);

            _gpsServiceIntent = new Intent(Android.App.Application.Context, typeof(GPSService));

            BindService(_gpsServiceIntent, _gpsServiceConnection, Bind.AutoCreate);

        }

        private void RegisterBroadcastReceiver()

        {

            IntentFilter filter = new IntentFilter(GPSServiceReciever.LOCATION_UPDATED);

            filter.AddCategory(Intent.CategoryDefault);

            _receiver = new GPSServiceReciever();

            RegisterReceiver(_receiver, filter);

        }

 

        private void UnRegisterBroadcastReceiver()

        {

            UnregisterReceiver(_receiver);

        }

        public void UpdateUI(Intent intent)

        {

            _locationText.Text = intent.GetStringExtra("Location");

            _addressText.Text = intent.GetStringExtra("Address");

            _remarksText.Text = intent.GetStringExtra("Remarks");

        }

 

        protected override void OnResume()

        {

            base.OnResume();

            RegisterBroadcastReceiver();

        }

 

        protected override void OnPause()

        {

            base.OnPause();

            UnRegisterBroadcastReceiver();

        }

 

        [BroadcastReceiver]

        internal class GPSServiceReciever : BroadcastReceiver

        {

            public static readonly string LOCATION_UPDATED = "LOCATION_UPDATED";

            public override void OnReceive(Context context, Intent intent)

            {

                if (intent.Action.Equals(LOCATION_UPDATED))

                {

                    MainActivity.Instance.UpdateUI(intent);

                }

 

            }

        }

    }

}

 

در رویداد Oncreate، ContentViews و TextViews مقداردهی اولیه می شود. در این قسمت  سرویس مورد نیاز برنامه ما ثبت می شود. RegisterService() سرویس مورد نیاز را ثبت و متصل (bind) می کند. متد RegisterBroadcastReciever() گیرنده های broadcast  (broadcast receiver) را ثبت می کنند. به این ترتیب می توانیم به داده ها از طریق broadcast دسترسی داشته باشیم. این متد در رویداد OnResume، override می شود. متد UnRegisterBroadcastReceiver() ثبت گیرنده های Broadcast را لغو می کنند. این متد نیز در رویداد OnPause در Activity فراخوانی می شود.

با پیاده سازی BroadcastReciever  در کلاس GPSServiceReciever، پیغام های broadcast کنترل می شوند. اگر به خاطر داشته باشید، در رویداد GPSService OnLocationChanged برای ارسال مقادیر به Broadcast از یک intent استفاده کردیم. این مقادیر در UI سمت client نمایش داده می شوند.

جمع بندی

در تصویر زیر نمایی از پروژه را مشاهده می کنید:

آموزش Xamarin

قبل از تست برنامه مطمئن شوید مجوزهای زیر در فایل AndroidManifest.xml دسترسی دارید:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 

<uses-permission android:name="android.permission.INTERNET" /> 

 

اجرای برنامه

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

آموزش Xamarin

 

 

1394/10/07 2695 1379
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...