写真のグリッドを表示するためにRecyclerView
を作成しています。それらの1つを選択すると、トランジション付きの新しいアクティビティが開きます。
Glideライブラリを使用して画像を読み込んでいますが、新しいアクティビティで画像が再読み込みされるため、遷移がひどく見えます。そのため、キャッシュに保存してから、移行に使用する必要がありました。
コードはありますが、画像が読み込まれない場合、CanvasRuntimeExceptionがスローされることがあります。
これはログです:
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 Android.graphics.Bitmap@29f09d20
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)
これは、他のアクティビティを開き、画像をキャッシュとして保存するためのコードです。
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;
}
この問題を解決するにはどうすればよいですか?前もって感謝します。
Canvas
がここdrawable.draw(canvas);
に描画する機会を得る直前に、ビットマップがリサイクル状態になることがあると思います。
簡単な解決策は、bitmap.recycle();
を呼び出さないことです。これは、 Android> 2.3. では厳密には必要ありません。それでもこのメモリを強制的に再利用したい場合は、ビットマップが実際に不要になったときを確認する方法を見つける必要があります(つまり、Canvas
は描画操作を終了する機会がありました)。
bitmap.recycle();
を、このビットマップが実際には不要になったコード内の別の場所に移動します。
キャンバスについてはよくわかりませんが(アニメーションはあまり使用しません)、これを修正する方法が見つからない場合は、代わりにこのライブラリを使用してみてください: https://github.com/codepath/Android_guides/wiki/shared-element-activity-transition