2016-02-05 10 views
8

W moim App Engine backend Mam metodę, która pobiera obraz z Google Cloud StorageWysyłanie danych obrazowych do android aplikacji z 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; 
} 

problem mam jest w jaki sposób uzyskać dane obrazu, gdy zgłoszę to w mojej aplikacji na Androida?

Ponieważ nie można zwrócić prymitywów z silnika aplikacji, przekonwertowałem go na Image, dzięki czemu mógłbym wywołać w mojej aplikacji getImageData(), aby uzyskać bajt [].

Jednak obiekt Obraz, który został zwrócony do aplikacji, nie jest tym samym, co obiekt w silniku aplikacji, więc nie ma metody getImageData().

Jak mogę uzyskać dane obrazu do mojej aplikacji na Androida?

Jeśli utworzę obiekt o zmiennej bajtowej [], ustawię zmienną byte [] z danymi ciągu i zwrócę obiekt z metody, która będzie działać?

Aktualizacja

Obraz zostaje wysłany z aplikacji na Androida. (Kod ten może lub nie może być poprawne, ja nie debugowany go jeszcze)

@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:

Widocznie jej nie jasne dla ludzi, że używam punktów końcowych w moim Android app

+0

Zwykle używam Python więc nie wiem, to zrobić w Javie, ale może po prostu wrócić url obraz wygenerowany profil z Google Cloud Storage zamiast zwracać tablicę bajtów. W ten sposób można buforować adres URL profilu, aby uniknąć jego odbudowy przez cały czas. –

+0

As @ Maël powiedział, że nie powinieneś przenosić całego obrazu przez stos (ze względu na wydajność, ale także w celu zmniejszenia kosztów).Czy tworzysz typ obrazu? Jeśli tak, czy możesz opublikować jego źródło? –

+0

@ BenoîtSauvère obrazy pochodzą z aplikacji na Androida, zaktualizowałem pytanie tym kodem. Aby uzyskać adres URL obrazu, muszę mimo wszystko pobrać dane obrazu? Zasadniczo chciałbym pobrać dane obrazu dwukrotnie, raz na serwerze, aby uzyskać adres URL do wyświetlania i ponownie w aplikacji klienckiej. Czy nie byłoby to bardziej nieefektywne (kosztowne) niż tylko uzyskiwanie danych obrazu z serwera? Gdy aplikacja na Androida otrzyma dane obrazu, mój plan polegał na buforowaniu obrazu lokalnie (zapisanie go na dysku), aby nie musiała go już odzyskiwać. – tyczj

Odpowiedz

1

Co skończyło się robi/dowiedzieć się, że trzeba zadzwonić execute() na wywołanie API z punktami końcowymi i zwraca rzeczywiste dane przekazane z powrotem z API

przykład

powraca wywołanie API 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; 
} 

następnie po stronie klienta nazwałbym go tak, aby to

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

można użyć Google cloud Endpoints na to:

Google cloud Punkty końcowe składa się z narzędzi, bibliotek i możliwości Tha t umożliwia generowanie interfejsów API i bibliotek klienckich z aplikacji App Engine, określanej jako backend interfejsu API, w celu uproszczenia dostępu klienta do danych z innych aplikacji za pomocą klienta . Punkty końcowe ułatwiają tworzenie backendu internetowego dla klientów internetowych i klientów mobilnych, takich jak Android lub Apple iOS.

zobaczyć https://cloud.google.com/appengine/docs/java/endpoints/

+0

którego używam więc tak naprawdę nie odpowiedziałeś na moje pytanie – tyczj

+0

Naprawdę przykro mi, że moja próba pomocy nie była dla ciebie satysfakcjonująca. Może wspomnienie Punktów Końcowych w pytaniu lub tagach mogłoby uniknąć mojej nietolerancyjnej błędnej interpretacji. – robert

Powiązane problemy