2015-07-04 16 views
7

Tôi đang tạo một RecyclerView để hiển thị Lưới ảnh. Khi chọn một trong số họ, nó sẽ mở một hoạt động mới với một quá trình chuyển đổi.Cách khắc phục "canvas: đang cố sử dụng lỗi bitmap tái chế"?

Tôi đang sử dụng thư viện Glide để tải những hình ảnh và quá trình chuyển đổi trông khủng khiếp vì nó tải lại hình ảnh trong hoạt động mới. Vì vậy, tôi đã phải lưu nó trong bộ nhớ cache, và sau đó sử dụng nó cho quá trình chuyển đổi.

Tôi có đoạn code, nhưng đôi khi nếu hình ảnh không tải, nó ném một Canvas RuntimeException.

Đây là nhật ký:

07-03 15:19:58.633 28461-28461/jahirfiquitiva.project E/AndroidRuntime﹕ FATAL EXCEPTION: main 
    Process: jahirfiquitiva.project, PID: 28461 
    java.lang.RuntimeException: Canvas: trying to use a recycled bitmap [email protected] 
      at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1282) 
      at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:599) 
      at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:538) 
      at android.widget.ImageView.onDraw(ImageView.java:1176) 
      at android.view.View.draw(View.java:15239) 
      at android.view.View.updateDisplayListIfDirty(View.java:14175) 
      at android.view.View.getDisplayList(View.java:14197) 
      at android.view.GhostView.onDraw(GhostView.java:52) 
      at android.view.View.draw(View.java:15239) 
      at android.view.View.updateDisplayListIfDirty(View.java:14175) 
      at android.view.View.getDisplayList(View.java:14197) 
      at android.view.View.draw(View.java:14967) 
      at android.view.ViewGroup.drawChild(ViewGroup.java:3406) 
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199) 
      at android.view.View.updateDisplayListIfDirty(View.java:14170) 
      at android.view.View.getDisplayList(View.java:14197) 
      at android.view.View.draw(View.java:14967) 
      at android.view.ViewGroup.drawChild(ViewGroup.java:3406) 
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199) 
      at android.view.ViewOverlay$OverlayViewGroup.dispatchDraw(ViewOverlay.java:219) 
      at android.view.View.draw(View.java:15248) 
      at android.widget.FrameLayout.draw(FrameLayout.java:598) 
      at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2906) 
      at android.view.View.updateDisplayListIfDirty(View.java:14175) 
      at android.view.View.getDisplayList(View.java:14197) 
      at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273) 
      at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279) 
      at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318) 
      at android.view.ViewRootImpl.draw(ViewRootImpl.java:2536) 
      at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2352) 
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1982) 
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) 
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5891) 
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) 
      at android.view.Choreographer.doCallbacks(Choreographer.java:580) 
      at android.view.Choreographer.doFrame(Choreographer.java:550) 
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) 
      at android.os.Handler.handleCallback(Handler.java:739) 
      at android.os.Handler.dispatchMessage(Handler.java:95) 
      at android.os.Looper.loop(Looper.java:135) 
      at android.app.ActivityThread.main(ActivityThread.java:5289) 
      at java.lang.reflect.Method.invoke(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:372) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 

Đây là mã để mở hoạt động khác và lưu các hình ảnh như bộ nhớ cache:

private void openViewer(WallpapersAdapter.WallsHolder wallsHolder, int index, final HashMap<String, String> data) { 

     final Intent intent = new Intent(wallsActivity, ViewerActivity.class); 
     intent.putExtra("wallUrl", data.get(WallpapersActivity.WALL)); 
     intent.putExtra("wallName", data.get(WallpapersActivity.NAME)); 
     intent.putExtra("transitionName", ViewCompat.getTransitionName(wallsHolder.wall)); 

     //save image from drawable 
     //get its path and send it to activity 
     Bitmap bitmap = drawableToBitmap(wallsHolder.wall.getDrawable()); 
     //Convert to byte array and send to the other activity 

     Log.e("Resolution", bitmap.getWidth() + "x" + bitmap.getHeight()); 
     try { 
      //Write file 
      String filename = "bitmap.png"; 
      FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE); 
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 

      //Cleanup 
      stream.close(); 
      bitmap.recycle(); 

      //Pop intent 
      intent.putExtra("image", filename); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
       this, wallsHolder.wall, ViewCompat.getTransitionName(wallsHolder.wall)); 
     startActivity(intent, options.toBundle()); 

    } 

    public static Bitmap drawableToBitmap (Drawable drawable) { 
     Bitmap bitmap = null; 
     if (drawable instanceof BitmapDrawable) { 
      BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; 
      if(bitmapDrawable.getBitmap() != null) { 
       return bitmapDrawable.getBitmap(); 
      } 
     } 

     if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { 
      bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel 
     } else { 
      bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 
     } 

     Canvas canvas = new Canvas(bitmap); 
     drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 
     drawable.draw(canvas); 
     return bitmap; 
    } 

tôi có thể làm gì để khắc phục vấn đề này? Cảm ơn trước.

+0

Tôi không chắc chắn, nhưng tôi nghĩ bạn nên lưu bitmap vào tham chiếu đối tượng thực, chứ không phải trong bộ nhớ cache. Bộ nhớ cache có thể được phép giải phóng bitmap khi nó không còn được sử dụng nữa. –

Trả lời

12

tôi nghi ngờ một lần trong một thời gian bitmap của bạn được vào trạng thái tái chế ngay trước khi Canvas có cơ hội vẽ lên nó ở đây drawable.draw(canvas);.

Một giải pháp nhanh chóng không nên gọi số bitmap.recycle();, điều này là không bắt buộc đối với android >2.3.3. Nếu bạn vẫn muốn đòi lại bộ nhớ này một cách mạnh mẽ, bạn sẽ phải tìm cách kiểm tra khi bitmap thực sự không còn cần thiết nữa (tức là, Canvas đã có cơ hội hoàn tất thao tác vẽ).

5

Move bitmap.recycle(); đến một nơi khác trong mã nơi bitmap này thực sự là không còn cần thiết.

Các vấn đề liên quan