子レイアウト(ビュー)で、ビューが親から削除されたときのコールバックはありますか?ビューが完了したら、いくつかの画像をリサイクルする必要があります。私は何をすべきかをウェブで探していましたが、まだ何も役に立ちませんでした。
4 に答える
私もこんなものを探していました。私が見つけることができる最高のものはView.OnAttachStateChangeListenerです。ビューがウィンドウに追加およびウィンドウから削除されたときのコールバックであるため、これが理想的であるとは思えません。親ではありませんが、私のニーズには十分です。
onDetachedFromWindow
新しいリスナーを登録する代わりに、カスタムView
コードでオーバーライドできます。
私はマーマーが言ったことをその罠に陥ります:)
@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()
これで!と呼ばれます。
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回だけ呼び出され、その後すべてのリスナーが削除されます。