2016-02-05 33 views
8

nella mia app backend Engine Ho un metodo che ottiene un'immagine da Google Cloud StorageInvia i dati delle immagini per android app da App Engine

@ApiMethod(
     name = "getProfileImage", 
     path = "image", 
     httpMethod = ApiMethod.HttpMethod.GET) 
public Image getProfileImage(@Named("imageName")String imageName){ 
    try{ 
     HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); 
     GoogleCredential credential = GoogleCredential.getApplicationDefault(); 

     Storage.Builder storageBuilder = new Storage.Builder(httpTransport,new JacksonFactory(),credential); 
     Storage storage = storageBuilder.build(); 

     Storage.Objects.Get getObject = storage.objects().get("mybucket", imageName); 

     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     // If you're not in AppEngine, download the whole thing in one request, if possible. 
     getObject.getMediaHttpDownloader().setDirectDownloadEnabled(false); 
     getObject.executeMediaAndDownloadTo(out); 

     byte[] oldImageData = out.toByteArray(); 
     out.close(); 

     ImagesService imagesService = ImagesServiceFactory.getImagesService(); 

     return ImagesServiceFactory.makeImage(oldImageData); 
    }catch(Exception e){ 
     logger.info("Error getting image named "+imageName); 
    } 
    return null; 
} 

il problema che sto avendo è come faccio ad ottenere i dati dell'immagine quando chiamo quello nella mia app per Android?

Poiché non è possibile restituire le primitive dal motore di app, l'ho convertito in un Image in modo da poter chiamare getImageData() nella mia app per ottenere il byte [].

Tuttavia, l'oggetto Immagine restituito all'app non è uguale a quello nel motore di app, quindi non esiste getImageData().

Come posso ottenere i dati delle immagini sulla mia app Android?

Se creo un oggetto contenente una variabile byte [], quindi imposto la variabile byte [] con i dati stringa e restituisco quell'oggetto dal metodo funzionerà?

Aggiornamento

L'immagine viene inviato dal app Android. (Questo codice può o non può essere corretto, non ho ancora il debug esso)

@WorkerThread 
    public String startResumableSession(){ 
     try{ 
      File file = new File(mFilePath); 
      long fileSize = file.length(); 
      file = null; 
      String sUrl = "https://www.googleapis.com/upload/storage/v1/b/lsimages/o?uploadType=resumable&name="+mImgName; 
      URL url = new URL(sUrl); 
      HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection(); 
      urlConnection.setRequestProperty("Authorization",""); 
      urlConnection.setRequestProperty("X-Upload-Content-Type","image/png"); 
      urlConnection.setRequestProperty("X-Upload-Content-Length",String.valueOf(fileSize)); 
      urlConnection.setRequestMethod("POST"); 

      if(urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK){ 
       return urlConnection.getHeaderField("Location"); 
      } 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private long sendNextChunk(String sUrl,File file,long skip){ 
     int bytesRead, bytesAvailable, bufferSize; 
     byte[] buffer; 
     int maxBufferSize = 524287; 
     long totalBytesSent = 0; 
     try{ 
      long fileSize = file.length(); 
      FileInputStream fileInputStream = new FileInputStream(file); 
      skip = fileInputStream.skip(skip); 

      bytesAvailable = fileInputStream.available(); 
      bufferSize = Math.min(bytesAvailable, maxBufferSize); 
      totalBytesSent = skip + bufferSize; 
      buffer = new byte[bufferSize]; 

      bytesRead = fileInputStream.read(buffer, 0, bufferSize); 
      try { 
       while (bytesRead > 0) { 

        try { 
         URL url = new URL(sUrl); 
         HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection(); 
         urlConnection.setDoInput(true); 
         urlConnection.setDoOutput(true); 
         urlConnection.setUseCaches(false); 
         urlConnection.setChunkedStreamingMode(524287); 
         urlConnection.setRequestMethod("POST"); 
         urlConnection.setRequestProperty("Connection", "Keep-Alive"); 
         urlConnection.setRequestProperty("Content-Type","image/png"); 
         urlConnection.setRequestProperty("Content-Length",String.valueOf(bytesRead)); 
         urlConnection.setRequestProperty("Content-Range", "bytes "+String.valueOf(skip)+"-"+String.valueOf(totalBytesSent)+"/"+String.valueOf(fileSize)); 

         DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream()); 
         outputStream.write(buffer, 0, bufferSize); 

         int code = urlConnection.getResponseCode(); 

         if(code == 308){ 
          String range = urlConnection.getHeaderField("Range"); 
          return Integer.parseInt(range.split("-")[1]); 
         }else if(code == HttpURLConnection.HTTP_CREATED){ 
          return -1; 
         } 

         outputStream.flush(); 
         outputStream.close(); 
         outputStream = null; 
        } catch (OutOfMemoryError e) { 
         e.printStackTrace(); 
//      response = "outofmemoryerror"; 
//      return response; 
         return -1; 
        } 
        fileInputStream.close(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
//    response = "error"; 
//    return response; 
       return -1; 
      } 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
     return -1; 
    } 

Edit 2:

A quanto pare la sua non è chiaro alla gente che sto usando endpoint nella mia app Android

+0

io di solito uso Python in modo da non so lo si fa in Java, ma si può solo restituire l'URL immagine del profilo generato da Google Cloud Storage invece di restituire la matrice di byte. In questo modo, è possibile memorizzare nella cache l'URL del profilo per evitare di ricostruirlo tutto il tempo. –

+0

Come @ Maël ha detto che non è necessario trasferire l'intera immagine attraverso il proprio stack (per motivi di prestazioni ma anche per ridurre i costi).Crei il tipo di immagine? Se sì, puoi postare la sua fonte? –

+0

@ BenoîtSauvère le immagini provengono dall'app per android, ho aggiornato la domanda con quel codice. Per ottenere l'URL dell'immagine non devo scaricare comunque i dati dell'immagine? Quindi essenzialmente scaricherò i dati dell'immagine due volte, una volta sul server solo per ottenere l'Url di servizio e di nuovo sull'app client. Non sarebbe più inefficiente (costo) che ottenere i dati delle immagini dal server? Una volta che l'app per Android ottiene i dati dell'immagine il mio piano era di memorizzare l'immagine localmente in cache (salvarla su disco) in modo che non debba andare a prenderla nuovamente – tyczj

risposta

1

Quello che ho finito per fare/scoprire che è necessario chiamare execute() sulla chiamata API con endpoint e restituisce i dati reali passati indietro dal API

esempio

la chiamata API ritorna Image

public Image getProfileImage(@Named("id") long id, @Named("imageName")String imageName){ 
     try{ 
      ProfileRecord pr = get(id); 
      HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); 
      GoogleCredential credential = GoogleCredential.getApplicationDefault(); 

      Storage.Builder storageBuilder = new Storage.Builder(httpTransport,new JacksonFactory(),credential); 
      Storage storage = storageBuilder.build(); 

      Storage.Objects.Get getObject = storage.objects().get("mybucket", imageName); 

     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     // If you're not in AppEngine, download the whole thing in one request, if possible. 
     getObject.getMediaHttpDownloader().setDirectDownloadEnabled(false); 
     getObject.executeMediaAndDownloadTo(out); 

     byte[] oldImageData = out.toByteArray(); 
     out.close(); 
     return ImagesServiceFactory.makeImage(oldImageData); 
    }catch(Exception e){ 
     logger.info("Error getting image named "+imageName); 
    } 
    return null; 
} 

poi sul lato client vorrei chiamare in questo modo per farlo

Image i = pr.profileImage(id,"name.jpg").execute(); 
byte[] data = i.decodeImageData(); 
-1

È possibile utilizzare Google cloud Endpoint per questo:

Google cloud endpoint consiste di strumenti, librerie e le capacità tha t consentono di generare API e librerie client da un'applicazione del motore dell'applicazione , indicata come back-end API, per semplificare l'accesso del client ai dati da altre applicazioni. Endpoint rende più semplice il creare un back-end Web per client Web e client mobili come Android o iOS di Apple.

vedere https://cloud.google.com/appengine/docs/java/endpoints/

+0

che è quello che sto usando quindi non hai davvero risposto alla mia domanda – tyczj

+0

Mi dispiace davvero che il mio tentativo di aiutarti non fosse per la tua soddisfazione. Forse menzionare Endpoint nella tua domanda o tag avrebbe potuto evitare la mia intollerabile interpretazione errata. – robert