Использование акселерометра в Android приложении
Главная » Использование акселерометра в Android приложении

В этом уроке мы научимся работать в Android приложении с акселерометром, одной из многих фишек на современном смартфоне. Мы разберем, что же такое акселерометр и как его можно использовать при программировании приложений. 

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

В этом уроке мы будем работать с такими жестами - пользователь будет встряхивать устройство и на экране будет появляться 6 лотерейных номеров в сопровождении симпатичной анимации.

Начинаем работать. Создаем новый проект, названия либо оставьте по умолчанию, либо введите свои, но потом будете разбираться в них сами:). Наше будущее приложение будет поддерживать только портретную ориентацию. Поэтому сразу идем в файл манифеста приложения AndroidManifest.xml и настроим проекту только портретный вид:

<activity android:name="com.Lottery.Main"
 android:screenOrientation="portrait"
 android:label="@string/app_name">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
</activity>

В основном классе программы MainActivity.java нужно выполнить SensorEventListener интерфейс. Для этого, добавляем к строке объявления класса следующее:

public class MainActivity extends Activity implements SensorEventListener

Для успешного использования SensorEventListener нужно добавить к строкам импорта следующее:

import android.hardware.SensorEventListener;

При объявлении выполнения интерфейса SensorEventListener программа заругалась на нас ошибками. Ничего страшного, просто для реализации этого интерфейса необходимы два особых метода, с которыми мы сейчас разберемся. Ниже метода onCreate добавим следующие методы:

@Override
public void onSensorChanged(SensorEvent event) {
 
}
 
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
 
}

Взглянем на метод onSensorChanged. Этот метод используется для обнаружения жестов. Он вызывается всякий раз, когда в акселерометре устройства происходят какие то перемены. Он вызывается многократно, всякий раз, когда устройство приходит в движение. Для того, чтобы использовать классы Sensor и SensorEvent, необходимо добавить еще пару строк в импорт:

import android.hardware.Sensor;
import android.hardware.SensorEvent;

Перед тем, как использовать метод onSensorChanged, нам нужно задекларировать использование следующих переменных:

private SensorManager senSensorManager;
private Sensor senAccelerometer;

Если после этого у вас появились ошибки, проверьте, есть ли среди импорта это:

import android.hardware.SensorManager;

В методе onCreate мы инициализируем наши переменные и создаем слушателя событий:

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
 senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
}

Для инициализации SensorManager мы вызываем getSystemService, таким образом мы получаем доступ к акселерометру. Метод getSystemService вызывается для получения ссылки на необходимый нам сервис. Отсылка к акселерометру происходит благодаря команде getDefaultSensor. Далее, для регистрации сенсора, мы используем метод registerListener:

public class Main extends Activity implements SensorEventListener {
 private SensorManager senSensorManager;
 private Sensor senAccelerometer;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
 senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
 }
 
 @Override
 public void onSensorChanged(SensorEvent sensorEvent) {
 
 }
 
 @Override
 public void onAccuracyChanged(Sensor sensor, int accuracy) {
 
 }
}

Теперь нам нужно описать еще два метода: onPause и onResume. Это будет использоваться для того, чтобы отключать работу с акселерометром, когда мы не работаем в приложении, и опять включать при продолжении работы, что будет способствовать быстродействия аппарата и уровню потребления батареи. Эти методы будут выглядеть примерно так:

protected void onPause() {
 super.onPause();
 senSensorManager.unregisterListener(this);
}

protected void onResume() {
 super.onResume();
 senSensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}

Теперь нужно научить наше приложение распознавать жесты. Большинство работ по реализации этого будет происходить внутри метода onSensorChanged. Для начала задекларируем в классе MainActivity.java такие переменные:

private long lastUpdate = 0;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 600;

Теперь перейдем в работе в методе onSensorChanged. Мы получаем ссылку на акселерометр и проверяем, не ошиблись ли мы с выбором адаптера (акселерометра):

public void onSensorChange(SensorEvent sensorEvent) {
 Sensor mySensor = sensorEvent.sensor;
 
 if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
 }
}

Далее нужно определить положение устройства в трехмерном пространстве по x,y, и z осям. Чтобы лучше понять о чем речь, изучаем следующую картинку:

Для того, чтобы получить эти необходимые нам координаты, мы делаем так:

public void onSensorChange(SensorEvent sensorEvent) {
 Sensor mySensor = sensorEvent.sensor;
 
 if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
 float x = sensorEvent.values[0];
 float y = sensorEvent.values[1];
 float z = sensorEvent.values[2];
 }
}

Сенсоры большинства смартфонов невероятно чувствительны. Неважно, насколько твердо ваша рука держит смартфон, сенсор все равно будет постоянно видеть изменение положения аппарата. Поэтому для мониторинга положения устройства метод onSensorChanged вызывается очень часто, по несколько раз в секунду. Правда нам не нужно так много информации для нашего приложения, поэтому мы сделаем так, что этот методу будет вызываться не чаще, чем раз в 100 миллисекунд:

public void onSensorChange(SensorEvent sensorEvent) {
 Sensor mySensor = sensorEvent.sensor;
 
 if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
 float x = sensorEvent.values[0];
 float y = sensorEvent.values[1];
 float z = sensorEvent.values[2];
 
 long curTime = System.currentTimeMillis();
 
 if ((curTime - lastUpdate) > 100) {
 long diffTime = (curTime - lastUpdate);
 lastUpdate = curTime;
 }
 }
}

Теперь усовершенствуем программу до состояния, когда она сможет подсчитывать скорость движения устройства, Для этого мы декларируем особенную переменную SHAKE_THRESHOLD, которая будет показывать, зарегистрировано ли движение устройства или нет. Изменение значения переменной SHAKE_THRESHOLD увеличивает или уменьшает чувствительность сенсора, поэтому здесь можете пофантазировать на свое усмотрение:

public void onSensorChange(SensorEvent sensorEvent) {
 Sensor mySensor = sensorEvent.sensor;
 
 if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
 float x = sensorEvent.values[0];
 float y = sensorEvent.values[1];
 float z = sensorEvent.values[2];
 
 long curTime = System.currentTimeMillis();
 
 if ((curTime - lastUpdate) > 100) {
 long diffTime = (curTime - lastUpdate);
 lastUpdate = curTime;
 
 float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000;
 
 if (speed > SHAKE_THRESHOLD) {
 
 }
 
 last_x = x;
 last_y = y;
 last_z = z;
 }
 }
}

И так, у нас уже есть приложение, с помощью акселерометра способное определять жесты и движение. Теперь мы сделаем так, что при встряхивании устройством будет выбираться 6 случайных чисел, но об этом чуть позже. Сейчас нам нужно отредактировать файл activity_main.xml. В уроке в качестве фона используется изображение синего шара, вы можете выбрать на фон, что вам угодно:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <LinearLayout
 android:layout_height="wrap_content"
 android:layout_width="fill_parent"
 android:weightSum="6"
 android:orientation="horizontal">
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:layout_weight="2"
 android:id="@+id/ball_1"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_1"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:layout_weight="2"
 android:id="@+id/ball_2"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_2"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:layout_weight="2"
 android:id="@+id/ball_3"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_3"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 </LinearLayout>
 
 <LinearLayout
 android:layout_height="wrap_content"
 android:layout_width="fill_parent"
 android:weightSum="6"
 android:orientation="horizontal">
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:layout_weight="2"
 android:id="@+id/ball_4"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_4"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:id="@+id/ball_5"
 android:layout_weight="2"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_5"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 <FrameLayout
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_margin="5dp"
 android:id="@+id/ball_6"
 android:layout_weight="2"
 android:background="@drawable/blue">
 <TextView
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/number_6"
 android:gravity="center"
 android:layout_gravity="center_vertical"
 android:textColor="@android:color/white"/>
 </FrameLayout>
 </LinearLayout>
 </LinearLayout>

Каждый FrameLayout содержит элемент TextView, в котором будет отображаться случайно сгенерированное число от 1 до 49. Удостоверьтесь, что все FrameLayout и TextView имеют свой id, чтобы можно было к ним потом обращаться. 

Теперь давайте еще разок вернемся в класс MainActivity.java и добавим туда метод выбора случайного числа от 1 до 49:

private void getRandomNumber() {
 ArrayList numbersGenerated = new ArrayList();
 
 for (int i = 0; i < 6; i++) {
 Random randNumber = new Random();
 int iNumber = randNumber.nextInt(48) + 1;
 
 if(!numbersGenerated.contains(iNumber)) {
 numbersGenerated.add(iNumber);
 } else {
 i--;
 }
 }
}

Мы создаем объект ArrayList для хранения выбранных 6 чисел и в цикле for с помощью стандартного java класса Random выбираем случайные числа. Также выполняется проверка уже добавленных в ArrayList чисел, чтобы избежать повторов. Чтобы все заработало исправно, добавим еще пару строчек к импорту:

import java.util.ArrayList;
import java.util.Random;

Последним шагом будет отображение выбранных 6 случайных чисел в пользовательском интерфейсе. Получаем ссылки на элементы TextView, созданные ранее, и привязываем к ним числа, а также добавим анимацию нашим FrameLayout:

private void getRandomNumber() {
 ArrayList numbersGenerated = new ArrayList();
 
 for (int i = 0; i < 6; i++) {
 Random randNumber = new Random();
 int iNumber = randNumber.nextInt(48) + 1;
 
 if(!numbersGenerated.contains(iNumber)) {
 numbersGenerated.add(iNumber);
 } else {
 i--;
 }
 }
 
 TextView text = (TextView)findViewById(R.id.number_1);
 text.setText(""+numbersGenerated.get(0));
 
 text = (TextView)findViewById(R.id.number_2);
 text.setText(""+numbersGenerated.get(1));
 
 text = (TextView)findViewById(R.id.number_3);
 text.setText(""+numbersGenerated.get(2));
 
 text = (TextView)findViewById(R.id.number_4);
 text.setText(""+numbersGenerated.get(3));
 
 text = (TextView)findViewById(R.id.number_5);
 text.setText(""+numbersGenerated.get(4));
 
 text = (TextView)findViewById(R.id.number_6);
 text.setText(""+numbersGenerated.get(5));
 
 FrameLayout ball1 = (FrameLayout) findViewById(R.id.ball_1);
 ball1.setVisibility(View.INVISIBLE);
 
 FrameLayout ball2 = (FrameLayout) findViewById(R.id.ball_2);
 ball2.setVisibility(View.INVISIBLE);
 
 FrameLayout ball3 = (FrameLayout) findViewById(R.id.ball_3);
 ball3.setVisibility(View.INVISIBLE);
 
 FrameLayout ball4 = (FrameLayout) findViewById(R.id.ball_4);
 ball4.setVisibility(View.INVISIBLE);
 
 FrameLayout ball5 = (FrameLayout) findViewById(R.id.ball_5);
 ball5.setVisibility(View.INVISIBLE);
 
 FrameLayout ball6 = (FrameLayout) findViewById(R.id.ball_6);
 ball6.setVisibility(View.INVISIBLE);
 
 Animation a = AnimationUtils.loadAnimation(this, R.anim.move_down_ball_first);
 ball6.setVisibility(View.VISIBLE);
 ball6.clearAnimation();
 ball6.startAnimation(a);
 
 ball5.setVisibility(View.VISIBLE);
 ball5.clearAnimation();
 ball5.startAnimation(a);
 
 ball4.setVisibility(View.VISIBLE);
 ball4.clearAnimation();
 ball4.startAnimation(a);
 
 ball3.setVisibility(View.VISIBLE);
 ball3.clearAnimation();
 ball3.startAnimation(a);
 
 ball2.setVisibility(View.VISIBLE);
 ball2.clearAnimation();
 ball2.startAnimation(a);
 
 ball1.setVisibility(View.VISIBLE);
 ball1.clearAnimation();
 ball1.startAnimation(a);
}

Добавим к строкам импорта еще такие:

import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.TextView;

Для настройки анимации нужно создать соответствующий файл, в котором мы ее зададим. Создайте в файлах проекта папку anim и в ней файл move_down_ball_first.xml и добавьте туда следующий код:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:fillAfter="true"
 android:interpolator="@android:anim/bounce_interpolator">
 
 <scale
 android:duration="1500"
 android:fromXScale="1.0"
 android:fromYScale="-10.0"
 android:toXScale="1.0"
 android:toYScale="1.0" />
</set>

Все, что осталось сделать, это вызвать метод getRandomNumber в методе onSensorChanged класса MainActivity.java:

public void onSensorChange(SensorEvent sensorEvent) {
 Sensor mySensor = sensorEvent.sensor;
 
 if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
 float x = sensorEvent.values[0];
 float y = sensorEvent.values[1];
 float z = sensorEvent.values[2];
 
 long curTime = System.currentTimeMillis();
 
 if ((curTime - lastUpdate) > 100) {
 long diffTime = (curTime - lastUpdate);
 lastUpdate = curTime;
 
 float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000;
 
 if (speed > SHAKE_THRESHOLD) {
 getRandomNumber();
 }
 
 last_x = x;
 last_y = y;
 last_z = z;
 }
 }
}

Все, наше приложение, работающее на акселерометре устройства готово! Запускаем на смартфоне программу, трясем как следует аппарат и видим примерно это:

Надеюсь, вам этот урок оказался полезен, удачи!

Категория: Уроки программирования | Просмотров: 1656 | Добавил: Oleg | Теги: Акселерометр, программируем на Android | Рейтинг: 4.7/3
Всего комментариев: 0
avatar