BitmapFactory.decodeStream方法及如何將Raw中的圖片載入為Bitmap
阿新 • • 發佈:2018-11-10
結論
將輸入流傳遞給 BitmapFactory.decodeStream(in) 方法,建立完成 Bitmap 之後,開發者一定要主動去關閉這個輸入流。否則,對輸入流執行 reset() 方法,則可以重新獲取輸入流中的所有資料,並且創建出一張新的圖片。
從res-raw目錄下獲取一張Bitmap圖片(工具類)
public static @Nullable Bitmap loadBitmapFromRawResource(@NonNull Context context, @RawRes int id) { InputStream inputStream = null; try { inputStream = context.getResources().openRawResource(id); Bitmap rawBitmap = BitmapFactory.decodeStream(inputStream); return rawBitmap; } catch (Exception e) { e.printStackTrace(); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { } } return null; }
下面是測試用例及詳細異常
測試用例說明
1、從raw目錄下獲取一個輸入流
2、使用這個輸入流建立一張Bitmap圖片,並且丟棄之
3、根據 System.currentTimeMillis() % 2 是否為0,決定是否關閉這個輸入流
4、reset上面的輸入流
5、使用上面reset過的輸入流再建立一張Bitmap圖片
6、返回第二次建立的Bitmap圖片,並關閉輸入流
測試用例(異常程式碼)
public static @Nullable Bitmap loadBitmapFromRawResource(@NonNull Context context, @RawRes int id) { InputStream inputStream = null; try { inputStream = context.getResources().openRawResource(id); //第一次從流中建立圖片 Bitmap rawBitmap = BitmapFactory.decodeStream(inputStream); /*********************************************************/ /*模擬 decodeStream 之後,開發者是否記得主動關閉輸入流的兩種情況*/ if (System.currentTimeMillis() % 2 == 0){ try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { } } /*********************************************************/ //1、如果,僅將 inputStream 直接丟給 BitmapFactory.decodeStream 方法,下面執行 inputStream.reset() 可以重新獲取流中所有資料,並創建出正常的 Bitmap 圖片。 //2、如果,在 BitmapFactory.decodeStream 讀取完成之後,呼叫 inputStream.close() 方法。下面執行 reset() 方法時,會報 // "java.lang.NullPointerException: asset at android.content.res.AssetManager.seekAsset(Native Method) at android.content.res.AssetManager.-wrap4(Unknown Source:0)" 異常 //結論:BitmapFactory.decodeStream 處理完流之後,輸入流一定記得關。各位,一定記得關流啊! try { inputStream.reset(); }catch (Exception e){ e.printStackTrace(); } //第二次從流中建立圖片 //如果開發者忘記關流,第二次可以建立成功。 //如果開發都把已經關閉的流交給 decodeStream 來解析,應用將直接閃退。try-catch也沒有用。異常資訊是: //"/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 25381 (RxIoScheduler-5)" Bitmap testRawBitmap = BitmapFactory.decodeStream(inputStream); TestToastUtil.toastAll("" + testRawBitmap); return testRawBitmap; } catch (Throwable e) { e.printStackTrace(); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { } } return null; }
對已經close的InputStream執行reset方法,產生的異常
10-19 17:08:52.542 22783-22961/cn.dxy.android.aspirin W/System.err: java.lang.NullPointerException: asset at android.content.res.AssetManager.seekAsset(Native Method) 10-19 17:08:52.543 22783-22961/cn.dxy.android.aspirin W/System.err: at android.content.res.AssetManager.-wrap4(Unknown Source:0) at android.content.res.AssetManager$AssetInputStream.reset(AssetManager.java:642) at cn.dxy.aspirin.utils.LoadBitmapFromViewUtil.loadBitmapFromRawResource(LoadBitmapFromViewUtil.java:43) 10-19 17:08:52.544 22783-22961/cn.dxy.android.aspirin W/System.err: at cn.dxy.android.aspirin.dailyhealth.DailyHealthTruthPresenter.lambda$shareWechatMoment$1$DailyHealthTruthPresenter(DailyHealthTruthPresenter.java:149) 10-19 17:08:52.545 22783-22961/cn.dxy.android.aspirin W/System.err: at cn.dxy.android.aspirin.dailyhealth.DailyHealthTruthPresenter$$Lambda$1.call(Unknown Source:8) at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:69) at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:77) 10-19 17:08:52.546 22783-22961/cn.dxy.android.aspirin W/System.err: at rx.internal.util.ScalarSynchronousObservable$ScalarAsyncProducer.call(ScalarSynchronousObservable.java:200) at rx.internal.util.ScalarSynchronousObservable$2$1.call(ScalarSynchronousObservable.java:114) at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230) 10-19 17:08:52.547 22783-22961/cn.dxy.android.aspirin W/System.err: at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) at java.util.concurrent.FutureTask.run(FutureTask.java:266) 10-19 17:08:52.548 22783-22961/cn.dxy.android.aspirin W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 10-19 17:08:52.549 22783-22961/cn.dxy.android.aspirin W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)