2016-01-20 22 views
11

Attualmente codifico e decodifico le immagini su Base64. Ho superato il problema iniziale con OOM con l'uso di stream per codificare le immagini in stringhe.Caricamento/download di immagini Android con Base64 in JSON causa Errore memoria insufficiente

Il mio problema ora è che non riesco a capire come aggiungere più stringhe con codifica Base64 per più risoluzioni di immagini (5620 x 3747 - 4,92 MB o 3264 x 1836 - 1,35 MB) a un oggetto JSON tramite Gson. Attualmente Gson lancia un'eccezione OOM solo con 2 stringhe Base64 da un'immagine 5312 x 2988 - 4,95 MB.

Capisco che Android possa risparmiare solo 16/20 Mb per applicazione, quindi questa conversione deve superare il limite.

Come posso scrivere la stringa Base64 in un flusso su un oggetto JSON che conterrà i valori specifici necessari per caricare nel mio server?

Sarebbe più semplice cambiare il mio server per accettare una richiesta di più parti invece di un POJO basato su JSON con più stringhe Base64? Al momento utilizzo Volley e non esiste una richiesta multi-parte ufficiale né lo streaming IO.

Se si tratta di compressione, quanta compressione devo applicare all'immagine prima della codifica in una stringa Base64? Preferisco idealmente perdere ogni qualità, ma ho livelli di compressione ottimali.

qualche informazione in più

sto caricando immagini multiple di risoluzione differenti in quanto è un test per la compatibilità. Ad esempio, tutte le immagini che sto inviando sono state scattate su dispositivi a bassa risoluzione e ad altissima risoluzione poiché la mia app si basa su queste immagini per funzionalità. Sto cercando di dimostrare che qualsiasi immagine (in una certa misura, principalmente immagini acquisite su dispositivi mobili) può essere gestita dalla mia applicazione.

Capisco che alcune immagini potrebbero essere così grandi che caricandole in memoria causeranno delle eccezioni. Questo è qualcosa che proverò a gestire più tardi.

In alcuni casi le immagini che verranno caricati possono estendersi da 1 a 200.

sto cercando di cercare la soluzione più ottimale in grado di scalare bene.

+0

Se si desidera utilizzare Mutipart Request con Volley, IMO, è possibile fare riferimento al mio codice di esempio all'indirizzo https://github.com/ngocchung/VolleyNoApache/blob/master/app/src/main/java/com/example/ volleynoapache/MultipartActivity.java. Nella risposta @ kevinkl3, http://stackoverflow.com/a/16803473/3393666 ho avuto anche una risposta – BNK

risposta

2

Ho guardato in utilizzando Volley come un meccanismo per il trasporto di oggetti di grandi dimensioni JSON a un server e pensano che questa answer. Questa risposta dimostrò essenzialmente che Volley sarebbe stata una cattiva idea per quello che volevo.

Sono passato a OkHttp e ora uso i loro metodi di streaming che consentono al JSON di essere trasmesso in streaming al server e quindi leggere la risposta con un approccio semplificato. Ho usato la libreria GSON per analizzare la risposta in quanto OKHttp consente alla risposta JSON/Object di essere trasmessa in streaming in un oggetto lettore che Gson quindi utilizza per lo streaming interno e l'analisi di una classe POJO.

L'unica ragione per cui non sono passato a una richiesta di più parti era dovuta al fatto che l'implementazione del lato server era rigida e non modificabile per coprire richieste Multipart, si aspettava una rappresentazione JSON di dati e file.

Per la movimentazione Immagini Base64 su Android ho gravemente raccomando non utilizzando il String rappresentanza e solo la conversione in Bytes per risparmiare sull'uso di una quantità eccessiva di memoria. Ho letto l'articolo this sull'utilizzo e la gestione della memoria String. Con i byte è possibile trasportare facilmente i dati senza lasciare un ingombro enorme sulla memoria.

Per la visualizzazione delle immagini Evito ancora la conversione da byte a String utilizzando la libreria di immagini Glide. Ti permettono di passare in un byte[] che era di enorme convenienza.

2

... per immagini multiple risoluzioni (5620 x 3747 - 4.92MB o 3264 x 1836 - 1.35MB) ...

Non sono sicuro se questa è la dimensione del file o la memoria necessaria per allocare l'immagine nella memoria, ma dare un'occhiata al seguente link: http://www.scantips.com/basics1d.html, vedo questo:

Per un'immagine 4000 x 2500 pixel,

poi: 4000 x 2500 pixel = 4000x2500 = 10 megapixel

4000x2500 x 3 = 30 milioni di byte (se 24-bit RGB)

30.000.000 byte/(1024 x 1024) = 28.61 megabyte (MB)

questo è semplicemente quanto grande i dati sono - Per QUALSIASI immagine da 24-bit 10 megapixel , ma i file JPG lo comprimono più piccolo (solo mentre si trova nel file).

Penso che le immagini che stai gestendo abbiano molta più memoria di quanto ti aspetti.

Inoltre, dando uno sguardo a questa domanda e la risposta: https://stackoverflow.com/a/11402374/3393666, sappiamo che una rappresentazione base64 di un'immagine prende fino al 37% in più di memoria rispetto alla dimensione originale dell'immagine.

Come posso scrivere la stringa Base64 in un flusso su un oggetto JSON che conterrà i valori specifici necessari per caricare nel mio server?

Penso che si possa fare questo (con piccole immagini non grandi) semplicemente aggiungendo la rappresentazione base64 dell'immagine in un oggetto JSON e quindi postandola sul server.

Sarebbe più semplice cambiare il mio server per accettare una richiesta di più parti invece di un POJO basato su JSON con più stringhe Base64?

Secondo me, sarebbe la soluzione migliore per implementare ciò che stai cercando di ottenere.

Attualmente utilizzo Volley e non vi è una richiesta multiparte ufficiale né uno streaming IO.

Si può dare un'occhiata a questa risposta: https://stackoverflow.com/a/16803473/3393666, si può sicuramente può farlo con tiro al volo, ma se si vuole un'alternativa si può provare con retrofit (http://square.github.io/retrofit/) che sostenere la nostra Multipart della scatola.

esempio:

@Multipart 
@PUT("user/photo") 
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);