2016-09-27 100 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);給解碼過程留出時間,就像之前沒有捕獲到解碼並且解碼返回錯誤消息出現 – zelf

+0

什麼是DecodeData?你從哪裏得到一個「resId」? – Bryan

+0

DecodeData是解碼接收圖像頭的類,以獲取圖像屬性也知道圖像大小 – zelf

回答

0

在Android上加載的位圖是一個龐大而相當複雜的話題。這就是爲什麼我建議使用一個經過驗證的庫來爲你處理它;如Glide,PicassoFresco。這些庫將處理加載位圖時出現的許多缺陷;包括內存限制,緩存和線程。


如果你真的想一個人去,你將不得不自己面對這些問題。 SkImageDecoder::Factory returned nullBitmapFactory.decode...方法吐出的位圖無法正確解碼的問題,這可能是由許多問題引起的。我不知道究竟是什麼導致了這種情況,但我確實在代碼中看到了一些問題。

首先,您將MainActivity傳入Thread,這只是要求麻煩。相反,您只需要將ImageView轉換爲Thread即可。並確保您使用的是WeakReference,否則你可能會泄露你的Context

WeakReference<ImageView> mDisplayedImageView; 

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

接下來,您使用的是繪製資源到Bitmap的範圍進行解碼,但你正試圖從一個Socket獲得Bitmap連接。相反,你應該使用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

我有一個問題,畢加索或滑翔包括一個圖像解碼器,而不是'BitmapFactory.decode'? – zelf

+1

就我所知畢加索,Glide和Fresco都使用'BitmapFactory.decode ...'方法來解碼圖像,它們不包含單獨的解碼器。 – Bryan