Получение информации с сенсоров устройства Android

Автор: | 04.09.2014

В более ранних статьях мы уже получали информацию об устройстве.

Теперь давайте копнем глубже и получим данные с доступных на устройстве сенсоров.

Их может быть много, а может и совсем чуть чуть, ранее мы уже смотрели на разные устройства, и в некоторых их было совсем не густо.

Полный их список можно получить здесь, пока их 13.

Для получения информации с сенсоров мы будем использовать класс SensorManager.

Его мы уже использовали в классе Tools для получения полного списка устройств.

Но для оперативной работы с их данными нужно зарегистрировать специальный слушатель SensorEventListener, который будет отлавливать события получения данных от сенсоров.

Для этого у класса нашей активности объявим интерфейс SensorEventListener и теперь при работе с SensorManager в места где нужен экземпляр слушателя, достаточно написать this.

[cce lang="java" tab_size="2" no_links="false"]

public class MainActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;

........

[/cce]

Теперь Eclipse должен заругаться:

Multiple markers at this line
- The type MainActivity must implement the inherited abstract method
SensorEventListener.onAccuracyChanged(Sensor, int)
- The type MainActivity must implement the inherited abstract method
SensorEventListener.onSensorChanged(SensorEvent)

В переводе на русский нужно реализовать два абстрактных метода onSensorChanged и onAccuracyChanged.

Первый произойдет, когда показания сенсора изменились, а второй - когда изменилась точность замеров сенсора.

Мы будем использовать только первый, в нём будем обновлять данные на экране устройства.

Вот код обновленной разметки activity_main.xml:

[cce lang="xml" tab_size="2" no_links="false"]

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="@string/hello_world" />

<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_info"
android:layout_marginTop="20dp"
android:text="@string/hello_world" />

<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tv1"
android:layout_marginTop="20dp"
android:text="@string/hello_world" />

<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tv2"
android:layout_marginTop="20dp"
android:text="@string/hello_world" />

<TextView
android:id="@+id/tv_sensors"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tv3"
android:layout_marginTop="20dp"
android:text="@string/hello_world" />

</RelativeLayout>

[/cce]

Данные с сенсоров будем выводить в TextView - tv_sensors.

В методе активности onResume() регистрируем слушателя:

[cce lang="java" tab_size="2" no_links="false"]

mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_UI);

[/cce]

А в методе onPause() слушателя аннулируем:

[cce lang="java" tab_size="2" no_links="false"]

mSensorManager.unregisterListener(this);

[/cce]

У mSensorManager.registerListener три параметра: слушатель(SensorEventListener object), сенсор и период его обновления.

Сенсор получаем через константу, к примеру тут у нас сенсор освещённости

[cce lang="java" tab_size="2" no_links="false"]

mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)

[/cce]

Период обновления задаем тоже через константу:

[cce lang="java" tab_size="2" no_links="false"]

SensorManager.SENSOR_DELAY_UI

[/cce]

Пока их придумали 4:

  • SENSOR_DELAY_FASTEST_UI
  • SENSOR_DELAY_GAME
  • SENSOR_DELAY_NORMAL
  • SENSOR_DELAY_UI

Нужно отметить, что работает этот период на каждом устройстве по-разному.

Вот код получившего в итоге класса активности:

[cce lang="java" tab_size="2" no_links="false"]

package com.rusdelphi.tools;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
StringBuilder mInfo = new StringBuilder();
StringBuilder mLight = new StringBuilder("Освещенность:");
StringBuilder mTemperature = new StringBuilder("Температура:");
StringBuilder mPressure = new StringBuilder("Давление:");

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

}

@Override
protected void onStart() {
super.onStart();
TextView tv_info = (TextView) findViewById(R.id.tv_info);
String info = "Доступ к интернет:"
+ (Tools.isOnline(this) ? "есть" : "нет") + "\n";

info += "Модель:" + Build.MODEL + "\n";
info += "Производитель:" + Build.MANUFACTURER + "\n";
info += "Версия ПО: " + Build.VERSION.RELEASE + "\n";
info += "Версия SDK: " + Build.VERSION.SDK_INT + "\n";
tv_info.setText(info);

TextView tv1 = (TextView) findViewById(R.id.tv1);
tv1.setText("Уровень заряда батареи " + Tools.getBatteryLevel(this));
TextView tv2 = (TextView) findViewById(R.id.tv2);
tv2.setText("Температура батареи " + Tools.getBatteryTemperatute(this));
TextView tv3 = (TextView) findViewById(R.id.tv3);
tv3.setText("Список доступных сенсоров на устройстве "
+ Tools.getSensorsList(this).toString());
}

@Override
protected void onResume() {
mSensorManager = (SensorManager) this
.getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, mSensorManager
.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE),
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
SensorManager.SENSOR_DELAY_UI);
super.onResume();
}

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

@Override
public void onSensorChanged(SensorEvent event) {
mInfo = new StringBuilder();
if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
mLight = new StringBuilder("Освещенность:");
mLight.append(event.values[0]);
}
if (event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
mTemperature = new StringBuilder("Температура:");
mTemperature.append(event.values[0]);
}
if (event.sensor.getType() == Sensor.TYPE_PRESSURE) {
mPressure = new StringBuilder("Давление:");
mPressure.append(event.values[0]);
}
mInfo.append(String.format("%1$s\n", mLight));
mInfo.append(String.format("%1$s\n", mTemperature));
mInfo.append(String.format("%1$s\n", mPressure));

TextView tv_sensors = (TextView) findViewById(R.id.tv_sensors);

tv_sensors.setText(mInfo.toString());
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
}
[/cce]

Использовано всего три простых датчика: освещенности, температуры и давления.

Их показания приходят в переменной event.values[0], если использовать более сложные датчики, то значений будет больше

К примеру вот датчик положения устройства, у него данные (values) приходят тремя параметрами.

В методе onSensorChanged мы не используем класс String, потому как при конкатенации строк он значительно медленнее работает, чем StringBuilder .

Переход на новую строку в нём реализован через String.format:

[cce lang="java" tab_size="2" no_links="false"]

String.format("%1$s\n", light)

[/cce]

Сенсоры и устройства всё время развиваются и сегодня Eclipse  радостно сообщил, что : The field Sensor.TYPE_TEMPERATURE is deprecated. Поискав в доках, нашел, что он устарел с 20 API  (This constant was deprecated in API level 20. use  Sensor.TYPE_AMBIENT_TEMPERATURE instead. )

Вот что получилось на выходе:

device-2014-09-04-150035Показаний температуры у нас нет, т.к. и температурного сенсора на устройстве не нашлось (и метод getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE) вернул null).

Во избежание таких досадных моментов, в манифесте приложения можно указывать требования к наличию датчиков.

Вот к примеру шагомер:

[cce lang="xml" tab_size="2" no_links="false"]

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

[/cce]

С такой записью в манифесте  Google Play сам отсечет устройства, которые не имеют указанного сенсора.

Получение информации с сенсоров устройства Android: 1 комментарий

  1. Уведомление: Новости из мира Delphi 1.09 – 7.09 2014 |

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *