-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
Summary: Implemented 2 TODOs from ReactART for Android: - TODO(7255985): Use TextureView and pass Surface from the view to draw on it asynchronously instead of passing the bitmap (which is inefficient especially in terms of memory usage) - TODO(6352067): Support dashes in ARTShape We use ReactNativeART in our Android project. 1. Our app crashes sometimes on large screen smartphones with OutOfMemoryError. Crashes happen in ARTSurfaceShadowNode where TODO(7255985) was suggested in a comment in order to use memory more efficiently. 2. We needed dashes for drawing on ARTSurface. **Test plan (required)** I attach a screenshot of our app which shows dashed-lines and two ARTSurfaces on top of each other rendering exactly the same as in the pervious implementation of ARTSurface. ![screenshot_2016-08-19-16-45-43](https://cloud.githubusercontent.com/assets/18415611/17811741/cafc35c4-662c-11e6-8a63-7c35ef1c5ba9.png) Closes #9486 Differential Revision: D4021303 Pulled By: foghina fbshipit-source-id: 880175e841e3c598013982a7748b6fc691c7e8d6
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,17 +9,29 @@ | |
|
||
package com.facebook.react.views.art; | ||
|
||
import android.graphics.Bitmap; | ||
import javax.annotation.Nullable; | ||
|
||
import android.graphics.Canvas; | ||
import android.graphics.Paint; | ||
import android.graphics.Color; | ||
import android.view.Surface; | ||
import android.graphics.PorterDuff; | ||
import android.graphics.SurfaceTexture; | ||
import android.view.TextureView; | ||
|
||
import com.facebook.common.logging.FLog; | ||
import com.facebook.react.common.ReactConstants; | ||
import com.facebook.react.uimanager.LayoutShadowNode; | ||
import com.facebook.react.uimanager.UIViewOperationQueue; | ||
import com.facebook.react.uimanager.ReactShadowNode; | ||
|
||
/** | ||
* Shadow node for ART virtual tree root - ARTSurfaceView | ||
*/ | ||
public class ARTSurfaceViewShadowNode extends LayoutShadowNode { | ||
public class ARTSurfaceViewShadowNode extends LayoutShadowNode | ||
implements TextureView.SurfaceTextureListener { | ||
|
||
private @Nullable Surface mSurface; | ||
|
||
@Override | ||
public boolean isVirtual() { | ||
|
@@ -34,23 +46,61 @@ public boolean isVirtualAnchor() { | |
@Override | ||
public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) { | ||
super.onCollectExtraUpdates(uiUpdater); | ||
uiUpdater.enqueueUpdateExtraData(getReactTag(), drawOutput()); | ||
drawOutput(); | ||
uiUpdater.enqueueUpdateExtraData(getReactTag(), this); | ||
} | ||
|
||
private Object drawOutput() { | ||
// TODO(7255985): Use TextureView and pass Surface from the view to draw on it asynchronously | ||
// instead of passing the bitmap (which is inefficient especially in terms of memory usage) | ||
Bitmap bitmap = Bitmap.createBitmap( | ||
(int) getLayoutWidth(), | ||
(int) getLayoutHeight(), | ||
Bitmap.Config.ARGB_8888); | ||
Canvas canvas = new Canvas(bitmap); | ||
Paint paint = new Paint(); | ||
for (int i = 0; i < getChildCount(); i++) { | ||
ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); | ||
child.draw(canvas, paint, 1f); | ||
private void drawOutput() { | ||
if (mSurface == null || !mSurface.isValid()) { | ||
markChildrenUpdatesSeen(this); | ||
return; | ||
} | ||
|
||
try { | ||
Canvas canvas = mSurface.lockCanvas(null); | ||
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); | ||
|
||
Paint paint = new Paint(); | ||
for (int i = 0; i < getChildCount(); i++) { | ||
ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); | ||
child.draw(canvas, paint, 1f); | ||
child.markUpdateSeen(); | ||
} | ||
|
||
if (mSurface == null) { | ||
return; | ||
} | ||
|
||
mSurface.unlockCanvasAndPost(canvas); | ||
} catch (IllegalArgumentException | IllegalStateException e) { | ||
FLog.e(ReactConstants.TAG, e.getClass().getSimpleName() + " in Surface.unlockCanvasAndPost"); | ||
} | ||
} | ||
|
||
private void markChildrenUpdatesSeen(ReactShadowNode shadowNode) { | ||
for (int i = 0; i < shadowNode.getChildCount(); i++) { | ||
ReactShadowNode child = shadowNode.getChildAt(i); | ||
child.markUpdateSeen(); | ||
markChildrenUpdatesSeen(child); | ||
} | ||
return bitmap; | ||
} | ||
|
||
@Override | ||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { | ||
mSurface = new Surface(surface); | ||
drawOutput(); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
magicismight
Contributor
|
||
} | ||
|
||
@Override | ||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { | ||
surface.release(); | ||
mSurface = null; | ||
return true; | ||
} | ||
|
||
@Override | ||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} | ||
|
||
@Override | ||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {} | ||
} |
ARTSurfaceView will be re-rendered every time it is scrolled out and into the sight.
If put the ART icons into a ListView it will make the ListView drop frames.
Is there anyway to prevent this?
Do not destroy the surface every time it is outside the screen.