Carica arraylist usando httpurlconnection multipart / form-data


11

Devo caricare Arraylistimmagini sul server senza usare alcuna libreria. Sto usando Asynctaskper caricare una singola immagine e funziona perfettamente con l'aiuto di httpurlconnection multipart / form-data. Ora ho bisogno di cambiare il mio codice per caricare più file di qualsiasi tipo usando Arraylist<String>ma il mio problema è che il codice esistente FileinputStreamnon supporta l'arraylist e non ho idea di cosa usare invece di Fileinputstreamcaricare l'arraylist sul server e non vuoi usare qualsiasi libreria anche per questo.

public class multipart_test extends AsyncTask<Void,Void,String> {
    Context context;
    String Images;
    public static final String TAG = "###Image Uploading###";


    public multipart_test(Context context,String Upload_Images) {
        this.context = context;
        this.Images = Upload_Images;

    }

    @Override
    protected String doInBackground(Void... params) {
        BufferedReader reader;
        String WebPath = null;
        try {
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "*****";
            int bytesRead, bytesAvailable, bufferSize;
            byte[] buffer;
            int maxBufferSize = 1024 * 1024;
            //todo change URL as per client ( MOST IMPORTANT )
            URL url = new URL("10.0.0.1/uploadMultipart.php");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // Allow Inputs &amp; Outputs.
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);

            // Set HTTP method to POST.
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            FileInputStream fileInputStream;
            DataOutputStream outputStream;
            outputStream = new DataOutputStream(connection.getOutputStream());
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);

            outputStream.writeBytes("Content-Disposition: form-data; name=\"reference\""+ lineEnd);
            outputStream.writeBytes(lineEnd);
            //outputStream.writeBytes("my_refrence_text");
            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);

            outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadFile\";filename=\"" + "profileImage" +"\"" + lineEnd);
            outputStream.writeBytes(lineEnd);

            //Dummy ArrayList for upload
            ArrayList<String> uploadFiles = new ArrayList<>();
            uploadFiles.add(Images);
            uploadFiles.add(Images);
            uploadFiles.add(Images);
            uploadFiles.add(Images);


            fileInputStream = new FileInputStream(uploadFiles); // NOT SUPPORTING ARRAYLIST HERE
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // Read file
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            while (bytesRead > 0) {
                outputStream.write(buffer, 0, bufferSize);
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
                fileInputStream.close();
            }
            // Responses from the server (code and message)
            int serverResponseCode = connection.getResponseCode();
            String result = null;
            if (serverResponseCode == 200) {
                StringBuilder s_buffer = new StringBuilder();
                InputStream is = new BufferedInputStream(connection.getInputStream());
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String inputLine;
                while ((inputLine = br.readLine()) != null) {
                    s_buffer.append(inputLine);
                }
                result = s_buffer.toString();
            }
            connection.getInputStream().close();
            outputStream.flush();
            outputStream.close();
            if (result != null) {
                Log.d("result_for upload", result);
            }
            return WebPath;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}

Ho anche provato a mettere FileInputStreamin loop ma caricare immagini in una richiesta multipla non è quello che voglio. L'app del mio server richiede l'applicazione singola per n numero di immagini. Qualsiasi aiuto sarebbe apprezzato ma senza l'uso di alcuna libreria


Le classi Http sono obsolete, utilizzano retrofit o altre librerie
Jaiprakash Soni il

puoi utilizzare il retrofit e caricare più immagini in un'unica richiesta
Priyankagb,

Risposte:


4

NOTA che non ho provato se questo codice funziona in modo accurato con HttpURLConnection ma dovrebbe.

Da quello che ho letto da Internet puoi ancora usare quel ciclo che hai citato ma con alcune modifiche.

Ho seguito il tutorial su multipart / form-data qui dev.to , per rendere questo più di un post di apprendimento ti dirò quale è questo metodo che dovrebbe accadere.

I dati multipart / form vengono inviati in questo modo

--boundary
Content-Disposition: form-data; name="something1"

data1
--boundary
Content-Disposition: form-data; name="something2"

data2
--boundary--

Quello che vorrei fare è creare un nuovo metodo ma puoi semplicemente scrivere il codice nel tuo metodo già esistente.

public byte[] get_multipart_data(List<String> files, String boundary)

Si desidera scrivere è il limite seguito dalla disposizione e quindi dai dati . Fatelo per tutti i file e poi inviate il limite di chiusura . Ciò genererà la struttura multipart / form-data desiderata.

In psudo-codice questo sarebbe

loop for all files
    write "--boundary"
    write "Content-Disposition: ...."
    write image_data
end
write "--boundary--"

Il codice potrebbe essere scritto in questo modo, prima di definire le variabili

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

int maxBufferSize = 1024 * 1024;
byte[] buffer = new byte[maxBufferSize];
byte[] sendData = new byte[0];

Qui è dove verranno generati i dati. Si inizia concatenando il confine e quindi leggendo i dati. I dati vengono scritti nello stream e si continua il ciclo per tutti i file / immagini.

try {
    message = new ByteArrayOutputStream();
    stream = new DataOutputStream(message);

    // Loop though all file names
    for(String fileName : files) {
        stream.writeBytes("--" + boundary + "\r\n"); // Start boundary
        stream.writeBytes("Content-Disposition: form-data; name=\"" + fileName + "\"\r\n\r\n");

        // Read the image data
        fileInputStream = new FileInputStream(fileName);
        int readBytes = 0;
        while((readBytes = fileInputStream.read(buffer)) != -1) {
            // Write file data to output
            stream.write(buffer, 0, readBytes);
        }
        fileInputStream.close();

        stream.writeBytes("\r\n");
    }
    stream.writeBytes("--" + boundary + "--\r\n"); // Closing boundary

    sendData = message.toByteArray();
} catch(IOException e) {
    e.printStackTrace();
}

Ora l'array di byte sendDataconterrà i dati multipart / form che è necessario inviare con HttpURLConnection.

Non sono stato così attivo qui per molto tempo. Dimmi se hai bisogno di ulteriori specifiche o se chiarisco il mio testo: D


Se eseguo il loop, allora devo fare più richieste per il caricamento dell'array. Devo caricare un array sul server in una sola chiamata.
Ritu,

Da quello che ho sottolineato è che vuoi inviare n immagini al server in una singola chiamata HttpURLConnection. Puoi provare a utilizzare un formato zip in cui inserisci i file con ZipEntry, altrimenti ciò che ho scritto sarà solo una richiesta. @Ritu
HardCoded

È possibile per te che usi un loop esterno al tuo asincrono? Ad esempio, se hai 3 file per il caricamento, esegui 3 asynctask in modo indipendente. In questo modo se viene riscontrato un problema o un'immagine per un'immagine (processo di caricamento), altre immagini (processi) continuano a caricarsi. contare da un contatore nella tua classe e mantenere un ritardo (tempo stimato) se necessario (per avvisare che esiste un problema durante il caricamento).
maniaq

1
@maniaq non è un codice ottimale per eseguire più asynctask per la stessa attività. Dovremmo evitare le chiamate di rete ovunque possibile.
androidXP il

0

FileinputStream non supporta ArrayList. Ma c'è un modo per aggirare utilizzando ObjectOutputStream . Serializzerà anche la tua ArrayList. Controlla le modifiche nel codice.

       //Changes required in your code
        ArrayList<String> uploadFiles = new ArrayList<>();
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);

        fileInputStream = new FileInputStream("listImages"); 
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fileInputStream); 
        oos.writeObject(uploadFiles);

        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];
        ...
        ...
        ...
        oos.close();

Happy Coding :)


0

Non sono sicuro se l'utilizzo di una singola attività asincrona sia indispensabile per te.

Come hai detto, il tuo codice funziona perfettamente per una singola immagine. Quindi per caricare più file dall'arraylist devi semplicemente modificare un po 'il tuo AsyncTask. Carica semplicemente un file dopo l'altro O se non vuoi nemmeno fare troppe modifiche, dichiara semplicemente la variabile globale che contiene l'indice dell'elemento che viene caricato e in OnPostExecute crea una nuova istanza dell'attività asincrona e passa l'elemento successivo nell'arraylist. Spero sia chiaro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.