Hvordan Ring av kameraet i Android App Development


En av de store tingene om moderne mobiltelefoner er stadig god onboard kamera. Android API gir deg sømløs tilgang til kameraet fra en hvilken som helst annen app, og gir deg mange muligheter for å forbedre eksisterende apps eller lage nye

Det er to grunnleggende tilnærminger til kameratilgang. Kan du bruke en intensjon om å ringe standard kamera app, eller du kan bruke API for å bygge ditt eget kamera aktivitet. Den andre er mer fleksibel, men også krever mer arbeid for å kode. Ofte er det fint bare å bruke standard app, og det er det vi vil dekke i denne opplæringen.

Vårt eksempel applikasjonen vil være ganske grunnleggende, bare for å illustrere poenget. Vi vil ha en knapp, som vi deretter å lansere et kamera hensikt, så viser vi returnerte bildet. Som forklart i forrige tutorial, er Intents brukes av Android å passere meldinger innenfor og mellom aktiviteter og moduler. Her vil vår Intent passere en melding til og fra ombord kameraet.

Sette opp

Når du har opprettet prosjektet, og før du starter koding, må du redigere manifest (AndroidManifest.xml) for å legge tillatelse til å bruke kameraet og ekstern lagring, og for å legge til et notat at dette programmet bruker kamerafunksjonen:

 < manifest .... > < bruker-tillatelse android: name = "android.permission.CAMERA" /> < bruker-tillatelse android: name = "android.permission.ACCESS_NETWORK_STATE" /> < bruker-feature android: name = "android.hardware.camera" /> 

Deretter setter du opp XML display (i activity_call_camera.xml) for å vise en knapp og et bilde:

 < RelativeLayout xmlns: android = "http://schemas.android.com/apk/res/android" > < Button android: id = "+ id /button_callcamera" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_alignParentTop = "true" android: layout_centerHorizontal = "true" android: layout_marginTop = "18dp" android : text = "@ streng /get_photo" /> < Imageview android: id = "+ id /photo_image" android: contentDescription = "vil variere, bilde tatt fra kamera" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_below = "+ id /Button1 "android: layout_centerHorizontal =" true "android: layout_marginTop =" 80dp "android: src =" /@ teikne /ic_launcher "/> < /RelativeLayout > 
Calling av kameraet med Intent

Nå , sette opp én aktivitet:

 public class CallCamera strekker Aktivitet {private static endelige String TAG = "CallCamera"; private static final int CAPTURE_IMAGE_ACTIVITY_REQ = 0; Uri fileUri = null; Imageview photoImage = null; Override Beskyttet void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_call_camera); photoImage = (Imageview) findViewById (R.id.photo_image); Button callCameraButton = (knappen) findViewById (R.id.button_callcamera); callCameraButton.setOnClickListener (ny View.OnClickListener () {public void onClick (Vis visning) {Intent i = new Intent (MediaStore.ACTION_IMAGE_CAPTURE); Fil = getOutputPhotoFile (); fileUri = Uri.fromFile (getOutputPhotoFile ()); i. putExtra (MediaStore.EXTRA_OUTPUT, fileUri); startActivityForResult (i, CAPTURE_IMAGE_ACTIVITY_REQ);}}); }} 

Vi bruker startActivityForResult (), fordi vi ønsker et resultat (fotofilen) returnerte til vår aktivitet når kameraet er ferdig. Dette betyr at vi må levere inn en URI å gi kameraet et sted å lagre bildet. (Se litt lenger ned for hvorfor fileUri, grammatikken, må være en klassevariabel.)

getOutputPhotoFile () metoden ser slik ut:

 privat File getOutputPhotoFile () {File directory = new File (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_PICTURES), getPackageName ()); hvis {if {Log.e (TAG, "Klarte ikke å lage lagringskatalog.") (directory.exists (!)) (directory.mkdirs ()!); returnere null; }} String timestamp = new SimpleDateFormat ("yyyMMdd_HHmmss", locale.UK) .format (new Date ()); returnere new File (directory.getPath () + File.separator + "IMG_" + TimeStamp + ".jpg");} 

Dette gir bildet en fornuftig og standard (tidsbundet) navn, og bruker system- trukket bildelagrings katalog for enheten.

Til slutt må vi håndtere resultatet når den returnerer til aktiviteten. Dette er vår onActivityResult ():

 beskyttet void onActivityResult (int requestCode, int resultCode, Intent data) {if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQ) {if (resultCode == RESULT_OK) {Uri photoUri = null; if (data == null) {//en kjent feil her! Bildet bør ha lagret i fileUri Toast.makeText (dette, "Image lagret", Toast.LENGTH_LONG) .vis (); photoUri = fileUri; } Else {photoUri = data.getData (); Toast.makeText (dette, "Image lagret i:" + data.getData (), Toast.LENGTH_LONG) .vis (); } //ShowPhoto (photoUri); } Else if (resultCode == RESULT_CANCELED) {Toast.makeText (dette, "Avbrutt", Toast.LENGTH_SHORT) .vis (); } Else {Toast.makeText (dette "! Nummer for bildeopptak mislyktes", Toast.LENGTH_LONG) .vis (); }}} 


Du vil merke at kommentaren om en kjent feil. Hva som skal skje er at bildet URI skal returneres av Intent. Men noen eldre enheter (inkludert mine) lagrer filen i den valgte plasseringen, men sende tilbake en null Intent. Løsningen er å lagre posisjonen (fileUri) og bruke det hvis vi får en "OK" resultat kode, men ingen bilde posisjonsdata. Hvis du kjører denne koden som det er, bør det fungere, men du vil bare få Toast meldinger på retur.



Viser bilde

Nå, la oss vise returnert image. Uncomment showPhoto () linje i metoden over, og legge til en showPhoto () metode:

 private void showPhoto (Uri photoUri) {File imageFile = new File (photoUri); if (imageFile.exists ()) {Bitmap bitmap = BitmapFactory.decodeFile (imageFile.getAbsolutePath ()); BitmapDrawable teikne = nye BitmapDrawable (this.getResources (), bitmap); photoImage.setScaleType (ImageView.ScaleType.FIT_CENTER); photoImage.setImageDrawable (teikne); }} 

Kjør koden, og du skal se bildet vist under "få bildet" -knappen når du kommer tilbake fra kameraet.

Forbedringer og feilrettinger

Hvis du klikker knappen en gang og ta en andre bildet, bør det gamle bildet bli erstattet av den nye en ... men faktisk, hvis du prøver det, avhengig av enheten kan du bli møtt med en OutOfMemoryError. For å fikse dette, legg til denne linjen i showPhoto (): private void showPhoto (Uri photoUri) {if (imageFile.exists ()) {((BitmapDrawable) photoImage.getDrawable ()) getBitmap () resirkulere ();.. //... Som før}}

Til slutt, har du kanskje lagt merke til at i utgangspunktet når du fyrer opp koden, får du en liten Android robot hvor bildet skal være. For å fikse dette, og bare viser ingenting, legge til en linje i onCreate ():

 photoImage = (Imageview) findViewById (R.id.photo_image); photoImage.setImageDrawable (null); 

Du vil også trenger å gjøre noen endringer i showPhoto () for å unngå en NullPointerException:

 private void showPhoto (Uri photoUri) {if (imageFile.exists ()) {teikne oldDrawable = photoImage.getDrawable (); if (oldDrawable = null) {((BitmapDrawable) oldDrawable) .getBitmap () resirkulering (.); } //Hvile som før}} 

En siste utgave: avhengig av enheten, kan bildet også roteres på skjermen. Dessverre er dette en litt komplisert å fikse, hovedsakelig på grunn av minne kostnadene for roterende punktgrafikk, og er utenfor omfanget av denne opplæringen. Hvis du ønsker å utforske dette videre, kan du bruke EXIF-informasjon for å finne rotasjonen, og BitmapFactory å redusere overhead håndtere punktgrafikk. Litt senere i denne opplæringen serien, vil jeg se på manipulere bitmaps og bilder; neste opplæringen i serien, men vil ta en nærmere titt på kameraet API og ved å bygge ditt eget kamera app. Anmeldelser