Hvordan Ring av kameraet i Android Apps Del 2: Capture and Store Photos

I den siste Android tutorial, begynte vi å bygge en grunnleggende kameraaktivitet på Android. Dette vil gi oss mulighet til å kontrollere og styre enheten kameraet direkte, i stedet for bare å slenge en Intent til standard kamera aktivitet. Koden i forrige tutorial sette opp kameraet og forhåndsvisning av kameraet. Nå kommer vi til å fange og lagre et bilde.

Oppsett

Vi har allerede satt opp manifestet for å tillate bruk av kameraet. For å lagre et bilde, må vi også legge tillatelse til å bruke ekstern lagring, ved å redigere AndroidManifest.xml:


 < manifest .... > < bruker-tillatelse android: name = "android.permission.ACCESS_NETWORK_STATE" /> 

Deretter må vi legge til en "ta bilde" -knappen for å forhåndsvisning av kameraet. Edit main.xml å inkludere en knapp:

 < LinearLayout ... > < FrameLayout ... /> < Button android: id = "+ id /button_photo" android: text = "Ta bilde" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_gravity = "center" /> < /LinearLayout > 

(Det er å foretrekke å bruke strings.xml å lagre knappen teksten i stedet for hardkode det som det er her.)

Fange og lagre et bilde

Hvis du kjører koden nå, bør du se en Take Foto-knappen; men som ennå det ikke gjør noe. Vi trenger å skrive koden som håndterer den. Legg dette til setUpLayout () i MyCameraActivity:

 Button captureBtn = (Button) findViewById (R.id.button_photo); captureBtn.setOnClickListener (ny View.OnClickListener () {public void onClick (Vis v) {takePhoto ();}}); 

takePhoto () gjør arbeidet med å gripe et bilde fra forhåndsvisning av kameraet:

 beskyttet statisk final int MEDIA_TYPE_IMAGE = 0; private void takePhoto () {PictureCallback pictureCB = new PictureCallback () {public void onPictureTaken (byte [] data, kamera cam) {File picFile = getOutputMediaFile (MEDIA_TYPE_IMAGE); if (picFile == null) {Log.e (TAG, "Kunne ikke opprette mediefil, sjekk lager tillatelser?"); komme tilbake; } Try {Fileoutputstream fos = new Fileoutputstream (picFile); fos.write (data); fos.close (); } Catch (FileNotFoundException e) {Log.e (TAG, "Finner ikke fil:" + e.getMessage ()); e.getStackTrace (); } Catch (IOException e) {Log.e (TAG, "I /O error skriver file:" + e.getMessage ()); e.getStackTrace (); }}}; camera.takePicture (null, null, pictureCB);} 

La oss se på det i mer detalj. Android gir PictureCallback grensesnitt for å få tak i bildedata fra et kamera. Som du kan se, setter det meste av koden i takePhoto () opp PictureCallback. Den siste linjen er den som kroker denne nye tilbakeringing i kameraet ved å føre den inn takePicture () fra kameraet API. Så når brukeren treffer Capture-knappen, bruker metoden takePicture () for å fortelle kameraet til å ta et bilde, passerer så dataene inn i PictureCallback.

I PictureCallback, får vi en fil for å skrive til, skrive til den, og håndtere de ulike mulige feil. (. Hvis du skulle skrive en annen slags app, kan du gjøre noe helt annerledes med denne bildedata, for eksempel vise den eller lagre den i en database) for å få en bestemt output file, trenger vi en hjelper metode:

 privat File getOutputMediaFile (int type) {File dir = ny fil (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_PICTURES), getPackageName ()); hvis {if {Log.e (TAG, "Klarte ikke å lage lagringskatalog.") (dir.exists (!)) (dir.mkdirs ()!); returnere null; }} String timestamp = new SimpleDateFormat ("yyyMMdd_HHmmss", Locale.UK) .format (new Date ()); hvis (type == MEDIA_TYPE_IMAGE) {return new File (directory.getPath () + File.separator + "IMG_" + TimeStamp + ".jpg"); } Else {return null; }} 

Det er to alternativer for å få en lagringskatalog på SD-kortet:


    Environment.getExternalStoragePublicDirectory (): dette bruker en offentlig katalog. Hvis programmet er avinstallert, vil bildene være

    Context.getExternalFilesDir (). Dette bruker en katalog som er privat til app. Hvis programmet er avinstallert, vil bildene også bli slettet.

    Når du bestemmer hvilken av disse du skal bruke, bør du tenke nøye om oppførselen brukerne vil forvente hvis, eller når, de sletter appen . I de fleste tilfeller kan brukerne være ganske skuffet over å finne bilder uventet slettet, men dette vil avhenge av detaljene i programmet ditt.

    Hvis du bruker offentlig katalog, som her, må du opprette en undermappe for lagring ( som her, en mulig katalognavn er det som er returnert av getPackageName ()). Ellers bruker ender opp med en masse bilder forurensende deres rot ekstern lagring. Når katalogen er valgt - og om nødvendig, skapt - vi også lage et filnavn; her med dato /tid, som er ganske standard. Her skal vi bare gjøre med JPG mediefiler. Hvis du ønsker å håndtere video i tillegg, kan du legge koden til å takle det og lagre det på riktig måte. Vær imidlertid oppmerksom på at videoen er mye mer komplisert å administrere.

    Bakgrunn kode

    Kjør koden og prøve det ut. Nå kan du lagre en fil (som du ser om du bruker en filbehandler app for å navigere til lagringskatalog).

    Men du vil finne at forhåndsvisningen fryser som du tar bildet. Du kan starte det enkelt, ved å legge til denne linjen i takePhoto ():

     camera.takePicture (null, null, pictureCB); camera.startPreview (); 

    Selv med denne linjen, skjønt, forhåndsvisnings fryser mens filen blir lagret. Dette er fordi som vår kode står, alt blir gjort på samme tråd. Vi så på threading i Canvas opplæringen, men i stedet for å skrive din egen tråd, gir AsyncTask en rask måte å overlate noe til en bakgrunn hjelper tråd med minimal kode. (Husk at Android-kode er ikke THREADSAFE. Bare bruke en bakgrunnstråd for noe som ikke involverer UI Her er vi bare lagre bildet i bakgrunnen.) Vi skal se på AsyncTask i detalj i en annen opplæringen, men her er koden for å løse problemet.

     private void takePhoto () {PictureCallback pictureCB = new PictureCallback () {public void onPictureTaken (byte [] data, kamera cam) {new SavePhotoTask () utfører (data); cam.startPreview (); }}; camera.takePicture (null, null, pictureCB);} class SavePhotoTask strekker AsyncTask < byte [], String, String > {Override Beskyttet String doInBackground (byte [] ... data) {File picFile = getOutputMediaFile (MEDIA_TYPE_IMAGE); if (picFile == null) {Log.e (TAG, "Feil ved oppretting mediefil, er lagring tillatelser riktig?"); returnere null; } Byte [0] photoData = data [0]; try {Fileoutputstream fos = new Fileoutputstream (picFile); fos.write (photoData); fos.close (); } Catch (FileNotFoundException e) {Log.e (TAG, "Finner ikke fil:" + e.getMessage ()); e.getStackTrace (); } Catch (IOException e) {Log.e (TAG, "I /O feil med filen:" + e.getMessage ()); e.getStackTrace (); } Returnere null; }} 

    Legg merke til at du trenger for å få ett utvalg photoData ut av multi-dimensjonale array-data før du kan skrive det til filen. Ellers er det den samme koden nettopp flyttet inn i en egen klasse og tråd. Kjøre den, så sjekk ut lagrede bilder med filbehandling.

    Det er mange forbedringer du kan gjøre for å dette programmet; kameraer har mange forskjellige evner, for eksempel. I ytterligere tutorials vil vi se på å ta video og ved å legge til alternativer for flash og andre kamerafunksjoner. Anmeldelser