From 384913333f37669eb104ffaa881bb7f85deb3139 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 12 Jul 2024 17:40:51 +0800 Subject: [PATCH 1/6] fix(android): erase NativeRenderManager when destroy --- .../android/src/main/cpp/src/renderer/native_render_manager.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc b/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc index 18457c3fb42..dc2bf6f4805 100644 --- a/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc +++ b/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc @@ -110,6 +110,7 @@ void NativeRenderManager::DestroyRenderDelegate(JNIEnv* j_env) { j_env->CallVoidMethod(j_object, j_method_id); JNIEnvironment::ClearJEnvException(j_env); j_env->DeleteLocalRef(j_class); + persistent_map_.Erase(id_); } void NativeRenderManager::InitDensity() { From a35a34d20a3521dab972059bdc7a59cb72f4ac21 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 12 Jul 2024 20:46:36 +0800 Subject: [PATCH 2/6] fix(android): to use WeakReference as much as possible --- .../hippy/uimanager/ControllerManager.java | 27 ++++---- .../hippy/uimanager/ControllerRegistry.java | 14 ++-- .../uimanager/ControllerUpdateManger.java | 17 +++-- .../views/hippylist/HippyRecyclerView.java | 1 + .../helper/skikcy/StickyHeaderHelper.java | 41 ++++++++---- .../helper/skikcy/StickyViewFactory.java | 8 ++- .../com/tencent/renderer/NativeRenderer.java | 65 ++++++++++++------- 7 files changed, 105 insertions(+), 68 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java index 095d7636ce4..b0c676e4da5 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java @@ -35,7 +35,6 @@ import com.tencent.mtt.hippy.modules.Promise; import com.tencent.mtt.hippy.views.custom.HippyCustomPropsController; import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewController; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewWrapper; import com.tencent.mtt.hippy.views.image.HippyImageViewController; import com.tencent.mtt.hippy.views.list.HippyListItemViewController; import com.tencent.mtt.hippy.views.modal.HippyModalHostManager; @@ -58,6 +57,7 @@ import com.tencent.renderer.Renderer; import com.tencent.renderer.node.RenderNode; import com.tencent.renderer.node.VirtualNode; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -74,24 +74,26 @@ public class ControllerManager { @NonNull private final Map> mRecycleViewPools = new HashMap<>(); @Nullable - private Renderer mRenderer; + private final WeakReference mRendererWeakRef; @Nullable private static List> sDefaultControllers; public ControllerManager(@NonNull Renderer renderer) { - mRenderer = renderer; + mRendererWeakRef = new WeakReference<>(renderer); mControllerRegistry = new ControllerRegistry(renderer); mControllerUpdateManger = new ControllerUpdateManger<>(renderer); } @Nullable public RenderManager getRenderManager() { - return mRenderer != null ? ((NativeRender) mRenderer).getRenderManager() : null; + Renderer renderer = mRendererWeakRef.get(); + return renderer != null ? ((NativeRender) renderer).getRenderManager() : null; } @Nullable public NativeRender getNativeRender() { - return mRenderer != null ? ((NativeRender) mRenderer) : null; + Renderer renderer = mRendererWeakRef.get(); + return renderer != null ? ((NativeRender) renderer) : null; } @NonNull @@ -192,7 +194,6 @@ public void destroy() { deleteRootView(mControllerRegistry.getRootIdAt(i)); } } - mRenderer = null; } @Nullable @@ -234,7 +235,7 @@ public void preCreateView(int rootId, int id, @NonNull String className, if (view != null || rootView == null || controller == null) { return; } - view = controller.createView(rootView, id, mRenderer, className, props); + view = controller.createView(rootView, id, mRendererWeakRef.get(), className, props); if (view != null) { addPreView(view, rootId); } @@ -291,7 +292,7 @@ public View createView(@NonNull RenderNode node, PoolType cachePoolType) { if (controller == null) { return null; } - view = controller.createView(rootView, id, mRenderer, className, node.getProps()); + view = controller.createView(rootView, id, mRendererWeakRef.get(), className, node.getProps()); node.setNodeFlag(FLAG_UPDATE_LAYOUT); } if (view != null) { @@ -625,21 +626,23 @@ private String getViewOperationExceptionMessage(int pid, View parent, int id, Vi } private void reportRemoveViewException(int pid, View parent, int id, View child) { - if (mRenderer != null) { + Renderer renderer = mRendererWeakRef.get(); + if (renderer != null) { NativeRenderException exception = new NativeRenderException( REMOVE_CHILD_VIEW_FAILED_ERR, getViewOperationExceptionMessage(pid, parent, id, child, "Remove view failed:")); - mRenderer.handleRenderException(exception); + renderer.handleRenderException(exception); } } private void reportAddViewException(int pid, View parent, int id, View child) { - if (mRenderer != null) { + Renderer renderer = mRendererWeakRef.get(); + if (renderer != null) { NativeRenderException exception = new NativeRenderException(ADD_CHILD_VIEW_FAILED_ERR, getViewOperationExceptionMessage(pid, parent, id, child, "Add child to parent failed:")); - mRenderer.handleRenderException(exception); + renderer.handleRenderException(exception); } } } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java index 4bea4686dca..0c49a43df16 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java @@ -28,6 +28,7 @@ import com.tencent.renderer.Renderer; import com.tencent.renderer.node.RenderNode; +import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; @@ -42,15 +43,13 @@ public class ControllerRegistry { @NonNull private final Map mControllers = new HashMap<>(); @Nullable - private Renderer mRenderer; + private final WeakReference mRendererWeakRef; public ControllerRegistry(@NonNull Renderer renderer) { - mRenderer = renderer; + mRendererWeakRef = new WeakReference<>(renderer); } - public void clear() { - mRenderer = null; - } + public void clear() {} public void addControllerHolder(String name, ControllerHolder controllerHolder) { mControllers.put(name, controllerHolder); @@ -66,10 +65,11 @@ public ControllerHolder getControllerHolder(String className) { public HippyViewController getViewController(@NonNull String className) { ControllerHolder holder = mControllers.get(className); if (holder == null) { - if (mRenderer != null) { + Renderer renderer = mRendererWeakRef.get(); + if (renderer != null) { NativeRenderException exception = new NativeRenderException( GET_VIEW_CONTROLLER_FAILED_ERR, "Unknown class name=" + className); - mRenderer.handleRenderException(exception); + renderer.handleRenderException(exception); } return null; } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java index aa024048ae3..8e228392c0f 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java @@ -39,6 +39,7 @@ import com.tencent.renderer.utils.PropertyUtils.PropertyMethodHolder; import com.tencent.renderer.node.RenderNode; +import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; @@ -64,7 +65,7 @@ public class ControllerUpdateManger { NodeProps.OVERFLOW }; @Nullable - private Renderer mRenderer; + private final WeakReference mRendererWeakRef; @Nullable private ComponentController mComponentController; @Nullable @@ -79,11 +80,11 @@ public class ControllerUpdateManger { } public ControllerUpdateManger(@NonNull Renderer renderer) { - mRenderer = renderer; + mRendererWeakRef = new WeakReference<>(renderer); } public void clear() { - mRenderer = null; + } public void setCustomPropsController(T controller) { @@ -144,10 +145,7 @@ private static boolean isComponentProps(String name) { return true; } // Special case: property "opacity" in TextVirtualNode also need to process in HippyViewController - if (NodeProps.OPACITY.equals(name)) { - return true; - } - return false; + return NodeProps.OPACITY.equals(name); } void findViewPropsMethod(Class cls, @@ -198,8 +196,9 @@ private void invokePropMethod(@NonNull Object obj, @NonNull Object arg1, methodHolder.method.invoke(obj, arg1, value); } } catch (Exception exception) { - if (mRenderer != null) { - mRenderer.handleRenderException( + Renderer renderer = mRendererWeakRef.get(); + if (renderer != null) { + renderer.handleRenderException( PropertyUtils.makePropertyConvertException(exception, key, methodHolder.method)); } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java index 732cbfa4fe2..a2be91b24bb 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java @@ -98,6 +98,7 @@ protected void init() { public void onDestroy() { if (stickyHeaderHelper != null) { stickyHeaderHelper.detachSticky(); + stickyHeaderHelper.onDestroy(); } } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyHeaderHelper.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyHeaderHelper.java index 54772321c35..772cb4e392b 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyHeaderHelper.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyHeaderHelper.java @@ -41,16 +41,16 @@ public class StickyHeaderHelper extends OnScrollListener implements private static final String TAG = "StickyHeaderHelper"; private static final int INVALID_POSITION = -1; - private final com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderAttachListener headerAttachListener; + private IHeaderAttachListener headerAttachListener; private RecyclerViewBase recyclerView; - private com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IStickyItemsProvider stickyItemsProvider; - private StickyViewFactory stickyViewFactory; + private IHeaderHost headerHost; + private IStickyItemsProvider stickyItemsProvider; + private final StickyViewFactory stickyViewFactory; private ViewHolder headerOrgViewHolder; private boolean orgViewHolderCanRecyclable = false; private View currentHeaderView; private int orientation; private int currentStickPos = -1; - private com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderHost headerHost; private com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.StickViewListener stickViewListener; private boolean isUpdateStickyHolderWhenLayout; @@ -59,9 +59,9 @@ public StickyHeaderHelper(final RecyclerViewBase recyclerView, IHeaderAttachListener headerAttachListener, IHeaderHost headerHost) { this.recyclerView = recyclerView; this.headerAttachListener = headerAttachListener; + this.headerHost = headerHost; this.stickyItemsProvider = stickyItemsProvider; stickyViewFactory = new StickyViewFactory(recyclerView); - this.headerHost = headerHost; orientation = recyclerView.getLayoutManager().canScrollVertically() ? VERTICAL : HORIZONTAL; } @@ -94,6 +94,14 @@ public void setUpdateStickyViewWhenLayout(boolean bindStickyHolderWhenLayout) { isUpdateStickyHolderWhenLayout = bindStickyHolderWhenLayout; } + public void onDestroy() { + recyclerView = null; + headerAttachListener = null; + headerHost = null; + stickyItemsProvider = null; + currentHeaderView = null; + } + /** * 如果当前stickHolder和新的stickyHolder 不一样,那么把当前的stickyHolder删除掉,并还原HeaderView的Translation */ @@ -103,7 +111,9 @@ public void detachSticky() { currentHeaderView.setTranslationY(0); currentHeaderView.setTranslationX(0); returnHeaderBackToList(); - headerHost.removeOnLayoutListener(this); + if (headerHost != null) { + headerHost.removeOnLayoutListener(this); + } notifyStickDetached(); } currentStickPos = -1; @@ -123,16 +133,16 @@ private void notifyStickDetached() { */ private void returnHeaderBackToList() { headerOrgViewHolder.setIsRecyclable(orgViewHolderCanRecyclable); - if (headerAttachListener != null) { + if (headerAttachListener != null && currentHeaderView != null) { headerAttachListener.onHeaderDetached(headerOrgViewHolder, currentHeaderView); - } else { + } else if (recyclerView != null) { ViewHolder viewHolderToReturn = recyclerView .findViewHolderForAdapterPosition(headerOrgViewHolder.getAdapterPosition()); if (viewHolderToReturn != null && viewHolderToReturn.itemView instanceof ViewGroup) { ViewGroup itemView = (ViewGroup) viewHolderToReturn.itemView; //已经有孩子了,就不要加了,这个可能是新创建的ViewHolder已经有了内容 - if (itemView.getChildCount() <= 0) { - itemView.addView(this.currentHeaderView); + if (itemView.getChildCount() <= 0 && currentHeaderView != null) { + itemView.addView(currentHeaderView); } } } @@ -142,7 +152,7 @@ private void returnHeaderBackToList() { * 将stickyItemPosition对应的View挂载到RecyclerView的父亲上面 */ private void attachSticky(int newStickyPosition) { - if (newStickyPosition != INVALID_POSITION) { + if (newStickyPosition != INVALID_POSITION && headerHost != null) { headerOrgViewHolder = stickyViewFactory.getHeaderForPosition(newStickyPosition); currentStickPos = newStickyPosition; Log.d("returnHeader", "attachSticky:" + headerOrgViewHolder); @@ -172,7 +182,7 @@ private void notifyStickAttached(int stickyPosition) { * 设置吸顶的View的偏移 在下一个吸顶view和当前吸顶的view交汇的时候,需要把当前吸顶view往上面移动,慢慢会把当前的吸顶view顶出屏幕 */ private void offsetSticky() { - if (headerOrgViewHolder != null) { + if (headerOrgViewHolder != null && currentHeaderView != null) { float offset = getOffset(findNextSticky(currentStickPos)); if (orientation == VERTICAL) { currentHeaderView.setTranslationY(offset); @@ -186,6 +196,9 @@ private void offsetSticky() { * 找到屏幕中,下一个即将吸顶的view,主要用于计算当前吸顶的HeaderView的Offset, 下一个即将吸顶的View会慢慢把当前正在吸顶的HeaderView慢慢顶出屏幕外 */ private View findNextSticky(int currentStickyPos) { + if (recyclerView == null || stickyItemsProvider == null) { + return null; + } for (int i = 0; i < recyclerView.getChildCount(); i++) { View nextStickyView = recyclerView.getChildAt(i); int nextStickyPos = recyclerView.getChildLayoutPosition(nextStickyView); @@ -239,7 +252,7 @@ public void onGlobalLayout() { * @return INVALID_POSITION,没有找到stickyItem */ public int getStickyItemPosition() { - if (recyclerView.getChildCount() <= 0) { + if (recyclerView == null || stickyItemsProvider == null || recyclerView.getChildCount() <= 0) { return INVALID_POSITION; } int positionToSticky = INVALID_POSITION; @@ -285,7 +298,7 @@ private void removeViewFromParent(View view) { } private void updateStickHolder() { - if (headerOrgViewHolder != null) { + if (headerOrgViewHolder != null && recyclerView != null) { recyclerView.getAdapter().onBindViewHolder(headerOrgViewHolder, currentStickPos); } } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyViewFactory.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyViewFactory.java index 012e04fb38f..83e5c319d27 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyViewFactory.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/recyclerview/helper/skikcy/StickyViewFactory.java @@ -18,13 +18,14 @@ import androidx.recyclerview.widget.RecyclerViewBase; import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import java.lang.ref.WeakReference; public final class StickyViewFactory implements IHeaderViewFactory { - private final RecyclerViewBase recyclerView; + private final WeakReference recyclerViewWeakRef; public StickyViewFactory(RecyclerViewBase recyclerView) { - this.recyclerView = recyclerView; + recyclerViewWeakRef = new WeakReference<>(recyclerView); } /** @@ -37,7 +38,8 @@ public StickyViewFactory(RecyclerViewBase recyclerView) { * @return 返回对应到ViewHolder,不会返回Null */ public ViewHolder getHeaderForPosition(int position) { - if (position < 0) { + RecyclerViewBase recyclerView = recyclerViewWeakRef.get(); + if (position < 0 || recyclerView == null) { return null; } ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position); diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java index b78c119fca8..70d5badc961 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java @@ -67,6 +67,7 @@ import com.tencent.renderer.utils.MapUtils; import com.tencent.vfs.VfsManager; +import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -120,7 +121,7 @@ public class NativeRenderer extends Renderer implements NativeRender, NativeRend private static final AtomicInteger sRootIdCounter = new AtomicInteger(0); private FCPBatchState mFcpBatchState = FCPBatchState.WATCHING; @Nullable - private FrameworkProxy mFrameworkProxy; + private WeakReference mFrameworkProxyWeakRef; @Nullable private List mInstanceLifecycleEventListeners; @NonNull @@ -194,16 +195,23 @@ public int getInstanceId() { return mRenderProvider.getInstanceId(); } + @Nullable + private FrameworkProxy getFrameworkProxy() { + return (mFrameworkProxyWeakRef != null) ? mFrameworkProxyWeakRef.get() : null; + } + @Override @Nullable public Object getCustomViewCreator() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getCustomViewCreator() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getCustomViewCreator() : null; } @Override @Nullable public String getBundlePath() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getBundlePath() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getBundlePath() : null; } @Override @@ -218,31 +226,36 @@ public ImageLoaderAdapter getImageLoader() { @Override @Nullable public VfsManager getVfsManager() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getVfsManager() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getVfsManager() : null; } @Override @Nullable public ImageDecoderAdapter getImageDecoderAdapter() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getImageDecoderAdapter() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getImageDecoderAdapter() : null; } @Override @Nullable public FontAdapter getFontAdapter() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getFontAdapter() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getFontAdapter() : null; } @Nullable public LogAdapter getLogAdapter() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getLogAdapter() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getLogAdapter() : null; } @Override @Nullable public Executor getBackgroundExecutor() { - if (mFrameworkProxy != null && mFrameworkProxy.getBackgroundExecutor() != null) { - return mFrameworkProxy.getBackgroundExecutor(); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null && frameworkProxy.getBackgroundExecutor() != null) { + return frameworkProxy.getBackgroundExecutor(); } if (mBackgroundExecutor == null) { mBackgroundExecutor = Executors.newFixedThreadPool(4); @@ -268,8 +281,9 @@ public void handleRenderException(@NonNull Exception exception) { msg = exception.getMessage(); } LogUtils.e(TAG, msg); - if (mFrameworkProxy != null) { - mFrameworkProxy.handleNativeException(exception); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null) { + frameworkProxy.handleNativeException(exception); } } @@ -284,17 +298,19 @@ public void onReceiveRenderLogMessage(int level, @NonNull String tag, @NonNull S @Override @Nullable public BaseEngineContext getEngineContext() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getEngineContext() : null; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getEngineContext() : null; } @Override public int getEngineId() { - return (mFrameworkProxy != null) ? mFrameworkProxy.getEngineId() : -1; + FrameworkProxy frameworkProxy = getFrameworkProxy(); + return (frameworkProxy != null) ? frameworkProxy.getEngineId() : -1; } @Override public void setFrameworkProxy(@NonNull FrameworkProxy proxy) { - mFrameworkProxy = proxy; + mFrameworkProxyWeakRef = new WeakReference<>(proxy); } @Override @@ -313,7 +329,6 @@ public void destroy() { if (mImageLoader != null) { mImageLoader.destroy(); } - mFrameworkProxy = null; NativeRendererManager.removeNativeRendererInstance(mRenderProvider.getInstanceId()); } @@ -359,15 +374,17 @@ public View getRootView(@NonNull View view) { @Override public void onFirstPaint() { - if (mFrameworkProxy != null) { - mFrameworkProxy.onFirstPaint(); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null) { + frameworkProxy.onFirstPaint(); } } @Override public void onFirstContentfulPaint() { - if (mFrameworkProxy != null) { - mFrameworkProxy.onFirstContentfulPaint(); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null) { + frameworkProxy.onFirstContentfulPaint(); } } @@ -391,8 +408,9 @@ private void onSizeChanged(int rootId, int w, int h) { @Override public void onSizeChanged(int rootId, int w, int h, int ow, int oh) { - if (mFrameworkProxy != null) { - mFrameworkProxy.onSizeChanged(rootId, w, h, ow, oh); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null) { + frameworkProxy.onSizeChanged(rootId, w, h, ow, oh); } onSizeChanged(rootId, w, h); } @@ -404,8 +422,9 @@ public void onSizeChanged(int rootId, int nodeId, int width, int height, boolean @Override public void updateDimension(int width, int height) { - if (mFrameworkProxy != null) { - mFrameworkProxy.updateDimension(width, height); + FrameworkProxy frameworkProxy = getFrameworkProxy(); + if (frameworkProxy != null) { + frameworkProxy.updateDimension(width, height); } } From 9cead15829561d2e71cdfd77cca0b0f6cafaea15 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 12 Jul 2024 21:14:41 +0800 Subject: [PATCH 3/6] fix(android): change to using global image cache --- .../com/openhippy/pool/ImageDataPool.java | 33 ++++++++++++------- .../com/openhippy/pool/RecycleObjectPool.java | 2 +- .../renderer/component/image/ImageLoader.java | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java b/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java index af5258655b5..566edb4e12c 100644 --- a/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java +++ b/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java @@ -23,6 +23,7 @@ public class ImageDataPool extends BasePool { private static final int DEFAULT_IMAGE_POOL_SIZE = 16; + private final Object mLock = new Object(); private LruCache mPools; public ImageDataPool() { @@ -50,15 +51,17 @@ protected void entryRemoved(boolean evicted, @NonNull ImageDataKey key, @Override @Nullable public ImageRecycleObject acquire(@NonNull ImageDataKey key) { - ImageRecycleObject data = mPools.get(key); - if (data != null && data.isScraped()) { - // Bitmap may have been recycled, must be removed from the cache and not - // returned to the component. - mPools.remove(key); - data.evicted(); - return null; + synchronized (mLock) { + ImageRecycleObject data = mPools.get(key); + if (data != null && data.isScraped()) { + // Bitmap may have been recycled, must be removed from the cache and not + // returned to the component. + mPools.remove(key); + data.evicted(); + return null; + } + return data; } - return data; } @Override @@ -71,18 +74,24 @@ public void release(@NonNull ImageRecycleObject data) { @Override public void release(@NonNull ImageDataKey key, @NonNull ImageRecycleObject data) { - mPools.put(key, data); - data.cached(); + synchronized (mLock) { + mPools.put(key, data); + data.cached(); + } } @Override public void clear() { - mPools.evictAll(); + synchronized (mLock) { + mPools.evictAll(); + } } @Override public void remove(@NonNull ImageDataKey key) { - mPools.remove(key); + synchronized (mLock) { + mPools.remove(key); + } } private void onEntryEvicted(@NonNull ImageRecycleObject data) { diff --git a/modules/android/pool/src/main/java/com/openhippy/pool/RecycleObjectPool.java b/modules/android/pool/src/main/java/com/openhippy/pool/RecycleObjectPool.java index 2b8bc104df3..d74853e3945 100644 --- a/modules/android/pool/src/main/java/com/openhippy/pool/RecycleObjectPool.java +++ b/modules/android/pool/src/main/java/com/openhippy/pool/RecycleObjectPool.java @@ -29,7 +29,7 @@ public class RecycleObjectPool extends BasePool { private static final String TAG = "RecycleObjectPool"; private final Object mLock = new Object(); private final Map> mPools = new HashMap<>(); - private int mPoolSize = 24; + private int mPoolSize = 12; public RecycleObjectPool() {} diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java b/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java index 493a0b845e8..3a0bd902702 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java @@ -46,7 +46,7 @@ public class ImageLoader implements ImageLoaderAdapter { @NonNull private final HashMap> mListenersMap = new HashMap<>(); @NonNull - private final Pool mImagePool = new ImageDataPool(); + private final static Pool mImagePool = new ImageDataPool(); public ImageLoader(@NonNull VfsManager vfsManager, @Nullable ImageDecoderAdapter imageDecoderAdapter) { From 6bce555aaf9be08dafc9d7e4e2e8576881d62445 Mon Sep 17 00:00:00 2001 From: maxli Date: Thu, 18 Jul 2024 21:35:16 +0800 Subject: [PATCH 4/6] fix(android): removeRootView params may be null --- .../hippy/modules/HippyModuleManagerImpl.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java b/framework/android/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java index db4822d89e6..3950ff82dce 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java @@ -19,6 +19,7 @@ import android.os.Handler; import android.os.Message; +import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -34,7 +35,6 @@ import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModuleInvocationHandler; import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleInfo; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; import com.tencent.mtt.hippy.runtime.builtins.array.JSDenseArray; import com.tencent.mtt.hippy.serialization.PrimitiveValueDeserializer; import com.tencent.mtt.hippy.serialization.compatible.Deserializer; @@ -46,6 +46,7 @@ import com.tencent.mtt.hippy.utils.LogUtils; import com.tencent.mtt.hippy.utils.UIThreadUtils; +import java.lang.ref.WeakReference; import java.lang.reflect.Proxy; import java.nio.ByteBuffer; import java.util.HashMap; @@ -437,14 +438,20 @@ private void onCallNativeFinished(@Nullable HippyCallNativeParams params) { adapter.onCallNativeFinished(mContext.getComponentName(), params); } - private void removeRootView(@NonNull final JSDenseArray roots) { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (roots.size() > 0) { + private void removeRootView(@Nullable final JSDenseArray roots) { + final WeakReference engineContextRef = new WeakReference<>(mContext); + UIThreadUtils.runOnUiThread(() -> { + HippyEngineContext engineContext = engineContextRef.get(); + if (engineContext != null) { + if (roots != null && roots.size() > 0) { Object valueObj = roots.get(0); if (valueObj instanceof Integer) { - ((HippyInstanceLifecycleEventListener) mContext).onInstanceDestroy((Integer) valueObj); + ((HippyInstanceLifecycleEventListener) engineContext).onInstanceDestroy((Integer) valueObj); + } + } else { + ViewGroup rootView = engineContext.getRootView(); + if (rootView != null) { + ((HippyInstanceLifecycleEventListener) engineContext).onInstanceDestroy(rootView.getId()); } } } From 892270611c04f58ac32190b437757312aec679e9 Mon Sep 17 00:00:00 2001 From: maxli Date: Thu, 18 Jul 2024 21:42:06 +0800 Subject: [PATCH 5/6] fix(android): sticky item type calculate using node id --- .../mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java index 818ae6f3b01..c9ccdf084c3 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java @@ -252,7 +252,7 @@ public int getItemViewType(int position) { return 0; } if (node.shouldSticky()) { - return STICK_ITEM_VIEW_TYPE_BASE - node.getItemViewType(); + return STICK_ITEM_VIEW_TYPE_BASE - node.getId(); } return node.getItemViewType(); } From dee2a2b3e59144f89fc414c67c6837ab0657b998 Mon Sep 17 00:00:00 2001 From: maxli Date: Mon, 22 Jul 2024 22:03:02 +0800 Subject: [PATCH 6/6] fix(android): lru cache is thread safe --- .../com/openhippy/pool/ImageDataPool.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java b/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java index 566edb4e12c..af5258655b5 100644 --- a/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java +++ b/modules/android/pool/src/main/java/com/openhippy/pool/ImageDataPool.java @@ -23,7 +23,6 @@ public class ImageDataPool extends BasePool { private static final int DEFAULT_IMAGE_POOL_SIZE = 16; - private final Object mLock = new Object(); private LruCache mPools; public ImageDataPool() { @@ -51,17 +50,15 @@ protected void entryRemoved(boolean evicted, @NonNull ImageDataKey key, @Override @Nullable public ImageRecycleObject acquire(@NonNull ImageDataKey key) { - synchronized (mLock) { - ImageRecycleObject data = mPools.get(key); - if (data != null && data.isScraped()) { - // Bitmap may have been recycled, must be removed from the cache and not - // returned to the component. - mPools.remove(key); - data.evicted(); - return null; - } - return data; + ImageRecycleObject data = mPools.get(key); + if (data != null && data.isScraped()) { + // Bitmap may have been recycled, must be removed from the cache and not + // returned to the component. + mPools.remove(key); + data.evicted(); + return null; } + return data; } @Override @@ -74,24 +71,18 @@ public void release(@NonNull ImageRecycleObject data) { @Override public void release(@NonNull ImageDataKey key, @NonNull ImageRecycleObject data) { - synchronized (mLock) { - mPools.put(key, data); - data.cached(); - } + mPools.put(key, data); + data.cached(); } @Override public void clear() { - synchronized (mLock) { - mPools.evictAll(); - } + mPools.evictAll(); } @Override public void remove(@NonNull ImageDataKey key) { - synchronized (mLock) { - mPools.remove(key); - } + mPools.remove(key); } private void onEntryEvicted(@NonNull ImageRecycleObject data) {