8

子レイアウト(ビュー)で、ビューが親から削除されたときのコールバックはありますか?ビューが完了したら、いくつかの画像をリサイクルする必要があります。私は何をすべきかをウェブで探していましたが、まだ何も役に立ちませんでした。

4

4 に答える 4

11

私もこんなものを探していました。私が見つけることができる最高のものはView.OnAttachStateChangeListenerです。ビューがウィンドウに追加およびウィンドウから削除されたときのコールバックであるため、これが理想的であるとは思えません。親ではありませんが、私のニーズには十分です。

于 2012-09-11T11:27:10.387 に答える
5

onDetachedFromWindow新しいリスナーを登録する代わりに、カスタムViewコードでオーバーライドできます。

于 2014-10-05T08:44:23.883 に答える
4

私はマーマーが言ったことをその罠に陥ります:)

@Override
protected void onDetachedFromWindow() { I want to do something here, sometimes called sometimes not!!}

protected void onAttachedToWindow() {It is working fine, always}

このコードはにありCustomViewます。

呼び出しコードは次のとおりです。

    contentHolder.removeAllViews();
    // ... init my  CustomView   ...
    contentHolder.addView(myCustomView);
    contentHolder.requestLayout();// useless, not need
    contentHolder.invalidate();// useless, not need

なぜ機能しないのかを理解するには、AndroidAPIの内部に入る必要があります。

public void removeAllViews() {
    removeAllViewsInLayout();
    requestLayout();
    invalidate(true);
}

public void removeAllViewsInLayout() {
    final int count = mChildrenCount;
    if (count <= 0) {
        return;
    }

    final View[] children = mChildren;
    mChildrenCount = 0;

    final View focused = mFocused;
    final boolean detach = mAttachInfo != null;
    boolean clearChildFocus = false;

    needGlobalAttributesUpdate(false);

    for (int i = count - 1; i >= 0; i--) {
        final View view = children[i];

        if (mTransition != null) {
            mTransition.removeChild(this, view);
        }

        if (view == focused) {
            view.unFocus(null);
            clearChildFocus = true;
        }

        view.clearAccessibilityFocus();

        cancelTouchTarget(view);
        cancelHoverTarget(view);

        if (view.getAnimation() != null ||
                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
            addDisappearingView(view);
        } else if (detach) {
           view.dispatchDetachedFromWindow();
        }

        if (view.hasTransientState()) {
            childHasTransientStateChanged(view, false);
        }

        dispatchViewRemoved(view);

        view.mParent = null;
        children[i] = null;
    }

    if (clearChildFocus) {
        clearChildFocus(focused);
        if (!rootViewRequestFocus()) {
            notifyGlobalFocusCleared(focused);
        }
    }
}

キーはここにあります:

        if (view.getAnimation() != null ||
                (mTransitioningViews != null && mTransitioningViews.contains(view))) {

したがって、アニメーションがある場合(1つの場合は持っていますが9つの場合はありません)、は呼び出されず、onDetachedFromWindow()UI全体が混乱します:)

public void endViewTransition(View view) {
    if (mTransitioningViews != null) {
        mTransitioningViews.remove(view);
        final ArrayList<View> disappearingChildren = mDisappearingChildren;
        if (disappearingChildren != null && disappearingChildren.contains(view)) {
            disappearingChildren.remove(view);
            if (mVisibilityChangingChildren != null &&
                    mVisibilityChangingChildren.contains(view)) {
                mVisibilityChangingChildren.remove(view);
            } else {
                if (view.mAttachInfo != null) {
                    view.dispatchDetachedFromWindow();
                }
                if (view.mParent != null) {
                    view.mParent = null;
                }
            }
            invalidate();
        }
    }
}

繰り返しますが、アニメーションでも呼び出される場合があります。addDisappearingView(view);

受け入れられた答えは次のようなものを示唆しています:

    addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View v) {
        }

        @Override
        public void onViewDetachedFromWindow(View v) {
            System.out.println("MyCustomView.onViewDetachedFromWindow");
        }
    });

悲しいことに、アニメーションでは目的のテキストが印刷されません。

android.view.ViewGroup APIからのいくつかの重要なコード:

void dispatchViewRemoved(View child) {
    onViewRemoved(child);
    if (mOnHierarchyChangeListener != null) {
        mOnHierarchyChangeListener.onChildViewRemoved(this, child);
    }
}

public void onViewRemoved(View child) {
}

RelativeLayoutしたがって、このメソッドのをオーバーライドできます。私のアニメーションは無限のアニメーションであり、どのメソッドもすぐには呼び出されません。

無限のアニメーションがある場合、正しい方法は、すべてのビューを削除するを呼び出すときに、このコードを記述することです。

    if(contentHolder.getChildCount() > 0 ){
        View child0 = contentHolder.getChildAt(0);
        Animation animation = child0.getAnimation();
        if(animation != null) {
            animation.cancel();
            child0.clearAnimation();
        }
    }
    contentHolder.removeAllViews();

protected void onDetachedFromWindow()これで!と呼ばれます。

于 2017-05-06T10:28:12.200 に答える
0

Android KTX (Core KTX)ライブラリは、このための優れたソリューションを提供します。

この依存関係が必要になります:androidx.core:core-ktx:1.3.0

次に、関数 "doOnDetach"を呼び出して、ビューがウィンドウから削除されたときにコードを(1回)実行するように通知できます。

fun myInitCode() {
    ...
    myView.doOnDetach(this::doOnMyViewDetachFromWindow)
    ...
}

fun doOnMyViewDetachFromWindow(view: View) {
    ... put your image cleanup code here ...
}

ラムダを「doOnDetach」に渡すことができますが、実行する必要のある作業の量によっては、上記のメソッド参照の方がクリーンな場合があります。

doOnDetachの説明は次のとおりです。

androidx.core.view ViewKt.class public inline fun View.doOnDetach(crossinline action:(View)→Unit):Unit

このビューがウィンドウから切り離されたときに、指定されたアクションを実行します。ビューがウィンドウにアタッチされていない場合、アクションはすぐに実行されます。そうでない場合、アクションは、ビューが現在のウィンドウから切り離された後に実行されます。アクションは1回だけ呼び出され、その後すべてのリスナーが削除されます。

于 2020-07-21T09:30:23.987 に答える