2016-09-27 16 views
1

Я разработал класс ниже для получения изображения, отправленного с заголовком (22 байта). Сначала я декодирую заголовок, чтобы проверить правильность изображения, а затем декодировать изображение, но не все изображения декодируются, иногда они возвращаются с SkImageDecoder::Factory returned null. Я использую this учебник для Android до inSampleImage.Иногда растровое декодирование возвращает SkImageDecoder :: Factory возвращает null и отображает поврежденное изображение

public class SocketServerStreamDataThread extends Thread { 

    private Socket streamSocket; 
    MainActivity mainActivity ; 
    ImageView displayedImage ; 

    Bitmap bitmapImageToDisplay = null; 
    byte[] dataBuffer = new byte[1048576]; 

    boolean result ; 

    protected static boolean mReceivingStop; // Flag used to start and stop transmitting data 

    SocketServerStreamDataThread(Socket socket, MainActivity mainActivityReceived, ImageView displayedImageView) { 
     streamSocket = socket; 
     // received activity to work on it in our java file 
     mainActivity = mainActivityReceived ; 
     // received image UI component to display 
     displayedImage = displayedImageView; 
    } 

    @Override 
    public void run() { 
     /* Receiving the image */ 
     try { 
      DecodeData decodeData = new DecodeData(); 
      // call DecodeData to get Image data from stream 
      while (mReceivingStop == false) { 
       if (bitmapImageToDisplay == null) { 
        InputStream inputStream = streamSocket.getInputStream(); 
        if (inputStream.read(dataBuffer) > -1) { 
         // Call the class to decode received stream and return integer with the state of the decoding of the received data 
         // result = 0 ; means that decoding header is successful. 
         // result = -1 ; means that there is a problem in decoding header. 
         byte [] dataHeaderReceived = Arrays.copyOf(dataBuffer, 23) ; 
         result = decodeData.iDecodeReceiveData(dataHeaderReceived); 
         // Evalute the received data 
         if (result == false) { 
          /* Fault on application */ 
          /* Close socket */ 
          streamSocket.close(); 
          mReceivingStop = true; 
         } 

         if (result == true) { 
          /* Data have been received */ 
          /* Show image */ 
          BitmapFactory.Options imageOption = new BitmapFactory.Options(); 
          imageOption.inJustDecodeBounds = true; 
          BitmapFactory.decodeResource(mainActivity.getResources(), R.id.display_image, imageOption); 
          imageOption.inSampleSize = calculateInSampleSize (imageOption, 550, 435) ; 
          imageOption.inJustDecodeBounds = false; 
          bitmapImageToDisplay = BitmapFactory.decodeByteArray(dataBuffer, 23, decodeData.imageSize, imageOption); 

          if (bitmapImageToDisplay != null) { 
           mainActivity.runOnUiThread(new Runnable() { 
            @Override 
            public void run() { 
             //try to display to image 
             displayedImage.setImageBitmap(bitmapImageToDisplay); 
            } 
           }); 
          } 
         } 
        } 
        SystemClock.sleep(300); 
        bitmapImageToDisplay = null ; 
       } 
      } 
      streamSocket.close(); 
      mReceivingStop = true; 

      mainActivity.runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        Toast.makeText(mainActivity, "Finished", Toast.LENGTH_LONG).show(); 
       } 
      }); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      StringBuilder eMsg = new StringBuilder(); 
      eMsg.append("Something wrong: " + e.getMessage()); 
      final String eMessage=eMsg.toString(); 
      // final String eMsg = "Something wrong: " + e.getMessage(); 

      mainActivity.runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        Toast.makeText(mainActivity, eMessage, Toast.LENGTH_LONG).show(); 
       } 
      }); 
     } finally { 
      if(streamSocket != null){ 
       try { 
        streamSocket.close(); 
        mReceivingStop = true ; 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

Logcat выход:

GC_FOR_ALLOC freed 1307K, 27% free 13676K/18596K, paused 34ms, total 34ms 
D/dalvikvm: GC_FOR_ALLOC freed 1306K, 27% free 13676K/18596K, paused 8ms, total 8ms 
D/skia: --- SkImageDecoder::Factory returned null 
D/skia: --- SkImageDecoder::Factory returned null 
D/dalvikvm: GC_FOR_ALLOC freed 1607K, 29% free 13376K/18596K, paused 24ms, total 24ms 
D/skia: --- SkImageDecoder::Factory returned null 
D/dalvikvm: GC_FOR_ALLOC freed 1255K, 27% free 13728K/18596K, paused 9ms, total 9ms 
+0

Я использовал SystemClock.sleep (300); чтобы дать время для процесса декодирования, как раньше он не ловил для декодирования, и появилось сообщение об ошибке декодирования false – zelf

+0

Что такое 'DecodeData'? И откуда вы получаете 'resId'? – Bryan

+0

DecodeData - это класс для декодирования заголовка полученного изображения, чтобы получить атрибуты изображения, чтобы узнать размер изображения – zelf

ответ

0

Загрузка растровых изображений на Android является большой и довольно сложная тема. Именно поэтому я рекомендую использовать одну из проверенных библиотек для ее обработки; таких как Glide, Picasso или Fresco. Эти библиотеки будут обрабатывать многие проблемы, связанные с загрузкой растровых изображений для вас; включая ограничения памяти, кеширование и потоки.


Если вы действительно хотите отправиться в одиночку, вам придется столкнуться с этими проблемами самостоятельно. SkImageDecoder::Factory returned null - это то, что методы BitmapFactory.decode... выплюснут, если растровое изображение невозможно правильно декодировать, что может быть вызвано рядом проблем. Я не знаю точно, что вызывает это, но я вижу ряд проблем в вашем коде.

Во-первых, вы передаете MainActivity в Thread, это просто просит неприятностей. Вместо этого вам нужно только передать ImageView в Thread. И убедитесь, что вы используете WeakReference, в противном случае вы рискуете протечки ваш Context:

WeakReference<ImageView> mDisplayedImageView; 

SocketServerStreamDataThread(Socket socket, ImageView imageView) { 
    mDisplayedImageView = new WeakReference<>(imageView); 
    ... 
} 

Далее вы используете Drawable ресурс для декодирования границы с Bitmap, но вы пытаетесь получить Bitmap от Socket подключение. Вместо этого вы должны декодировать границы с помощью InputStream:

BufferedInputStream inBounds = new BufferedInputStream(streamSocket.getInputStream()); 

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 
BitmapFactory.decodeStream(inBounds, null, options); 

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

inBounds.close(); 

И вам не нужно будет иметь отдельный DecodeData класс, так как BitmapFactory имеет метод для декодирования потока, а также:

options.inJustDecodeBounds = false; 

BufferedInputStream in = new BufferedInputStream(streamSocket.getInputStream()); 

Bitmap bitmap = BitmapFactory.decodeStream(in, null, options); 

in.close(); 

Наконец, если вы используете Thread.sleep() или SystemClock.sleep(), чтобы преодолеть какое-то препятствие, вы должны, вероятно, переосмыслить свое решение. Это лишь те проблемы, которые я заметил при быстром просмотре. Если вы действительно хотите продолжить работу без помощи библиотеки, я предлагаю сделать еще несколько исследований о том, как эффективно загружать растровые изображения; хорошей отправной точкой является the documentation.

+0

за вашу помощь, но сначала полученное изображение добавлено с 22 специальным заголовком байта, который необходимо декодировать, чтобы я использовал DecodeData класс он не может быть декодирован с помощью BitmapFactory, поэтому мне нужно сначала прочитать первые 22 байта для чтения специальных данных. Во-вторых, я использую «SystemClock.sleep()» для преодоления этой проблемы, что я не могу найти ее источник. Также я передаю «MainActivity» для использования «runOnUiThread». Я не знаю о «WeakReference». Я буду искать его если это решение. – zelf

+0

У меня вопрос: есть ли в Picasso или Glide декодер изображения внутри вместо «BitmapFactory.decode»? – zelf

+1

Насколько я знаю, Picasso, Glide и Fresco используют методы «BitmapFactory.decode ...» для декодирования изображений, они не содержат отдельных декодеров. – Bryan