Utilizarea accelerometrului pe Android

În acest tutorial, vom explora cum să folosim accelerometrul, unul din multele senzori hardware ai smartphone-urilor moderne, într-o aplicație Android. Voi explica ce este un accelerometru și de ce poate fi ceva la care doriți să profitați în aplicațiile Android.

Introducere

Înainte de apariția zorilor smartphone-uri, una dintre puținele aplicații ale componentelor hardware care puteau interacționa era tastatura. Dar vremurile s-au schimbat și interacțiunea cu componentele hardware devine din ce în ce mai des întâlnită.

Utilizarea gesturilor se simte adesea mai naturală decât interacțiunea cu o interfață de utilizator prin mouse și tastatură. Acest lucru este valabil mai ales pentru dispozitivele touch, cum ar fi smartphone-urile și tabletele. Consider că utilizarea gesturilor poate aduce o aplicație Android la viață, făcând-o mai interesantă și mai interesantă pentru utilizator.

Destul de câteva aplicații utilizează acum accelerometrul. De exemplu, aruncați o privire asupra acestor șabloane de aplicații de pe Envato Market, care includ un joc de curse cu viteză și un agitator de numere aleatorii.

În acest tutorial, vom folosi un gest pe care îl găsiți în numeroase aplicații mobile, gestul de agitare. Vom folosi gestul pentru a genera aleatoriu șase numere de loterie și le vom afișa pe ecran folosind o animație destul de bună.

1. Noțiuni de bază

Pasul 1: Configurarea proiectului

Începeți un nou proiect Android în IDE-ul preferat (Integrated Development Environment) pentru dezvoltarea Android. Pentru acest tutorial, voi folosi IntelliJ IDEA.

Dacă IDE-ul dvs. suportă dezvoltarea Android, acesta va fi creat un Principal pentru tine. Numele acestei clase poate varia în funcție de IDE-ul pe care îl utilizați. Principal clasa joacă un rol cheie atunci când cererea dvs. este lansată. IDE-ul dvs. ar fi trebuit, de asemenea, să fi creat un fișier principal de aspect, care să fie Principal utilizează clasa pentru a crea interfața de utilizare a aplicației.

Deoarece vom folosi un gest de agitare, este o idee bună să blocați orientarea dispozitivului. Acest lucru va asigura că interfața de utilizare a aplicației nu se schimbă în mod constant între portret și peisaj. Deschideți fișierul manifest al proiectului și setați orientarea ecranului opțiunea pentru portret.

     

Pasul 2: Configurarea senzorului

Cu proiectul stabilit, este timpul să ne murdărim mâinile și să scriem niște coduri. În prezent, clasa principală de activitate are un onCreate metoda în care am setat aspectul principal invocând setContentView așa cum se arată mai jos.

clasa publică Extensie principală Activitate / ** Chemată când activitatea este creată pentru prima dată. * / @Override publică void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

În funcție de IDE pe care îl utilizați, este posibil să fie necesar să adăugați câteva declarații de import către Main.java, fișierul în care dvs. Principal clasa vieți. Majoritatea IDE-urilor vor introduce aceste declarații de import pentru dvs., dar vreau să fiu sigur că suntem pe aceeași pagină înainte de a continua. Prima declarație de import, importă android.app.Activity, importă Activitate clasa în timp ce a doua declarație de import, import șiroid.os.Bundle, importă Pachet clasă. A treia declarație de import, com.example.R, conține definițiile pentru resursele aplicației. Această declarație de import va fi diferită de cea pe care o vedeți mai jos, deoarece depinde de numele pachetului dvs..

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

În pasul următor, vom folosi efectul SensorEventListener , care este declarat în Android SDK. Pentru a utiliza SensorEventListener interfață, Principal clasa de activități trebuie să o implementeze așa cum se arată în fragmentul de cod de mai jos. Dacă vă uitați la actualizată Principal clasa de activitate, veți găsi că folosesc ustensile cuvânt cheie pentru a spune compilatorului că Principal clasa implementează SensorEventListener interfață.

clasa publică principală se extinde Activitatea implementează SensorEventListener / ** Chemată când activitatea este inițial creată. * / @Override publică void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); 

Pentru a utiliza SensorEventListener trebuie să adăugați o altă declarație de import, după cum se arată mai jos. Majoritatea IDE-urilor vor adăuga inteligent declarația de import pentru dvs., astfel încât, probabil, nu va trebui să vă faceți griji în legătură cu acest lucru.

import android.hardware.SensorEventListener;

Din moment, actualizați Principal implementarea clasei, așa cum se arată mai sus, veți vedea câteva erori de afișare. Acest lucru nu este surprinzător, deoarece avem nevoie de două implementăm două metode necesare SensorEventListener interfață.

Dacă utilizați IntelliJ IDEA, ar trebui să vi se solicite să adăugați aceste metode necesare când faceți clic pe eroare. Dacă utilizați un IDE diferit, acest comportament poate fi diferit. Să adăugăm manual cele două metode necesare, așa cum se arată în fragmentul de cod de mai jos. Asigurați-vă că adăugați aceste metode în Principal clasa și în afara onCreate metodă.

@Override public void onSensorChanged (eveniment SensorEvent)  @Override public void onAccuracyChanged (senzor senzor, precizie int) 

Să aruncăm o privire la onSensorChanged metodă. Vom folosi această metodă pentru a detecta gestul de agitare. onSensorChanged metoda este invocată de fiecare dată când senzorul încorporat detectează o modificare. Această metodă este invocată în mod repetat de fiecare dată când dispozitivul este în mișcare. Pentru a utiliza Senzor și SensorEvent clase, adăugăm două declarații de import suplimentare, după cum se arată mai jos.

import șiroid.hardware.Sensor; import android.hardware.SensorEvent;

Înainte să implementăm onSensorChanged, trebuie să declarăm două variabile private în Principal clasă, senSensorManager de tip SensorManager și senAccelerometer de tip Senzor.

privat SensorManager senSensorManager; senzor privat senAccelerometer;

SensorManager clasa este declarată în android.hardware.SensorManager. Dacă vedeți erori de afișare, verificați din nou că SensorManager este importată și clasa.

import șiroid.hardware.SensorManager;

În onCreate , inițializăm variabilele pe care tocmai le-am declarat și le înregistrăm pe un ascultător. Aruncați o privire la implementarea actualizată a onCreate metodă.

@Override protejate void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); senSensorManager = (senzorManager) getSystemService (Context.SENSOR_SERVICE); senAccelerometru = senSensorManager.getDefaultSensor (Sensor.TYPE_ACCELEROMETER); senSensorManager.registerListener (acest, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

Pentru a inițializa SensorManager exemplu, invocăm getSystemService pentru a prelua sistemul SensorManager exemplu, pe care noi, la rândul nostru, le folosim pentru a accesa senzorii sistemului. getSystemService metoda este folosită pentru a obține o referință la un serviciu al sistemului prin trecerea numelui serviciului. Cu managerul de senzori la dispoziția noastră, vom primi o referință la accelerometrul sistemului invocând getDefaultSensor pe managerul de senzori și trecând de la tipul de senzor de care suntem interesați. Apoi, înregistram senzorul utilizând unul din SensorManagermetodele publice, registerListener. Această metodă acceptă trei argumente, contextul activității, un senzor și rata la care sunt livrate evenimentele senzorilor.

clasa publică principală se extinde Activitatea implementează SensorEventListener private SensorManager senSensorManager; senzor privat senAccelerometer; / ** Chemată când se creează prima activitate. * / @Override publică void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.main); senSensorManager = (senzorManager) getSystemService (Context.SENSOR_SERVICE); senAccelerometru = senSensorManager.getDefaultSensor (Sensor.TYPE_ACCELEROMETER); senSensorManager.registerListener (acest, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);  @Override public void onSensorChanged (SensorEvent sensorEvent)  @Overide public void onAccuracyChanged (senzor senzor, precizie int) 

Există două alte metode pe care trebuie să le suprimăm, onPause și onResume. Acestea sunt metode ale Principal clasă. Este o practică bună să anulați înregistrarea senzorului atunci când aplicația hibernează și să înregistreze senzorul din nou când aplicația se reia. Uitați-vă la fragmentele de cod de mai jos pentru a obține o idee despre cum funcționează acest lucru în practică.

protejat void onPause () super.onPause (); senSensorManager.unregisterListener (aceasta); 
protejat void onResume () super.onResume (); senSensorManager.registerListener (acest, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 

Pasul 3: Detectarea gestului de agitare

Acum putem începe să ne concentrăm asupra cărnii cererii. Va fi nevoie de un pic de matematică pentru a descoperi când are loc un gest de agitare. Cea mai mare parte a logicii va intra în onSensorChanged metodă. Începem prin a declara câteva variabile în cadrul nostru Principal clasă. Uitați-vă la fragmentul de cod de mai jos.

private long lastUpdate = 0; float privat last_x, last_y, last_z; finale statice private int int SHAKE_THRESHOLD = 600;

Acum, măriți performanța aplicației onSensorChanged metodă. Luăm o referință la Senzor instanță folosind SensorEvent instanță care ne este transmisă. După cum puteți vedea în fragmentul de cod de mai jos, verificăm din nou că avem o referință la tipul de senzor corect, accelerometrul sistemului.

public void onSensorChange (SensorEvent senzorEvent) Sensor mySensor = sensorEvent.sensor; dacă (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) 

Următorul pas este extragerea poziției dispozitivului în spațiu X, y, și z axă. Uitați-vă la imaginea de mai jos pentru a înțelege mai bine ce mă refer. X axa definește mișcarea laterală, în timp ce y axa definește mișcarea verticală. z axa este puțin mai complicată deoarece definește mișcarea în și din planul definit de X și y axă.


Pentru a obține valorile fiecărei axe, cerem evenimentul senzorului pentru valorile sale, după cum se arată mai jos. Evenimentele valorile atributul este o serie de flotoare.

public void onSensorChange (SensorEvent senzorEvent) Sensor mySensor = sensorEvent.sensor; dacă (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = senzorEvent.value [0]; flotat y = senzorEvaluarea valorilor [1]; float z = senzorEvaluarea valorilor [2]; 

Senzorii sistemului sunt incredibil de sensibili. Când țineți un dispozitiv în mână, acesta este în mișcare constantă, indiferent cât de stabilă este mâna. Rezultatul este că onSensorChanged metoda este invocată de mai multe ori pe secundă. Nu avem nevoie de toate aceste date, așa că trebuie să ne asigurăm că eșantionăm doar un subset de date pe care le obținem de la accelerometrul dispozitivului. Stocam ora actuala a sistemului (in milisecunde) curTime și verificați dacă mai mult de 100 milisecunde au trecut de la ultima dată onSensorChanged a fost invocată.

public void onSensorChange (SensorEvent senzorEvent) Sensor mySensor = sensorEvent.sensor; dacă (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = senzorEvent.value [0]; flotat y = senzorEvaluarea valorilor [1]; float z = senzorEvaluarea valorilor [2]; curTime lung = System.currentTimeMillis (); dacă ((curTime - lastUpdate)> 100) lung diffTime = (curTime - lastUpdate); lastUpdate = curTime; 

Ultima piesă a puzzle-ului detectează dacă dispozitivul a fost scuturat sau nu. Noi folosim Math pentru a calcula viteza dispozitivului, după cum se arată mai jos. Declarat static SHAKE_THRESHOLD variabila este utilizată pentru a vedea dacă a fost detectat sau nu un gest de agitare. modificarea SHAKE_THRESHOLD crește sau scade sensibilitatea, deci nu ezitați să jucați cu valoarea sa.

public void onSensorChange (SensorEvent senzorEvent) Sensor mySensor = sensorEvent.sensor; dacă (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = senzorEvent.value [0]; flotat y = senzorEvaluarea valorilor [1]; float z = senzorEvaluarea valorilor [2]; curTime lung = System.currentTimeMillis (); dacă ((curTime - lastUpdate)> 100) lung diffTime = (curTime - lastUpdate); lastUpdate = curTime; viteza flotorului = Math.abs (x + y + z - ultima_x - ultima_y - ultima_z) / diffTime * 10000; dacă (viteza> SHAKE_THRESHOLD)  last_x = x; last_y = y; last_z = z; 

2. Finalizarea aplicației de loterie

Acum avem o aplicație care poate detecta un gest de agitare folosind accelerometrul. Să terminăm acest proiect folosind gestul pentru a alege șase numere loterie aleatorii. Vă voi arăta cum să generați un număr aleator între 1 și 49, dar sunteți liber să modificați implementarea mea pentru ca aceasta să funcționeze cu modul în care este jucată loteria în țara dvs..

Să începem prin configurarea fișierului de aspect principal al aplicației pe care îl vom folosi pentru interfața cu utilizatorul. După cum puteți vedea mai jos, folosesc șase layout-uri de cadre cu fundal de imagine a unei mingi.

                        

Fiecare aspect al cadrului conține o vizualizare text care va afișa un număr loterie generat la întâmplare. Rețineți că fiecare aspect de cadru și vizualizare de text are un id pentru a vă asigura că le putem trimite mai târziu.

Cu aspectul principal gata de utilizare, să revizuim Principal clasă. Începem prin a crea getRandomNumber, o metodă privată pentru generarea a șase numere aleatorii între 1 și 49.

privat void getRandomNumber () ArrayList numereGenerat = nou ArrayList (); pentru (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--;   

Mai întâi creăm un ArrayList exemplu, pe care îl folosim pentru a stoca cele șase numere. În fiecare buclă din pentru bucla, vom profita de Java Întâmplător pentru a genera un număr aleator. Pentru a vă asigura că avem un număr între 1 și 49, adaugam 1 la rezultat. Următorul pas este să verificați dacă numărul generat este deja în lista de matrice, deoarece dorim numai numere unice în lista de matrice.

Rețineți că poate fi necesar să adăugați încă două declarații de import pentru a menține compilatorul fericit.

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

Ultimul pas este afișarea numărului generat aleator în interfața cu utilizatorul. Obținem o referință la vederile de text pe care le-am creat mai devreme și vom popula fiecare vizualizare text cu un număr aleatoriu. Adăugăm, de asemenea, o animație elegantă în layout-urile de cadre, dar nu ezitați să omiteți sau să modificați animația.

privat void getRandomNumber () ArrayList numereGenerat = nou ArrayList (); pentru (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); 

Va trebui să adăugăm câteva declarații de import suplimentare pentru a face toate aceste lucruri. Uitați-vă la fragmentul de cod de mai jos.

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

În ceea ce privește animațiile, aruncați o privire la conținutul fișierului de animație de mai jos. Rețineți că trebuie să creați un anim folder în directorul de resurse al proiectului și numiți-l move_down_ball_first.xml. Prin ajustarea valorilor scară element, puteți modifica durata animației și poziția fiecărei mingi.

   

Tot ce a mai rămas pentru noi este să sunăm getRandomNumber în onSensorChanged în Principal clasă. Aruncați o privire la implementarea completă a onSensorChanged prezentat mai jos.

public void onSensorChange (SensorEvent senzorEvent) Sensor mySensor = sensorEvent.sensor; dacă (mySensor.getType () == Sensor.TYPE_ACCELEROMETER) float x = senzorEvent.value [0]; flotat y = senzorEvaluarea valorilor [1]; float z = senzorEvaluarea valorilor [2]; curTime lung = System.currentTimeMillis (); dacă ((curTime - lastUpdate)> 100) lung diffTime = (curTime - lastUpdate); lastUpdate = curTime; viteza flotorului = Math.abs (x + y + z - ultima_x - ultima_y - ultima_z) / diffTime * 10000; dacă (viteza> SHAKE_THRESHOLD) getRandomNumber ();  last_x = x; last_y = y; last_z = z; 

Concluzie

În acest tutorial, v-am arătat cum funcționează accelerometrul și cum îl puteți folosi pentru a detecta un gest de agitare. Desigur, există multe alte cazuri de utilizare pentru accelerometru. Cu o înțelegere de bază a detectării gesturilor utilizând accelerometrul, vă încurajez să experimentați cu accelerometrul pentru a vedea ce altceva puteți face cu acesta.

Dacă lucrați foarte mult cu dezvoltarea Android, probabil că veți întâlni situații în care aveți nevoie de ajutor pentru un anumit aspect care nu este specialitatea dvs. În acest caz, încercați să angajați unul dintre dezvoltatorii de aplicații de la Envato Studio pentru a finaliza lucrarea rapid și fiabil.

Cod