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.
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.
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
.
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 SensorManager
openbare 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);
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;
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;
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.