De versnellingsmeter op Android gebruiken

In deze zelfstudie gaan we verkennen hoe de accelerometer, een van de vele hardwaresensoren van moderne smartphones, in een Android-toepassing kan worden gebruikt. Ik zal uitleggen wat een accelerometer is en waarom het misschien iets is waar je gebruik van wilt maken in je Android-applicaties.

Invoering

Vóór het begin van smartphones, was een van de weinige hardware-componenten die konden communiceren met het toetsenbord. Maar de tijden zijn veranderd en interactie met hardware-componenten komt steeds vaker voor.

Het gebruik van gebaren voelt vaak natuurlijker dan interactie met een gebruikersinterface via muis en toetsenbord. Dit geldt met name voor aanraakapparaten, zoals smartphones en tablets. Ik merk dat het gebruik van gebaren een Android-applicatie tot leven kan brengen, waardoor het interessanter en opwindender voor de gebruiker wordt.

Heel wat apps maken nu gebruik van de versnellingsmeter. Neem bijvoorbeeld een kijkje op deze app-sjablonen op Envato Market, die een snelheidsracespel en een schudmachine met willekeurige nummers bevatten.

In deze zelfstudie gebruiken we een gebaar dat u in een flink aantal mobiele apps vindt, het schudgebaar. We zullen het schudgebaar gebruiken om willekeurig zes Loterijnummers te genereren en ze op het scherm te tonen met behulp van een mooie animatie.

1. Aan de slag

Stap 1: Projectinstellingen

Start een nieuw Android-project in uw favoriete IDE (Integrated Development Environment) voor Android-ontwikkeling. Voor deze zelfstudie gebruik ik IntelliJ IDEA.

Als uw IDE Android-ontwikkeling ondersteunt, heeft deze een Hoofd klasse voor jou. De naam van deze klasse kan variëren, afhankelijk van welke IDE u gebruikt. De Hoofd klasse speelt een belangrijke rol wanneer uw toepassing wordt gestart. Uw IDE moet ook een hoofdlay-outbestand hebben gemaakt dat de Hoofd klasse gebruikt om de gebruikersinterface van de toepassing te maken.

Omdat we gebruik gaan maken van een schudgebaar, is het een goed idee om de richting van het apparaat te vergrendelen. Dit zorgt ervoor dat de gebruikersinterface van de toepassing niet voortdurend wisselt tussen portret en landschap. Open het manifestbestand van het project en stel de oriëntatie van het scherm optie om portret.

     

Stap 2: De sensor instellen

Met ons project opgezet, is het tijd om onze handen vuil te maken en wat code te schrijven. Op dit moment heeft de hoofdactiviteitsklasse een onCreate methode waarin we de hoofdlay-out instellen door aan te roepen setContentView zoals hieronder getoond.

public class Hoofd breidt activiteit uit / ** Wordt gebeld wanneer de activiteit voor het eerst wordt gemaakt. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

Afhankelijk van de IDE die u gebruikt, moet u mogelijk enkele importstatements toevoegen Main.java, het bestand waarin uw Hoofd klasse leeft. De meeste IDE's voegen deze importinstructies voor u in, maar ik wil ervoor zorgen dat we op dezelfde pagina staan ​​voordat we verder gaan. De eerste importverklaring, import android.app.Activity, importeert het Activiteit klasse terwijl de tweede import-instructie, import android.os.Bundle, importeert het Bundel klasse. De derde importverklaring, com.example.R, bevat de definities voor de bronnen van de applicatie. Deze importverklaring zal verschillen van degene die u hieronder ziet, omdat deze afhankelijk is van de naam van uw pakket.

import android.app.Activity; import android.os.Bundle; import com.example.R;

In de volgende stap gebruiken we de SensorEventListener interface, die wordt gedeclareerd in de Android SDK. Om de te gebruiken SensorEventListener interface, de Hoofd activiteitsklasse moet deze implementeren, zoals weergegeven in het onderstaande codefragment. Als je de bijgewerkte versie bekijkt Hoofd activiteitenklasse, zult u merken dat ik de gereedschap sleutelwoord om de compiler te vertellen dat het Hoofd klasse implementeert de SensorEventListener interface.

public class Hoofduitbreiding Activiteitsinstrumenten SensorEventListener / ** Wordt gebeld wanneer de activiteit voor het eerst wordt gemaakt. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

Om de te gebruiken SensorEventListener interface, moet u nog een importinstructie toevoegen, zoals hieronder wordt getoond. De meeste IDE's voegen de importverklaring op intelligente wijze toe, zodat u zich hier waarschijnlijk geen zorgen over hoeft te maken.

importeer android.hardware.SensorEventListener;

Vanaf het moment dat u het Hoofd klasse-implementatie zoals hierboven getoond, zult u een aantal fouten zien verschijnen. Dit is niet verrassend omdat we twee vereiste twee methoden nodig hebben van de SensorEventListener interface.

Als u IntelliJ IDEA gebruikt, moet u worden gevraagd om deze vereiste methoden toe te voegen wanneer u op de fout klikt. Als u een andere IDE gebruikt, kan dit gedrag afwijken. Laten we de twee vereiste methoden handmatig toevoegen, zoals weergegeven in het onderstaande codefragment. Zorg ervoor dat u deze methoden in de Hoofd klas en buiten de onCreate methode.

@Override public void onSensorChanged (SensorEvent event)  @Override openbare ongeldigheid opAccuracyChanged (Sensor sensor, int accuracy) 

Laten we eens kijken naar de onSensorChanged methode. We zullen deze methode gebruiken om het schudgebaar te detecteren. De onSensorChanged methode wordt aangeroepen telkens wanneer de ingebouwde sensor een wijziging detecteert. Deze methode wordt herhaaldelijk aangeroepen wanneer het apparaat in beweging is. Om de te gebruiken Sensor en SensorEvent klassen, voegen we twee extra importinstructies toe, zoals hieronder getoond.

importeer android.hardware.Sensor; importeer android.hardware.SensorEvent;

Voordat we het implementeren onSensorChanged, we moeten twee privévariabelen verklaren in de Hoofd klasse, senSensorManager van type SensorManager en senAccelerometer van type Sensor.

private SensorManager senSensorManager; privé Sensor senAccelerometer;

De SensorManager klasse wordt aangegeven in android.hardware.SensorManager. Als er fouten worden weergegeven, controleert u of het SensorManager klasse wordt ook geïmporteerd.

importeer android.hardware.SensorManager;

In de onCreate methode, initialiseren we de variabelen die we zojuist hebben verklaard en registreren we een luisteraar. Bekijk de bijgewerkte implementatie van de onCreate methode.

@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_ACCEREROMETER); senSensorManager.registerListener (this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

Om de. Te initialiseren SensorManager we roepen bijvoorbeeld aan getSystemService om het systeem op te halen SensorManager bijvoorbeeld, die we op hun beurt gebruiken om toegang te krijgen tot de sensors van het systeem. De getSystemService methode wordt gebruikt om een ​​verwijzing naar een service van het systeem te krijgen door de naam van de service door te geven. Met de sensormanager tot onze beschikking krijgen we een verwijzing naar de accelerometer van het systeem door aan te roepen getDefaultSensor op de sensormanager en het doorgeven van het type sensor waarin we geïnteresseerd zijn. Vervolgens registreren we de sensor met een van de SensorManageropenbare methoden, registerListener. Deze methode accepteert drie argumenten, de context van de activiteit, een sensor en de snelheid waarmee sensorgebeurtenissen aan ons worden geleverd.

public class Hoofduitbreiding Activiteitsinstrumenten SensorEventListener private SensorManager senSensorManager; privé Sensor senAccelerometer; /** Opgeroepen wanneer de activiteit voor het eerst is gemaakt. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); senSensorManager = (SensorManager) getSystemService (Context.SENSOR_SERVICE); senAccelerometer = senSensorManager.getDefaultSensor (Sensor.TYPE_ACCEREROMETER); senSensorManager.registerListener (this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);  @Override public void onSensorChanged (SensorEvent sensorEvent)  @Override openbare ongeldig opAccuracyChanged (sensor sensor, int nauwkeurigheid) 

Er zijn twee andere methoden die we moeten negeren, onPause en onResume. Dit zijn methoden van de Hoofd klasse. Het is een goede gewoonte om de registratie van de sensor ongedaan te maken wanneer de toepassing in de slaapstand staat en de sensor opnieuw te registreren wanneer de toepassing wordt hervat. Bekijk de onderstaande codefragmenten om een ​​idee te krijgen hoe dit in de praktijk werkt.

protected void onPause () super.onPause (); senSensorManager.unregisterListener (deze); 
protected void onResume () super.onResume (); senSensorManager.registerListener (this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

Stap 3: Het bewegingsgezicht detecteren

We kunnen ons nu gaan concentreren op het vlees van de toepassing. Het vereist een beetje wiskunde om erachter te komen wanneer een schudgebaar plaatsvindt. Het grootste deel van de logica gaat naar de onSensorChanged methode. We beginnen met het declareren van enkele variabelen in onze Hoofd klasse. Bekijk het onderstaande codefragment.

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

Laten we nu inzoomen op de implementatie van de onSensorChanged methode. We grijpen een verwijzing naar de Sensor bijvoorbeeld met behulp van de SensorEvent instantie die aan ons wordt doorgegeven. Zoals u in het onderstaande codefragment kunt zien, controleren we nogmaals of we een verwijzing krijgen naar het juiste sensortype, de versnellingsmeter van het systeem.

public void onSensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; if (mySensor.getType () == Sensor.TYPE_ACCEREROMETER) 

De volgende stap is het uitpakken van de positie van het apparaat in de ruimte, de X, Y, en z as. Bekijk de afbeelding hieronder om beter te begrijpen waar ik het over heb. De X as definieert zijwaartse beweging, terwijl de Y as definieert verticale beweging. De z as is een beetje lastiger omdat het beweging definieert in en uit het vlak gedefinieerd door de X en Y as.


Om de waarden van elke as te krijgen, vragen we de sensorgebeurtenis om zijn waarden zoals hieronder weergegeven. De evenementen waarden kenmerk is een reeks drijvers.

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]; 

De sensoren van het systeem zijn ongelooflijk gevoelig. Wanneer u een apparaat in uw hand houdt, is het constant in beweging, ongeacht hoe stabiel uw hand is. Het resultaat is dat de onSensorChanged methode wordt meerdere keren per seconde aangeroepen. We hebben niet al deze gegevens nodig, dus we moeten er zeker van zijn dat we slechts een deel van de gegevens uit de accelerometer van het apparaat nemen. We slaan de huidige tijd van het systeem (in milliseconden) op curTime en controleer of meer dan 100 milliseconden zijn verstreken sinds de laatste keer onSensorChanged werd aangeroepen.

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; 

Het laatste stukje van de puzzel is het detecteren of het apparaat is geschud of niet. Wij gebruiken de Wiskunde klasse om de snelheid van het apparaat te berekenen, zoals hieronder weergegeven. De statisch verklaard SHAKE_THRESHOLD variabele wordt gebruikt om te zien of een schokbeweging is gedetecteerd of niet. Het wijzigen SHAKE_THRESHOLD verhoogt of verlaagt de gevoeligheid, dus voel je vrij om te spelen met de waarde ervan.

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; zweefsnelheid = Math.abs (x + y + z - last_x - last_y - last_z) / diffTime * 10000; if (snelheid> SHAKE_THRESHOLD)  last_x = x; last_y = y; last_z = z; 

2. Afronding van de loterijaanvraag

We hebben nu een applicatie die een schudbeweging kan detecteren met behulp van de versnellingsmeter. Laten we dit project afronden door met het schudgebaar zes willekeurige lotnummers te kiezen. Ik zal je laten zien hoe je een willekeurig getal kunt genereren tussen 1 en 49, maar je bent vrij om mijn implementatie aan te passen om het te laten werken met hoe de loterij in jouw land wordt gespeeld.

Laten we beginnen met het opzetten van het belangrijkste lay-outbestand van de toepassing dat we zullen gebruiken voor de gebruikersinterface. Zoals je hieronder kunt zien, gebruik ik zes framelay-outs met een achtergrond van een afbeelding van een bal.

                        

Elke frame-indeling bevat een tekstweergave die een willekeurig gegenereerd lotnummer toont. Merk op dat elke framelay-out en tekstweergave een heeft ID kaart om ervoor te zorgen dat we ze later kunnen raadplegen.

Met de hoofdlay-out klaar voor gebruik, gaan we terug naar Hoofd klasse. We beginnen met creëren getRandomNumber, een private methode voor het genereren van zes willekeurige getallen tussen 1 en 49.

private void getRandomNumber () ArrayList numbersGenerated = new ArrayList (); voor (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--;   

We maken eerst een ArrayList Bijvoorbeeld, die we gebruiken om de zes getallen op te slaan. In elke lus van de voor loop, profiteren we van Java's Willekeurig klasse om een ​​willekeurig getal te genereren. Om ervoor te zorgen dat we een nummer tussen krijgen 1 en 49, we voegen toe 1 naar het resultaat. De volgende stap is om te controleren of het gegenereerde nummer al in de arraylijst staat, omdat we alleen unieke nummers in de arraylijst willen.

Houd er rekening mee dat het misschien nodig is om nog twee importinstructies toe te voegen om de compiler tevreden te houden.

importeer java.util.ArrayList; importeer java.util.Random;

De laatste stap is om het willekeurig gegenereerde nummer in de gebruikersinterface weer te geven. We krijgen een verwijzing naar de tekstweergaven die we eerder hebben gemaakt en vullen elke tekstweergave met een willekeurig nummer. We voegen ook een leuke animatie toe aan de frame-indelingen, maar vergeet niet om de animatie weg te laten of aan te passen.

private void getRandomNumber () ArrayList numbersGenerated = new ArrayList (); voor (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); 

We moeten nog enkele importinstructies toevoegen om dit allemaal te laten werken. Bekijk het onderstaande codefragment.

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

Zie voor de animaties de inhoud van het onderstaande animatiebestand. Merk op dat je een Anim map in de bronnenmap van uw project en geef deze een naam move_down_ball_first.xml. Door de waarden van de schaal element, kunt u de duur van de animatie en de positie van elke bal wijzigen.

   

We hoeven alleen maar te bellen getRandomNumber in onSensorChanged in de Hoofd klasse. Bekijk de volledige implementatie van onSensorChanged hieronder weergegeven.

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; zweefsnelheid = Math.abs (x + y + z - last_x - last_y - last_z) / diffTime * 10000; if (snelheid> SHAKE_THRESHOLD) getRandomNumber ();  last_x = x; last_y = y; last_z = z; 

Conclusie

In deze zelfstudie heb ik je laten zien hoe de versnellingsmeter werkt en hoe je deze kunt gebruiken om een ​​schokbeweging te detecteren. Natuurlijk zijn er veel andere gebruiksgevallen voor de versnellingsmeter. Met een basiskennis van het detecteren van bewegingen met behulp van de versnellingsmeter, raad ik je aan te experimenteren met de accelerometer om te zien wat je er nog meer mee kunt doen.

Als je veel met Android-ontwikkeling werkt, zul je waarschijnlijk situaties tegenkomen waarin je hulp nodig hebt met een bepaald aspect dat niet jouw specialiteit is. Als dat het geval is, kun je een van de deskundige app-ontwikkelaars bij Envato Studio inhuren om het werk snel en betrouwbaar te voltooien.