anvil icon indicating copy to clipboard operation
anvil copied to clipboard

onDetachedFromWindow is called twice

Open amoikevin opened this issue 8 years ago • 13 comments

The method "onDetachedFromWindow" of RenderableView is called twice,this will cause some exceptions. For example, RecyclerView will throw NullPointerException, for mGapWorker was set to null at the first time.

amoikevin avatar Jan 20 '17 06:01 amoikevin

+1 I have exact the same issue. For now I explicitly unmount my RenderableViews, so that they won't be detach twice. BTW this issue is probably related to the #82

iciakky avatar Feb 12 '17 02:02 iciakky

Could you please give a bit more context? Are these renderable views located inside other renderable views? Or maybe they are adapter items? Or are they mounted directly into the activity?

FYI, in the upcoming Anvil 0.5.0 (see forge branch for now) I'm hoping to add umount(View v, boolean removeChildViews) to allow unounting RenderableViews without destroying the view hierarchy. Might help in some cases when Android removes child views by itself and doesn't expect Anvil to do so.

zserge avatar Feb 13 '17 08:02 zserge

For the stack trace, please see the first reply of #82, I've seen it before. To reproduce this issue, launch this(gist) and tap the back key to exit this app, then comes the NPE: (the anvil version I'm using is 0.4.0)

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.GapWorker.remove(android.support.v7.widget.RecyclerView)' on a null object reference
                      at android.support.v7.widget.RecyclerView.onDetachedFromWindow(RecyclerView.java:2489)
                      at android.view.View.dispatchDetachedFromWindow(View.java:15560)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3187)
                      at android.view.ViewGroup.removeViewsInternal(ViewGroup.java:4825)
                      at android.view.ViewGroup.removeViews(ViewGroup.java:4681)
                      at trikita.anvil.Anvil.unmount(Anvil.java:138)
                      at trikita.anvil.RenderableView.onDetachedFromWindow(RenderableView.java:33)
                      at android.view.View.dispatchDetachedFromWindow(View.java:15560)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3187)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3179)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3179)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3179)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3179)
                      at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3179)
                      at android.view.ViewRootImpl.dispatchDetachedFromWindow(ViewRootImpl.java:3259)
                      at android.view.ViewRootImpl.doDie(ViewRootImpl.java:5917)
                      at android.view.ViewRootImpl.die(ViewRootImpl.java:5894)
                      at android.view.WindowManagerGlobal.removeViewLocked(WindowManagerGlobal.java:446)
                      at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:384)
                      at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:124)
                      at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4243)
                      at android.app.ActivityThread.-wrap6(ActivityThread.java)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1538)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6119)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

iciakky avatar Feb 13 '17 15:02 iciakky

any workaround???

FunnyDevs avatar Mar 25 '17 12:03 FunnyDevs

I'm not sure how this issue has been affected by Anvil 0.5.1, but there is now an option to call Anvil.unmount(view, removeChildViews), so if the issue was caused by the fact that child views has already been removed - then perhaps changing the removeChildViews flag to false in the RenderableView class would help.

zserge avatar Mar 25 '17 12:03 zserge

The problem comes with recyclerview. The only solution, i think, is create a Custom Renderable View and put "Anvil.unmout(this,false)" inside "onDetachedFromWindow"

FunnyDevs avatar Mar 25 '17 14:03 FunnyDevs

Hm.. So RecyclerView injects some child views on its own, then during the unmount() call we remove its child views and when it tries to do the same - it crashes. I wonder if custom unmount(v, false) works any better, and if so - perhaps unmount() can be rewritten to only remove Anvil own views (much like end() does).

zserge avatar Mar 25 '17 15:03 zserge

I'm getting the same exception as @iciakky

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.GapWorker.remove(android.support.v7.widget.RecyclerView)' on a null object reference
  at android.support.v7.widget.RecyclerView.onDetachedFromWindow(RecyclerView.java:2534)
  at android.view.View.dispatchDetachedFromWindow(View.java:15560)
  at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3187)
  at android.view.ViewGroup.removeViewsInternal(ViewGroup.java:4825)
  at android.view.ViewGroup.removeViews(ViewGroup.java:4681)
  at trikita.anvil.Anvil.unmount(Anvil.java:181)
  at trikita.anvil.Anvil.unmount(Anvil.java:166)
  at trikita.anvil.RenderableView.onDetachedFromWindow(RenderableView.java:33)
  at clean.news.ui.item.list.ItemListView.onDetachedFromWindow(ItemListView.kt:38)
  at android.view.View.dispatchDetachedFromWindow(View.java:15560)
  at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3187)
  at android.view.ViewGroup.removeViewInternal(ViewGroup.java:4715)
  at android.view.ViewGroup.removeViewAt(ViewGroup.java:4665)
  at android.support.v7.widget.RecyclerView$5.removeViewAt(RecyclerView.java:732)
  at android.support.v7.widget.ChildHelper.removeViewAt(ChildHelper.java:168)
  at android.support.v7.widget.RecyclerView$LayoutManager.removeViewAt(RecyclerView.java:7915)
  at android.support.v7.widget.RecyclerView$LayoutManager.removeAndRecycleViewAt(RecyclerView.java:8187)
  at android.support.v7.widget.LinearLayoutManager.recycleChildren(LinearLayoutManager.java:1363)
  at android.support.v7.widget.LinearLayoutManager.recycleViewsFromStart(LinearLayoutManager.java:1409)
  at android.support.v7.widget.LinearLayoutManager.recycleByLayoutState(LinearLayoutManager.java:1478)
  at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1502)
  at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1325)
  at android.support.v7.widget.LinearLayoutManager.scrollHorizontallyBy(LinearLayoutManager.java:1049)
  at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4722)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
  at android.view.Choreographer.doCallbacks(Choreographer.java:686)
  at android.view.Choreographer.doFrame(Choreographer.java:618)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
  at android.os.Handler.handleCallback(Handler.java:751)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6119)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

I'm rewriting my best practices/example app to use Anvil instead of RxBinding and this is blocking me.

pardom-zz avatar May 28 '17 13:05 pardom-zz

See this bug report filed on the Android issue tracker: https://issuetracker.google.com/issues/38375597

If you star it, maybe it'll get more attention and get fixed.

autonomousapps avatar Nov 06 '17 19:11 autonomousapps

In my case I could fix it without modifying the recyclerview or downgrading the version I have my recyclerview inside a custom compound view and I was doing inflater.inflate(R.layout.layout_name, this, true); in the constructor now instead of doing it I'm inflating it this way mView = inflater.infltate(R.layout.layout_name, this, false); and after that adding the view with this.addView(mView);

and on my onDetachedFromWindow I have this:

if (mView != null) {
            removeView(mView);
        }

It works like a charm.

chriscoderdr avatar Jan 16 '18 14:01 chriscoderdr

support-v7:27.1.0 fix this bug

meikaiss avatar Apr 18 '18 03:04 meikaiss

@meikaiss are you sure? it it still void someone said

CK875430315 avatar May 22 '18 04:05 CK875430315

@meikaiss i am sry,recyclerview27.1.0 fixed the mGapWorker is null

CK875430315 avatar May 25 '18 06:05 CK875430315