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

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

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

  • سنسورهای حرکت

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

  • سنسورهای محیطی

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

  • سنسورهای موقعیت

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

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

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

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

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

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

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

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

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

چارچوب سنسور

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

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

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

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

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

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

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

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

در حالی که در دسترس بودن حسگر از دستگاهی به دستگاه دیگر متفاوت است، می تواند بین نسخه های اندروید نیز متفاوت باشد. این به این دلیل است که حسگرهای اندروید در طول چندین نسخه پلتفرم معرفی شده اند. به عنوان مثال، بسیاری از سنسورها در اندروید 1.5 (API Level 3) معرفی شدند، اما برخی از آنها پیاده سازی نشدند و تا اندروید 2.3 (API Level 9) برای استفاده در دسترس نبودند. به همین ترتیب، چندین حسگر در اندروید 2.3 (API Level 9) و Android 4.0 (API Level 14) معرفی شدند. دو سنسور منسوخ شده و با سنسورهای جدیدتر و بهتر جایگزین شده اند.

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

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

سنسور اندروید 4.0
(API سطح 14)
اندروید 2.3
(API سطح 9)
اندروید 2.2
(API سطح 8)
اندروید 1.5
(API سطح 3)
TYPE_ACCELEROMETER بله بله بله بله
TYPE_AMBIENT_TEMPERATURE بله n/a n/a n/a
TYPE_GRAVITY بله بله n/a n/a
TYPE_GYROSCOPE بله بله n/a 1 n/a 1
TYPE_LIGHT بله بله بله بله
TYPE_LINEAR_ACCELERATION بله بله n/a n/a
TYPE_MAGNETIC_FIELD بله بله بله بله
TYPE_ORIENTATION بله 2 بله 2 بله 2 بله
TYPE_PRESSURE بله بله n/a 1 n/a 1
TYPE_PROXIMITY بله بله بله بله
TYPE_RELATIVE_HUMIDITY بله n/a n/a n/a
TYPE_ROTATION_VECTOR بله بله n/a n/a
TYPE_TEMPERATURE بله 2 بله بله بله

1 این نوع حسگر در اندروید 1.5 (سطح API 3) اضافه شد، اما تا قبل از اندروید 2.3 (سطح API 9) برای استفاده در دسترس نبود.

2 این سنسور موجود است، اما منسوخ شده است.

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

چارچوب حسگر اندروید روش‌های مختلفی را ارائه می‌کند که تشخیص سنسورهای موجود در دستگاه را در زمان اجرا برای شما آسان می‌کند. 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 را به عنوان فروشنده فهرست می‌کند و شماره نسخه آن 3 است. اگر آن سنسور خاص روی دستگاه وجود ندارد، سعی می‌کنیم از شتاب‌سنج استفاده کنیم.

کاتلین

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() برمی گرداند، حسگر جریانی است. حسگرهای جریانی داده ها را در فواصل زمانی منظم حس می کنند و در اندروید 2.3 (سطح 9 API) معرفی شدند. اگر یک حسگر با فراخوانی متد getMinDelay() صفر را برگرداند، به این معنی است که حسگر یک حسگر جریانی نیست زیرا داده ها را تنها زمانی گزارش می دهد که در پارامترهایی که حس می کند تغییری ایجاد شود.

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

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

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

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

  • دقت سنسور تغییر می کند.

    در این مورد، سیستم متد 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() به برنامه شما ارسال می‌شوند. تأخیر پیش‌فرض داده برای نظارت بر تغییرات معمولی جهت صفحه نمایش مناسب است و از تأخیر 200000 میکروثانیه استفاده می‌کند. می‌توانید تأخیرهای داده دیگری مانند SENSOR_DELAY_GAME (تأخیر 20000 میکروثانیه)، SENSOR_DELAY_UI (تأخیر 60000 میکروثانیه)، یا SENSOR_DELAY_FASTEST (تأخیر 0 میکروثانیه) را مشخص کنید. از Android 3.0 (API Level 11) همچنین می توانید تاخیر را به عنوان یک مقدار مطلق (در میکروثانیه) مشخص کنید.

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

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

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

مدیریت تنظیمات مختلف سنسور

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

شما دو گزینه برای اطمینان از وجود حسگر معین در دستگاه دارید:

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

هر گزینه در بخش های زیر مورد بحث قرار می گیرد.

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

اگر برنامه شما از نوع خاصی از سنسور استفاده می کند، اما به آن متکی نیست، می توانید از چارچوب حسگر برای شناسایی حسگر در زمان اجرا استفاده کنید و سپس ویژگی های برنامه را در صورت لزوم غیرفعال یا فعال کنید. به عنوان مثال، یک برنامه ناوبری ممکن است از سنسور دما، سنسور فشار، سنسور 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.
}

استفاده از فیلترهای Google Play برای هدف قرار دادن تنظیمات حسگر خاص

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

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

اگر این عنصر و توصیفگر را به مانیفست برنامه خود اضافه کنید، کاربران تنها در صورتی برنامه شما را در Google Play خواهند دید که دستگاه آنها شتاب سنج داشته باشد.

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

سیستم مختصات سنسور

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

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

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

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

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

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

محدودیت سنسور

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

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

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

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

AndroidManifest.xml

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

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

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

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

در دستگاه‌های دارای Android 9 (سطح 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 را اجرا می کند. توجه داشته باشید که این برنامه فقط در دستگاه‌های دارای Android نسخه 4.0 (سطح API 14) یا بالاتر در دسترس است. (اگر دستگاه دارای اندروید 4.0 است، باید نسخه 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 را از مرحله 5 اجرا کنید.

برای اطلاعات بیشتر، راهنمای شبیه ساز Android را ببینید.

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

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

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

چندین روش و ثابت منسوخ شده اند. به ویژه، نوع سنسور TYPE_ORIENTATION منسوخ شده است. برای دریافت داده های جهت گیری، باید از متد getOrientation() به جای آن استفاده کنید. به همین ترتیب، نوع سنسور TYPE_TEMPERATURE منسوخ شده است. به جای آن باید از نوع حسگر TYPE_AMBIENT_TEMPERATURE در دستگاه‌هایی که Android نسخه 4.0 دارند استفاده کنید.

قبل از استفاده از سنسورها را بررسی کنید

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

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

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