نمای کلی سنسورها

اکثر دستگاه‌های اندروید دارای حسگرهای داخلی هستند که حرکت، جهت‌گیری و شرایط مختلف محیطی را اندازه‌گیری می‌کنند. این حسگرها قادر به ارائه داده‌های خام با دقت و صحت بالا هستند و در صورتی که بخواهید حرکت یا موقعیت‌یابی سه‌بعدی دستگاه را رصد کنید، یا می‌خواهید تغییرات محیط اطراف دستگاه را رصد کنید، مفید هستند. به عنوان مثال، یک بازی ممکن است داده‌های حسگر جاذبه دستگاه را ردیابی کند تا حرکات و اشارات پیچیده کاربر مانند شیب، لرزش، چرخش یا تاب خوردن را استنباط کند. به همین ترتیب، یک برنامه آب و هوا ممکن است از حسگر دما و حسگر رطوبت دستگاه برای محاسبه و گزارش نقطه شبنم استفاده کند، یا یک برنامه سفر ممکن است از حسگر میدان ژئومغناطیسی و شتاب‌سنج برای گزارش جهت قطب‌نما استفاده کند.

پلتفرم اندروید از سه دسته حسگر گسترده پشتیبانی می‌کند:

  • حسگرهای حرکتی

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

  • حسگرهای محیطی

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

  • حسگرهای موقعیت

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

شما می‌توانید با استفاده از چارچوب حسگر اندروید به حسگرهای موجود در دستگاه دسترسی پیدا کنید و داده‌های خام حسگر را دریافت کنید. چارچوب حسگر چندین کلاس و رابط کاربری ارائه می‌دهد که به شما در انجام طیف گسترده‌ای از وظایف مرتبط با حسگر کمک می‌کند. به عنوان مثال، می‌توانید از چارچوب حسگر برای انجام موارد زیر استفاده کنید:

  • مشخص کنید کدام حسگرها روی دستگاه موجود هستند.
  • قابلیت‌های یک حسگر خاص، مانند حداکثر برد، سازنده، توان مورد نیاز و وضوح تصویر آن را تعیین کنید.
  • داده‌های خام حسگر را دریافت کنید و حداقل نرخ دریافت داده‌های حسگر را تعریف کنید.
  • ثبت و لغو ثبت شنونده‌های رویداد حسگر که تغییرات حسگر را رصد می‌کنند.

این مبحث مروری بر حسگرهای موجود در پلتفرم اندروید و همچنین مقدمه‌ای بر چارچوب حسگرها ارائه می‌دهد.

مقدمه‌ای بر حسگرها

چارچوب حسگر اندروید به شما امکان دسترسی به انواع مختلفی از حسگرها را می‌دهد. برخی از این حسگرها مبتنی بر سخت‌افزار و برخی مبتنی بر نرم‌افزار هستند. حسگرهای مبتنی بر سخت‌افزار، اجزای فیزیکی هستند که در یک گوشی یا تبلت تعبیه شده‌اند. آن‌ها داده‌های خود را با اندازه‌گیری مستقیم ویژگی‌های خاص محیطی، مانند شتاب، قدرت میدان ژئومغناطیسی یا تغییر زاویه‌ای، به دست می‌آورند. حسگرهای مبتنی بر نرم‌افزار، دستگاه‌های فیزیکی نیستند، اگرچه از حسگرهای مبتنی بر سخت‌افزار تقلید می‌کنند. حسگرهای مبتنی بر نرم‌افزار، داده‌های خود را از یک یا چند حسگر مبتنی بر سخت‌افزار به دست می‌آورند و گاهی اوقات حسگرهای مجازی یا حسگرهای مصنوعی نامیده می‌شوند. حسگر شتاب خطی و حسگر گرانش نمونه‌هایی از حسگرهای مبتنی بر نرم‌افزار هستند. جدول 1 حسگرهایی را که توسط پلتفرم اندروید پشتیبانی می‌شوند، خلاصه می‌کند.

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

جدول 1. انواع حسگرهای پشتیبانی شده توسط پلتفرم اندروید.

سنسور نوع توضیحات کاربردهای رایج
TYPE_ACCELEROMETER سخت‌افزار نیروی شتاب وارد بر دستگاه را بر حسب متر بر ثانیه (m/s² ) در هر سه محور فیزیکی (x، y و z)، از جمله نیروی گرانش، اندازه‌گیری می‌کند. تشخیص حرکت (لرزش، کج شدن و غیره).
TYPE_AMBIENT_TEMPERATURE سخت‌افزار دمای محیط اتاق را بر حسب درجه سانتیگراد (°C) اندازه‌گیری می‌کند. به یادداشت زیر مراجعه کنید. نظارت بر دمای هوا.
TYPE_GRAVITY نرم‌افزار یا سخت‌افزار نیروی گرانش را بر حسب متر بر ثانیه مربع که به دستگاهی در هر سه محور فیزیکی (x، y، z) وارد می‌شود، اندازه‌گیری می‌کند. تشخیص حرکت (لرزش، کج شدن و غیره).
TYPE_GYROSCOPE سخت‌افزار سرعت چرخش دستگاه را بر حسب رادیان بر ثانیه حول هر یک از سه محور فیزیکی (x، y و z) اندازه‌گیری می‌کند. تشخیص چرخش (چرخش، چرخش و غیره).
TYPE_LIGHT سخت‌افزار میزان نور محیط (روشنایی) را بر حسب لوکس (lx) اندازه‌گیری می‌کند. کنترل روشنایی صفحه نمایش.
TYPE_LINEAR_ACCELERATION نرم‌افزار یا سخت‌افزار نیروی شتاب وارد بر دستگاه را بر حسب متر بر ثانیه (m/s²) در هر سه محور فیزیکی (x، y و z)، به استثنای نیروی جاذبه، اندازه‌گیری می‌کند. نظارت بر شتاب در امتداد یک محور واحد.
TYPE_MAGNETIC_FIELD سخت‌افزار میدان ژئومغناطیسی محیط را برای هر سه محور فیزیکی (x، y، z) بر حسب میکروتسلا اندازه‌گیری می‌کند. ساخت قطب نما.
TYPE_ORIENTATION نرم‌افزار درجه چرخش یک دستگاه را حول هر سه محور فیزیکی (x، y، z) اندازه‌گیری می‌کند. از سطح API 3، می‌توانید ماتریس شیب و ماتریس چرخش یک دستگاه را با استفاده از حسگر گرانش و حسگر میدان ژئومغناطیسی به همراه متد getRotationMatrix() به دست آورید. تعیین موقعیت دستگاه
TYPE_PRESSURE سخت‌افزار فشار هوای محیط را بر حسب هکتوپاسکال یا میلی بار اندازه گیری می کند. نظارت بر تغییرات فشار هوا.
TYPE_PROXIMITY سخت‌افزار نزدیکی یک جسم را نسبت به صفحه نمایش دستگاه بر حسب سانتی‌متر اندازه‌گیری می‌کند. این حسگر معمولاً برای تعیین اینکه آیا گوشی تلفن همراه در نزدیکی گوش فرد قرار گرفته است یا خیر، استفاده می‌شود. موقعیت تلفن در حین تماس.
TYPE_RELATIVE_HUMIDITY سخت‌افزار رطوبت نسبی محیط را بر حسب درصد (%) اندازه‌گیری می‌کند. پایش نقطه شبنم، رطوبت مطلق و نسبی
TYPE_ROTATION_VECTOR نرم‌افزار یا سخت‌افزار جهت‌گیری یک دستگاه را با ارائه سه عنصر بردار چرخش دستگاه اندازه‌گیری می‌کند. تشخیص حرکت و تشخیص چرخش
TYPE_TEMPERATURE سخت‌افزار دمای دستگاه را بر حسب درجه سانتیگراد (°C) اندازه‌گیری می‌کند. پیاده‌سازی این حسگر در دستگاه‌های مختلف متفاوت است و این حسگر در API سطح ۱۴ با حسگر TYPE_AMBIENT_TEMPERATURE جایگزین شده است. نظارت بر دماها.

چارچوب حسگر

شما می‌توانید با استفاده از چارچوب حسگر اندروید به این حسگرها دسترسی پیدا کنید و داده‌های خام حسگر را دریافت کنید. چارچوب حسگر بخشی از بسته android.hardware است و شامل کلاس‌ها و رابط‌های زیر است:

SensorManager
شما می‌توانید از این کلاس برای ایجاد یک نمونه از سرویس حسگر استفاده کنید. این کلاس روش‌های مختلفی برای دسترسی و فهرست کردن حسگرها، ثبت و لغو ثبت شنونده‌های رویداد حسگر و کسب اطلاعات جهت‌گیری ارائه می‌دهد. این کلاس همچنین چندین ثابت حسگر را ارائه می‌دهد که برای گزارش دقت حسگر، تنظیم نرخ جمع‌آوری داده‌ها و کالیبراسیون حسگرها استفاده می‌شوند.
Sensor
شما می‌توانید از این کلاس برای ایجاد یک نمونه از یک حسگر خاص استفاده کنید. این کلاس متدهای مختلفی را ارائه می‌دهد که به شما امکان می‌دهد قابلیت‌های یک حسگر را تعیین کنید.
SensorEvent
سیستم از این کلاس برای ایجاد یک شیء رویداد حسگر استفاده می‌کند که اطلاعاتی در مورد یک رویداد حسگر ارائه می‌دهد. یک شیء رویداد حسگر شامل اطلاعات زیر است: داده‌های خام حسگر، نوع حسگری که رویداد را ایجاد کرده است، دقت داده‌ها و مهر زمانی رویداد.
SensorEventListener
شما می‌توانید از این رابط برای ایجاد دو متد فراخوانی استفاده کنید که هنگام تغییر مقادیر حسگر یا تغییر دقت حسگر، اعلان‌هایی (رویدادهای حسگر) دریافت می‌کنند.

در یک برنامه معمولی، شما از این APIهای مرتبط با حسگر برای انجام دو کار اساسی استفاده می‌کنید:

  • شناسایی حسگرها و قابلیت‌های حسگر

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

  • نظارت بر رویدادهای حسگر

    نظارت بر رویدادهای حسگر، نحوه‌ی کسب داده‌های خام حسگر است. هر بار که حسگر تغییری را در پارامترهایی که اندازه‌گیری می‌کند تشخیص می‌دهد، یک رویداد حسگر رخ می‌دهد. یک رویداد حسگر چهار نوع اطلاعات در اختیار شما قرار می‌دهد: نام حسگری که رویداد را فعال کرده، زمان ثبت رویداد، دقت رویداد و داده‌های خام حسگر که رویداد را فعال کرده است.

در دسترس بودن سنسور

اگرچه دسترسی به حسگرها از دستگاهی به دستگاه دیگر متفاوت است، اما می‌تواند بین نسخه‌های مختلف اندروید نیز متفاوت باشد. دلیل این امر آن است که حسگرهای اندروید در طول انتشار چندین پلتفرم معرفی شده‌اند. به عنوان مثال، بسیاری از حسگرها در اندروید ۱.۵ (API Level 3) معرفی شدند، اما برخی از آنها پیاده‌سازی نشدند و تا اندروید ۲.۳ (API Level 9) برای استفاده در دسترس نبودند. به همین ترتیب، چندین حسگر در اندروید ۲.۳ (API Level 9) و اندروید ۴.۰ (API Level 14) معرفی شدند. دو حسگر منسوخ شده و با حسگرهای جدیدتر و بهتر جایگزین شده‌اند.

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

جدول 2. در دسترس بودن حسگرها بر اساس پلتفرم.

سنسور اندروید ۴.۰
(سطح API 14)
اندروید ۲.۳
(سطح API 9)
اندروید ۲.۲
(سطح API 8)
اندروید ۱.۵
(API سطح ۳)
TYPE_ACCELEROMETER بله بله بله بله
TYPE_AMBIENT_TEMPERATURE بله ناموجود ناموجود ناموجود
TYPE_GRAVITY بله بله ناموجود ناموجود
TYPE_GYROSCOPE بله بله ناموجود ۱ ناموجود ۱
TYPE_LIGHT بله بله بله بله
TYPE_LINEAR_ACCELERATION بله بله ناموجود ناموجود
TYPE_MAGNETIC_FIELD بله بله بله بله
TYPE_ORIENTATION بله ۲ بله ۲ بله ۲ بله
TYPE_PRESSURE بله بله ناموجود ۱ ناموجود ۱
TYPE_PROXIMITY بله بله بله بله
TYPE_RELATIVE_HUMIDITY بله ناموجود ناموجود ناموجود
TYPE_ROTATION_VECTOR بله بله ناموجود ناموجود
TYPE_TEMPERATURE بله ۲ بله بله بله

این نوع حسگر در اندروید ۱.۵ (API سطح ۳) اضافه شد، اما تا اندروید ۲.۳ (API سطح ۹) قابل استفاده نبود.

۲ این حسگر موجود است، اما دیگر استفاده نمی‌شود.

شناسایی حسگرها و قابلیت‌های حسگر

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

برای شناسایی سنسورهایی که روی یک دستگاه هستند، ابتدا باید به سرویس سنسور مراجعه کنید. برای انجام این کار، با فراخوانی متد getSystemService() و ارسال آرگومان SENSOR_SERVICE یک نمونه از کلاس SensorManager ایجاد می‌کنید. به عنوان مثال:

کاتلین

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

جاوا

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

در مرحله بعد، می‌توانید با فراخوانی متد getSensorList() و استفاده از ثابت TYPE_ALL ، فهرستی از تمام حسگرهای موجود در یک دستگاه را دریافت کنید. برای مثال:

کاتلین

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

جاوا

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

اگر می‌خواهید تمام حسگرهای یک نوع مشخص را فهرست کنید، می‌توانید به جای TYPE_ALL از ثابت دیگری مانند TYPE_GYROSCOPE ، TYPE_LINEAR_ACCELERATION یا TYPE_GRAVITY استفاده کنید.

همچنین می‌توانید با استفاده از متد getDefaultSensor() و ارسال ثابت نوع برای یک سنسور خاص، وجود نوع خاصی از سنسور را در دستگاه تعیین کنید. اگر دستگاهی بیش از یک سنسور از نوع مشخص داشته باشد، یکی از سنسورها باید به عنوان سنسور پیش‌فرض تعیین شود. اگر سنسور پیش‌فرض برای نوع مشخصی از سنسور وجود نداشته باشد، فراخوانی متد مقدار null را برمی‌گرداند، به این معنی که دستگاه آن نوع سنسور را ندارد. به عنوان مثال، کد زیر بررسی می‌کند که آیا یک مغناطیس‌سنج در دستگاه وجود دارد یا خیر:

کاتلین

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

جاوا

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

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

علاوه بر فهرست کردن سنسورهای موجود در یک دستگاه، می‌توانید از متدهای عمومی کلاس Sensor برای تعیین قابلیت‌ها و ویژگی‌های هر سنسور به صورت جداگانه استفاده کنید. این قابلیت زمانی مفید است که بخواهید برنامه شما بر اساس اینکه کدام سنسورها یا قابلیت‌های سنسور روی یک دستگاه موجود است، رفتار متفاوتی داشته باشد. به عنوان مثال، می‌توانید از متدهای getResolution() و getMaximumRange() برای به دست آوردن وضوح و حداکثر محدوده اندازه‌گیری یک سنسور استفاده کنید. همچنین می‌توانید از متد getPower() برای به دست آوردن نیازهای توان یک سنسور استفاده کنید.

دو مورد از متدهای عمومی به ویژه در صورتی مفید هستند که بخواهید برنامه خود را برای سنسورهای سازندگان مختلف یا نسخه‌های مختلف یک سنسور بهینه کنید. به عنوان مثال، اگر برنامه شما نیاز به نظارت بر حرکات کاربر مانند شیب و لرزش دارد، می‌توانید یک مجموعه از قوانین فیلترینگ داده و بهینه‌سازی‌ها را برای دستگاه‌های جدیدتری که دارای سنسور گرانش یک فروشنده خاص هستند، و مجموعه دیگری از قوانین فیلترینگ داده و بهینه‌سازی‌ها را برای دستگاه‌هایی که سنسور گرانش ندارند و فقط شتاب‌سنج دارند، ایجاد کنید. نمونه کد زیر به شما نشان می‌دهد که چگونه می‌توانید از متدهای getVendor() و getVersion() برای انجام این کار استفاده کنید. در این نمونه، ما به دنبال یک سنسور گرانش هستیم که Google LLC را به عنوان فروشنده فهرست می‌کند و شماره نسخه آن ۳ است. اگر آن سنسور خاص در دستگاه وجود نداشته باشد، سعی می‌کنیم از شتاب‌سنج استفاده کنیم.

کاتلین

private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

جاوا

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

روش مفید دیگر، روش getMinDelay() است که حداقل فاصله زمانی (برحسب میکروثانیه) را که یک حسگر می‌تواند برای حس کردن داده‌ها استفاده کند، برمی‌گرداند. هر حسگری که مقدار غیر صفر را برای روش getMinDelay() برگرداند، یک حسگر جریانی است. حسگرهای جریانی داده‌ها را در فواصل منظم حس می‌کنند و در اندروید ۲.۳ (API سطح ۹) معرفی شدند. اگر یک حسگر هنگام فراخوانی روش getMinDelay() صفر را برگرداند، به این معنی است که حسگر یک حسگر جریانی نیست، زیرا فقط زمانی داده‌ها را گزارش می‌دهد که تغییری در پارامترهایی که حس می‌کند، ایجاد شود.

متد getMinDelay() مفید است زیرا به شما امکان می‌دهد حداکثر نرخی را که یک حسگر می‌تواند داده‌ها را دریافت کند، تعیین کنید. اگر ویژگی‌های خاصی در برنامه شما به نرخ‌های بالای دریافت داده‌ها یا یک حسگر جریانی نیاز دارند، می‌توانید از این متد برای تعیین اینکه آیا یک حسگر آن الزامات را برآورده می‌کند یا خیر، استفاده کنید و سپس ویژگی‌های مربوطه را در برنامه خود بر این اساس فعال یا غیرفعال کنید.

احتیاط: حداکثر نرخ جمع‌آوری داده یک حسگر لزوماً نرخی نیست که چارچوب حسگر با آن، داده‌های حسگر را به برنامه شما تحویل می‌دهد. چارچوب حسگر، داده‌ها را از طریق رویدادهای حسگر گزارش می‌دهد و عوامل متعددی بر نرخی که برنامه شما رویدادهای حسگر را دریافت می‌کند، تأثیر می‌گذارند. برای اطلاعات بیشتر، به بخش «نظارت بر رویدادهای حسگر» مراجعه کنید.

نظارت بر رویدادهای حسگر

برای نظارت بر داده‌های خام حسگر، باید دو متد فراخوانی (callback) پیاده‌سازی کنید که از طریق رابط SensorEventListener در دسترس قرار می‌گیرند: onAccuracyChanged() و onSensorChanged() . سیستم اندروید هر زمان که موارد زیر رخ دهد، این متدها را فراخوانی می‌کند:

  • دقت یک حسگر تغییر می‌کند.

    در این حالت، سیستم متد onAccuracyChanged() را فراخوانی می‌کند و مرجعی به شیء Sensor که تغییر کرده و دقت جدید حسگر در اختیار شما قرار می‌دهد. دقت با یکی از چهار ثابت وضعیت نمایش داده می‌شود: SENSOR_STATUS_ACCURACY_LOW ، SENSOR_STATUS_ACCURACY_MEDIUM ، SENSOR_STATUS_ACCURACY_HIGH یا SENSOR_STATUS_UNRELIABLE .

  • یک حسگر مقدار جدیدی را گزارش می‌دهد.

    در این حالت، سیستم متد onSensorChanged() را فراخوانی می‌کند و یک شیء SensorEvent را در اختیار شما قرار می‌دهد. یک شیء SensorEvent حاوی اطلاعاتی در مورد داده‌های جدید حسگر است، از جمله: دقت داده‌ها، حسگری که داده‌ها را تولید کرده است، برچسب زمانی که داده‌ها در آن تولید شده‌اند و داده‌های جدیدی که حسگر ثبت کرده است.

کد زیر نحوه استفاده از متد onSensorChanged() را برای نظارت بر داده‌های حسگر نور نشان می‌دهد. این مثال داده‌های خام حسگر را در یک TextView که در فایل main.xml با نام sensor_data تعریف شده است، نمایش می‌دهد.

کاتلین

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

جاوا

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor mLight;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

در این مثال، تأخیر پیش‌فرض داده ( SENSOR_DELAY_NORMAL ) هنگام فراخوانی متد registerListener() مشخص می‌شود. تأخیر داده (یا نرخ نمونه‌برداری) فاصله زمانی ارسال رویدادهای حسگر به برنامه شما را از طریق متد فراخوانی onSensorChanged() کنترل می‌کند. تأخیر داده پیش‌فرض برای نظارت بر تغییرات معمول جهت‌گیری صفحه نمایش مناسب است و از تأخیر ۲۰۰۰۰۰ میکروثانیه استفاده می‌کند. می‌توانید تأخیرهای داده دیگری مانند SENSOR_DELAY_GAME (تأخیر ۲۰۰۰۰ میکروثانیه)، SENSOR_DELAY_UI (تأخیر ۶۰۰۰۰ میکروثانیه) یا SENSOR_DELAY_FASTEST (تأخیر ۰ میکروثانیه) را مشخص کنید. از اندروید ۳.۰ (API سطح ۱۱) می‌توانید تأخیر را به عنوان یک مقدار مطلق (برحسب میکروثانیه) نیز مشخص کنید.

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

هیچ روش عمومی برای تعیین نرخ ارسال رویدادهای حسگر توسط چارچوب حسگر به برنامه شما وجود ندارد. با این حال، می‌توانید از مهرهای زمانی مرتبط با هر رویداد حسگر برای محاسبه نرخ نمونه‌برداری در چندین رویداد استفاده کنید. پس از تنظیم نرخ نمونه‌برداری (تأخیر) نباید آن را تغییر دهید. اگر به هر دلیلی نیاز به تغییر تأخیر دارید، باید شنونده حسگر را لغو ثبت و دوباره ثبت کنید.

همچنین لازم به ذکر است که این مثال از متدهای فراخوانی onResume() و onPause() برای ثبت و لغو ثبت شنونده رویداد حسگر استفاده می‌کند. به عنوان یک اقدام بهینه، همیشه باید حسگرهایی را که نیازی به آنها ندارید، به خصوص هنگامی که فعالیت شما متوقف شده است، غیرفعال کنید. عدم انجام این کار می‌تواند باتری را تنها در عرض چند ساعت تخلیه کند زیرا برخی از حسگرها به برق قابل توجهی نیاز دارند و می‌توانند به سرعت از انرژی باتری استفاده کنند. سیستم هنگام خاموش شدن صفحه نمایش، حسگرها را به طور خودکار غیرفعال نمی‌کند.

مدیریت پیکربندی‌های مختلف حسگر

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

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

  • حسگرها را در زمان اجرا تشخیص داده و ویژگی‌های برنامه را در صورت لزوم فعال یا غیرفعال کنید.
  • از فیلترهای گوگل پلی برای هدف قرار دادن دستگاه‌هایی با پیکربندی‌های حسگر خاص استفاده کنید.

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

تشخیص حسگرها در زمان اجرا

اگر برنامه شما از نوع خاصی از حسگر استفاده می‌کند، اما به آن وابسته نیست، می‌توانید از چارچوب حسگر برای تشخیص حسگر در زمان اجرا استفاده کنید و سپس ویژگی‌های برنامه را به طور مناسب غیرفعال یا فعال کنید. به عنوان مثال، یک برنامه ناوبری ممکن است از حسگر دما، حسگر فشار، حسگر GPS و حسگر میدان ژئومغناطیسی برای نمایش دما، فشار بارومتریک، مکان و جهت قطب‌نما استفاده کند. اگر دستگاهی حسگر فشار ندارد، می‌توانید از چارچوب حسگر برای تشخیص عدم وجود حسگر فشار در زمان اجرا استفاده کنید و سپس بخشی از رابط کاربری برنامه خود را که فشار را نمایش می‌دهد غیرفعال کنید. به عنوان مثال، کد زیر بررسی می‌کند که آیا حسگر فشار روی دستگاه وجود دارد یا خیر:

کاتلین

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

جاوا

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

استفاده از فیلترهای گوگل پلی برای هدف قرار دادن پیکربندی‌های خاص حسگر

اگر برنامه خود را در گوگل پلی منتشر می‌کنید، می‌توانید از عنصر <uses-feature> در فایل مانیفست خود برای فیلتر کردن برنامه خود از دستگاه‌هایی که پیکربندی حسگر مناسبی برای برنامه شما ندارند، استفاده کنید. عنصر <uses-feature> دارای چندین توصیف‌گر سخت‌افزاری است که به شما امکان می‌دهد برنامه‌ها را بر اساس وجود حسگرهای خاص فیلتر کنید. حسگرهایی که می‌توانید فهرست کنید عبارتند از: شتاب‌سنج، فشارسنج، قطب‌نما (میدان ژئومغناطیسی)، ژیروسکوپ، نور و مجاورت. در زیر نمونه‌ای از ورودی مانیفست آمده است که برنامه‌هایی را که شتاب‌سنج ندارند فیلتر می‌کند:

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

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

شما باید توصیفگر را فقط در صورتی روی android:required="true" تنظیم کنید که برنامه شما کاملاً به یک حسگر خاص متکی باشد. اگر برنامه شما برای برخی از عملکردها از یک حسگر استفاده می‌کند، اما همچنان بدون حسگر اجرا می‌شود، باید حسگر را در عنصر <uses-feature> فهرست کنید، اما توصیفگر را روی android:required="false" تنظیم کنید. این کار به شما کمک می‌کند تا مطمئن شوید که دستگاه‌ها می‌توانند برنامه شما را نصب کنند، حتی اگر آن حسگر خاص را نداشته باشند. این همچنین یک روش عالی مدیریت پروژه است که به شما کمک می‌کند ویژگی‌هایی را که برنامه شما استفاده می‌کند، پیگیری کنید. به خاطر داشته باشید، اگر برنامه شما از یک حسگر خاص استفاده می‌کند، اما همچنان بدون حسگر اجرا می‌شود، باید حسگر را در زمان اجرا شناسایی کرده و ویژگی‌های برنامه را در صورت لزوم غیرفعال یا فعال کنید.

سیستم مختصات حسگر

به طور کلی، چارچوب حسگر از یک سیستم مختصات استاندارد ۳ محوره برای بیان مقادیر داده‌ها استفاده می‌کند. برای اکثر حسگرها، سیستم مختصات نسبت به صفحه نمایش دستگاه تعریف می‌شود، زمانی که دستگاه در جهت پیش‌فرض خود نگه داشته می‌شود (شکل ۱ را ببینید). وقتی دستگاه در جهت پیش‌فرض خود نگه داشته می‌شود، محور X افقی است و به سمت راست اشاره می‌کند، محور Y عمودی است و به سمت بالا اشاره می‌کند و محور Z به سمت خارج از صفحه نمایش اشاره می‌کند. در این سیستم، مختصات پشت صفحه نمایش دارای مقادیر Z منفی هستند. این سیستم مختصات توسط حسگرهای زیر استفاده می‌شود:

شکل ۱. سیستم مختصات (نسبت به یک دستگاه) که توسط Sensor API استفاده می‌شود.

مهمترین نکته‌ای که باید در مورد این سیستم مختصات بدانید این است که محورها هنگام تغییر جهت صفحه نمایش دستگاه، جابجا نمی‌شوند - یعنی سیستم مختصات حسگر هرگز با حرکت دستگاه تغییر نمی‌کند. این رفتار مشابه رفتار سیستم مختصات OpenGL است.

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

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

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

محدودکننده سرعت حسگر

برای محافظت از اطلاعات بالقوه حساس در مورد کاربران، اگر برنامه شما اندروید ۱۲ (سطح API 31) یا بالاتر را هدف قرار می‌دهد، سیستم محدودیتی بر نرخ به‌روزرسانی داده‌های دریافتی از حسگرهای حرکتی و حسگرهای موقعیت خاص اعمال می‌کند. این داده‌ها شامل مقادیر ثبت‌شده توسط شتاب‌سنج ، ژیروسکوپ و حسگر میدان ژئومغناطیسی دستگاه است.

محدودیت نرخ تازه‌سازی به نحوه دسترسی شما به داده‌های حسگر بستگی دارد:

  • اگر متد registerListener() را برای نظارت بر رویدادهای حسگر فراخوانی کنید، نرخ نمونه‌برداری حسگر به ۲۰۰ هرتز محدود می‌شود. این موضوع در مورد تمام انواع سربارگذاری‌شده‌ی متد registerListener() صادق است.
  • اگر از کلاس SensorDirectChannel استفاده کنید، نرخ نمونه‌برداری حسگر به RATE_NORMAL محدود می‌شود که معمولاً حدود ۵۰ هرتز است.

اگر برنامه شما نیاز به جمع‌آوری داده‌های حسگر حرکت با سرعت بالاتر دارد، باید مجوز HIGH_SAMPLING_RATE_SENSORS را همانطور که در قطعه کد زیر نشان داده شده است، اعلام کنید. در غیر این صورت، اگر برنامه شما سعی کند داده‌های حسگر حرکت را با سرعت بالاتر و بدون اعلام این مجوز جمع‌آوری کند، یک SecurityException رخ می‌دهد.

فایل AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

بهترین شیوه‌ها برای دسترسی و استفاده از حسگرها

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

فقط داده‌های حسگر را در پیش‌زمینه جمع‌آوری کنید

در دستگاه‌هایی که اندروید ۹ (سطح API 28) یا بالاتر دارند، برنامه‌هایی که در پس‌زمینه اجرا می‌شوند محدودیت‌های زیر را دارند:

  • حسگرهایی که از حالت گزارش‌دهی پیوسته استفاده می‌کنند، مانند شتاب‌سنج‌ها و ژیروسکوپ‌ها، رویدادها را دریافت نمی‌کنند.
  • حسگرهایی که از حالت‌های گزارش‌دهی در لحظه یا یک‌باره استفاده می‌کنند، رویدادها را دریافت نمی‌کنند.

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

لغو ثبت نام شنوندگان حسگر

حتماً وقتی کارتان با حسگر تمام شد یا وقتی فعالیت حسگر متوقف شد، شنونده حسگر را از حالت ثبت خارج کنید. اگر یک شنونده حسگر ثبت شده باشد و فعالیت آن متوقف شود، حسگر به جمع‌آوری داده‌ها و استفاده از منابع باتری ادامه می‌دهد، مگر اینکه حسگر را از حالت ثبت خارج کنید. کد زیر نحوه استفاده از متد onPause() برای لغو ثبت یک شنونده نشان می‌دهد:

کاتلین

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}

جاوا

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

برای اطلاعات بیشتر، به unregisterListener(SensorEventListener) مراجعه کنید.

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

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

این شبیه‌ساز از اتصال به دستگاه اندرویدی که برنامه SdkControllerSensor را اجرا می‌کند، استفاده می‌کند. توجه داشته باشید که این برنامه فقط در دستگاه‌هایی که اندروید ۴.۰ (سطح API ۱۴) یا بالاتر دارند، در دسترس است. (اگر دستگاه اندروید ۴.۰ را اجرا می‌کند، باید Revision 2 را نصب کرده باشد.) برنامه SdkControllerSensor تغییرات حسگرهای دستگاه را رصد می‌کند و آنها را به شبیه‌ساز منتقل می‌کند. سپس شبیه‌ساز بر اساس مقادیر جدیدی که از حسگرهای دستگاه شما دریافت می‌کند، تغییر شکل می‌دهد.

می‌توانید کد منبع برنامه‌ی SdkControllerSensor را در آدرس زیر مشاهده کنید:

$ your-android-sdk-directory/tools/apps/SdkController

برای انتقال اطلاعات بین دستگاه و شبیه‌ساز، مراحل زیر را دنبال کنید:

  1. بررسی کنید که اشکال‌زدایی USB روی دستگاه شما فعال باشد .
  2. دستگاه خود را با استفاده از کابل USB به دستگاه توسعه خود وصل کنید.
  3. برنامه SdkControllerSensor را روی دستگاه خود اجرا کنید.
  4. در برنامه، حسگرهایی را که می‌خواهید شبیه‌سازی کنید، انتخاب کنید.
  5. دستور adb زیر را اجرا کنید:

  6. $ adb forward tcp:1968 tcp:1968
    
  7. شبیه‌ساز را اجرا کنید. اکنون باید بتوانید با حرکت دادن دستگاه خود، تبدیل‌ها را روی شبیه‌ساز اعمال کنید.

توجه: اگر حرکاتی که روی دستگاه فیزیکی خود انجام می‌دهید، شبیه‌ساز را تغییر نمی‌دهد، دستور adb را از مرحله ۵ دوباره اجرا کنید.

برای اطلاعات بیشتر، به راهنمای شبیه‌ساز اندروید مراجعه کنید.

متد onSensorChanged() را مسدود نکنید

داده‌های حسگر می‌توانند با سرعت بالایی تغییر کنند، به این معنی که سیستم ممکن است متد onSensorChanged(SensorEvent) را مرتباً فراخوانی کند. به عنوان یک روش بهینه، باید تا حد امکان در متد onSensorChanged(SensorEvent) کارهای کمتری انجام دهید تا آن را مسدود نکنید. اگر برنامه شما نیاز به انجام هرگونه فیلتر کردن داده‌ها یا کاهش داده‌های حسگر دارد، باید آن کار را خارج از متد onSensorChanged(SensorEvent) انجام دهید.

از استفاده از متدها یا انواع حسگرهای منسوخ‌شده خودداری کنید

چندین متد و ثابت منسوخ شده‌اند. به طور خاص، نوع حسگر TYPE_ORIENTATION منسوخ شده است. برای دریافت داده‌های جهت‌یابی، باید از متد getOrientation() استفاده کنید. به همین ترتیب، نوع حسگر TYPE_TEMPERATURE منسوخ شده است. در دستگاه‌هایی که اندروید ۴.۰ را اجرا می‌کنند، باید از نوع حسگر TYPE_AMBIENT_TEMPERATURE استفاده کنید.

قبل از استفاده از حسگرها، آنها را بررسی کنید

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

تأخیرهای حسگر را با دقت انتخاب کنید

هنگام ثبت یک حسگر با استفاده از متد registerListener() ، مطمئن شوید که نرخ تحویلی را انتخاب می‌کنید که برای برنامه یا مورد استفاده شما مناسب باشد. حسگرها می‌توانند داده‌ها را با نرخ‌های بسیار بالایی ارائه دهند. اجازه دادن به سیستم برای ارسال داده‌های اضافی که نیازی به آنها ندارید، منابع سیستم را هدر می‌دهد و از باتری استفاده می‌کند.