Bruke Accelerometer på Android

I denne opplæringen skal vi undersøke hvordan du bruker accelerometeret, en av de mange maskinvaresensorene til moderne smartphones, i en Android-applikasjon. Jeg skal forklare hva en akselerometer er, og hvorfor det kan være noe du vil benytte deg av i Android-applikasjonene dine.

Introduksjon

Før begynnelsen av smarttelefoner kunne en av de få maskinvarekomponentene samhandle med tastaturet. Men tider har endret seg og interaksjon med maskinvarekomponenter blir stadig mer vanlige.

Bruk av bevegelser føles ofte naturligere enn å interagere med et brukergrensesnitt gjennom mus og tastatur. Dette gjelder spesielt for berøringsenheter, for eksempel smarttelefoner og nettbrett. Jeg finner at bruk av bevegelser kan bringe en Android-applikasjon til liv, noe som gjør den mer interessant og spennende for brukeren.

En hel del apps bruker nå akselerometeret. For eksempel, se på disse appmaler på Envato Market, som inkluderer et raceringsspill og en tilfeldig nummerrister.

I denne opplæringen bruker vi en gest som du finner i ganske mange mobile applikasjoner, ristbevegelsen. Vi bruker shake gestus til å tilfeldig opprette seks lotteri tall og vise dem på skjermen ved hjelp av en pen animasjon.

1. Komme i gang

Trinn 1: Prosjektoppsett

Start et nytt Android-prosjekt i din favoritt IDE (Integrated Development Environment) for Android-utvikling. For denne opplæringen bruker jeg IntelliJ IDEA.

Hvis IDE støtter Android-utvikling, har den opprettet en Hoved klasse for deg. Navnet på denne klassen kan variere avhengig av hvilken IDE du bruker. De Hoved klassen spiller en nøkkelrolle når søknaden din blir lansert. Din IDE bør også ha opprettet en hovedoppsettfil som Hoved klassen bruker til å lage applikasjonens brukergrensesnitt.

Siden vi skal bruke en shake gest, er det en god idé å låse enhetens orientering. Dette vil sikre at applikasjonens brukergrensesnitt ikke skifter hele tiden mellom portrett og landskap. Åpne prosjektets manifestfil og sett inn Skjermretning alternativ til portrett.

     

Trinn 2: Sette opp sensoren

Med vårt prosjekt satt opp, er det på tide å få hendene skitne og skrive noen kode. For øyeblikket har hovedaktivitetsklassen en onCreate Metode der vi angir hovedoppsettet ved å påkalle setContentView som vist under.

offentlig klasse Main utvider aktivitet / ** Kalt når aktiviteten er først opprettet. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

Avhengig av IDE du bruker, må du kanskje legge til noen få importeringserklæringer til Main.java, filen der din Hoved klasse liv. De fleste IDE-er vil sette inn disse importerklæringene for deg, men jeg vil sørge for at vi er på samme side før vi fortsetter. Den første importerklæringen, importer android.app.Activity, importerer Aktivitet klasse mens den andre importoppgaven, importer android.os.Bundle, importerer Bunt klasse. Den tredje importerklæringen, com.example.R, inneholder definisjonene for ressursene i søknaden. Denne importerklæringen vil avvike fra den du ser nedenfor, da det avhenger av navnet på pakken.

importer android.app.Activity; importere android.os.Bundle; importer com.example.R;

I neste trinn vil vi utnytte SensorEventListener grensesnitt, som er erklært i Android SDK. For å bruke SensorEventListener grensesnitt, Hoved Aktivitetsklassen må implementere den som vist i kodestykket nedenfor. Hvis du ser på den oppdaterte Hoved aktivitetsklasse, finner du at jeg bruker redskaper søkeord for å fortelle kompilatoren at Hoved klassen implementerer SensorEventListener grensesnitt.

offentlig klasse Hoved utvider Aktivitet implementerer SensorEventListener / ** Kalt når aktiviteten er først opprettet. * / @Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

For å bruke SensorEventListener grensesnitt, må du legge til en annen importoppgave som vist nedenfor. De fleste IDE-er vil legge til importoppførelsen for deg, slik at du sannsynligvis ikke trenger å bekymre deg for dette.

importer android.hardware.SensorEventListener;

Fra øyeblikket oppdaterer du Hoved klasse implementering som vist ovenfor, vil du se noen feil dukker opp. Dette er ikke overraskende siden vi trenger to implementere to nødvendige metoder for SensorEventListener grensesnitt.

Hvis du bruker IntelliJ IDEA, bør du bli bedt om å legge til disse nødvendige metodene når du klikker på feilen. Hvis du bruker en annen IDE, kan denne oppførselen være annerledes. La oss legge til de to nødvendige metodene for hånd som vist i kodestykket nedenfor. Pass på å legge til disse metodene i Hoved klasse og utenfor onCreate metode.

@Override public void onSensorChanged (SensorEvent-hendelse)  @Override public void on AccuracyChanged (Sensor sensor, int nøyaktighet) 

La oss ta en titt på onSensorChanged metode. Vi bruker denne metoden for å oppdage shake gestus. De onSensorChanged Metoden påberopes hver gang den innebygde sensoren oppdager en endring. Denne metoden brukes flere ganger når enheten er i bevegelse. For å bruke Sensor og SensorEvent klasser, legger vi til ytterligere to importangivelser som vist nedenfor.

importere android.hardware.Sensor; importer android.hardware.SensorEvent;

Før vi implementerer onSensorChanged, Vi må deklarere to private variabler i Hoved klasse, senSensorManager av type SensorManager og senAccelerometer av type Sensor.

Privat SensorManager SenSensorManager; Privat Sensor SenAccelerometer;

De SensorManager Klassen er erklært i android.hardware.SensorManager. Hvis du ser noen feil, dukker opp, dobbeltklikker du at SensorManager klassen er også importert.

importer android.hardware.SensorManager;

I onCreate Metode, vi initialiserer variablene vi nettopp har erklært og registrerer en lytter. Ta en titt på den oppdaterte implementeringen av onCreate metode.

@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 (dette, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

For å initialisere SensorManager eksempel, påberoper vi oss getSystemService for å hente systemets SensorManager eksempel, som vi igjen bruker for å få tilgang til systemets sensorer. De getSystemService Metoden brukes til å få en referanse til en tjeneste av systemet ved å sende navnet på tjenesten. Med sensorhåndteringen til vår disposisjon, får vi en referanse til systemets akselerometer ved å påkalle getDefaultSensor på sensorstyreren og passerer typen sensor vi er interessert i. Vi registrerer sensoren ved hjelp av en av SensorManagers offentlige metoder, registerListener. Denne metoden aksepterer tre argumenter, aktivitetens kontekst, en sensor og frekvensen der sensorhendelser leveres til oss.

offentlig klasse Hoved utvider Aktivitet implementerer SensorEventListener private SensorManager senSensorManager; Privat Sensor SenAccelerometer; / ** Kalt når aktiviteten er først opprettet. * / @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 (dette, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);  @Override public void onSensorChanged (SensorEvent sensorEvent)  @Override public void on AccuracyChanged (Sensor sensor, int nøyaktighet) 

Det er to andre metoder vi må overstyre, onPause og onResume. Dette er metoder for Hoved klasse. Det er god praksis å avregistrere sensoren når applikasjonen dvale og registrere sensoren igjen når programmet fortsetter. Ta en titt på kodestykket nedenfor for å få en ide om hvordan dette fungerer i praksis.

beskyttet ugyldig onPause () super.onPause (); senSensorManager.unregisterListener (this); 
beskyttet ugyldig onResume () super.onResume (); senSensorManager.registerListener (dette, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

Trinn 3: Registrere Shake Gesture

Vi kan nå begynne å fokusere på kjøttet i søknaden. Det vil kreve litt matte å finne ut når en rystelsesbevegelse finner sted. Det meste av logikken vil gå inn i onSensorChanged metode. Vi begynner med å erklære noen få variabler i vår Hoved klasse. Ta en titt på kodestykket nedenfor.

privat lenge sistUpdate = 0; privat float last_x, last_y, last_z; privat statisk endelig int SHAKE_THRESHOLD = 600;

La oss nå zoome inn på implementeringen av onSensorChanged metode. Vi tar en referanse til Sensor eksempel ved bruk av SensorEvent eksempel som er sendt til oss. Som du kan se i kodestykket under, dobbeltsjekker vi at vi får en referanse til riktig sensortype, systemets akselerometer.

Offentlig tomgang på SensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; hvis (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) 

Det neste trinnet er å trekke ut enhetens posisjon i rommet, x, y, og z akser. Ta en titt på bildet nedenfor for å bedre forstå hva jeg refererer til. De x akse definerer lateral bevegelse, mens y akse definerer vertikal bevegelse. De z akse er litt vanskeligere da den definerer bevegelse inn og ut av flyet definert av x og y akser.


For å få verdiene for hver akse, spør vi sensorhendelsen for dens verdier som vist nedenfor. Arrangementet er verdier Attribut er en rekke flyter.

Offentlig tomgang på SensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; hvis (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = sensorEvent.values ​​[0]; float y = sensorEvent.values ​​[1]; float z = sensorEvent.values ​​[2]; 

Systemets sensorer er utrolig følsomme. Når du holder en enhet i hånden, er den hele tiden i bevegelse, uansett hvor stabil hånden din er. Resultatet er at onSensorChanged Metoden påberopes flere ganger i sekundet. Vi trenger ikke alle disse dataene, så vi må sørge for at vi bare prøver en delmengde av dataene vi får fra enhetens akselerometer. Vi lagrer systemets nåværende tid (i millisekunder) lagrer den inn CurTime-verdien og sjekk om mer enn 100 millisekunder har gått siden siste gang onSensorChanged ble påkalt.

Offentlig tomgang på SensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; hvis (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = sensorEvent.values ​​[0]; float y = sensorEvent.values ​​[1]; float z = sensorEvent.values ​​[2]; lang curTime = System.currentTimeMillis (); hvis ((curTime - lastUpdate)> 100) long diffTime = (curTime - lastUpdate); lastUpdate = curTime; 

Det siste stykket av puslespillet oppdager om enheten har blitt rystet eller ikke. Vi bruker Matte klassen for å beregne enhetens hastighet som vist nedenfor. Den statisk erklært SHAKE_THRESHOLD Variabel brukes til å se om en shake gest er blitt oppdaget eller ikke. modifisering SHAKE_THRESHOLD øker eller reduserer følsomheten, så vær fri til å spille med verdien.

Offentlig tomgang på SensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; hvis (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = sensorEvent.values ​​[0]; float y = sensorEvent.values ​​[1]; float z = sensorEvent.values ​​[2]; lang curTime = System.currentTimeMillis (); hvis ((curTime - lastUpdate)> 100) long diffTime = (curTime - lastUpdate); lastUpdate = curTime; flytehastighet = Math.abs (x + y + z - last_x - last_y - siste_z) / diffTime * 10000; hvis (hastighet> SHAKE_THRESHOLD)  last_x = x; last_y = y; last_z = z; 

2. Fullføring av Lotteri-søknaden

Vi har nå et program som kan oppdage en shake gestus ved hjelp av akselerometeret. La oss fullføre dette prosjektet ved å bruke shake gesturen til å velge seks tilfeldige lotteri tall. Jeg skal vise deg hvordan du genererer et tilfeldig tall mellom 1 og 49, men du er fri til å endre implementeringen for å få det til å fungere med hvordan lotteriet spilles i ditt land.

La oss starte med å sette opp programmets hovedlayoutfil som vi bruker til brukergrensesnittet. Som du ser nedenfor bruker jeg seks rammeoppsett med bakgrunn av et bilde av en ball.

                        

Hver rammeoppsett inneholder en tekstvisning som vil vise et tilfeldig generert lotteri nummer. Merk at hver rammeoppsett og tekstvisning har en id for å sikre at vi kan referere dem senere.

Med hovedoppsettet klar til bruk, la oss se på nytt Hoved klasse. Vi begynner med å lage getRandomNumber, en privat metode for å generere seks tilfeldige tall mellom 1 og 49.

privat tomt 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--;   

Vi lager først en Arraylist eksempel, som vi bruker til å lagre de seks tallene i. I hver løkke av til loop, vi benytter oss av Java Tilfeldig klassen for å generere et tilfeldig tall. For å sikre at vi får et nummer mellom 1 og 49, vi legger til 1 til resultatet. Det neste trinnet er å kontrollere om det genererte nummeret allerede er i matelisten, fordi vi bare vil ha unike tall i matelisten.

Vær oppmerksom på at det kan være nødvendig å legge til to importangivelser for å holde kompilatoren glad.

importer java.util.ArrayList; importer java.util.Random;

Det siste trinnet er å vise det tilfeldig genererte nummeret i brukergrensesnittet. Vi får en referanse til tekstvisninger vi opprettet tidligere, og fylle hver tekstvisning med et tilfeldig tall. Vi legger også til en fin animasjon i rammebetingelsene, men vær så snill å unnlate eller endre animasjonen.

privat tomt 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); 

Vi må legge til noen få flere importeringserklæringer for å gjøre alt dette arbeidet. Ta en titt på kodestykket nedenfor.

importer android.view.View; importere android.view.animation.Animation; importer android.view.animation.AnimationUtils; importer android.widget.FrameLayout; importer android.widget.TextView;

Når det gjelder animasjonene, ta en titt på innholdet i animasjonsfilen nedenfor. Legg merke til at du må opprette en anim mappe i prosjektets ressurs katalog og navn den move_down_ball_first.xml. Ved å justere verdiene til skala element, kan du endre animasjonens varighet og posisjonen til hver ball.

   

Alt som er igjen for oss å gjøre er å ringe getRandomNumber i onSensorChanged i Hoved klasse. Ta en titt på den fullstendige implementeringen av onSensorChanged Vist under.

Offentlig tomgang på SensorChange (SensorEvent sensorEvent) Sensor mySensor = sensorEvent.sensor; hvis (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = sensorEvent.values ​​[0]; float y = sensorEvent.values ​​[1]; float z = sensorEvent.values ​​[2]; lang curTime = System.currentTimeMillis (); hvis ((curTime - lastUpdate)> 100) long diffTime = (curTime - lastUpdate); lastUpdate = curTime; flytehastighet = Math.abs (x + y + z - last_x - last_y - siste_z) / diffTime * 10000; hvis (hastighet> SHAKE_THRESHOLD) getRandomNumber ();  last_x = x; last_y = y; last_z = z; 

Konklusjon

I denne opplæringen har jeg vist deg hvordan akselerometeret fungerer, og hvordan du kan bruke det til å oppdage en rystebevegelse. Selvfølgelig er det mange andre brukstilfeller for akselerometeret. Med en grunnleggende forståelse for å oppdage gebyrer ved hjelp av akselerometeret, oppfordrer jeg deg til å eksperimentere med akselerometeret for å se hva annet du kan gjøre med det.

Hvis du jobber med Android-utvikling mye, vil du sannsynligvis løpe over situasjoner der du trenger hjelp med et bestemt aspekt som ikke er spesialitet. I så fall kan du prøve å ansette en av ekspertapputviklerne på Envato Studio for å fullføre arbeidet raskt og pålitelig.