12

編集:関連する可能性のある情報のもう1つの部分:問題が発生するユースケースは、タブの切り替えです。つまり、タブ A にビュー X を作成し、タブ A を離れるときにビュー X を削除し、タブ B に再利用します。そのときに問題が発生します。これはまさに、パフォーマンスの向上が必要なときでもあります。. .

Android アプリのパフォーマンスに取り組んでいます。MyLayout と呼ぶクラスの View オブジェクトを再利用することで、作業を高速化できることに気付きました。(これは実際にはカスタムの FrameLayout サブクラスですが、それはおそらく問題ではありません。また、これは ListView 関連ではありません。)つまり、ビューを使い終わったら、GC に取得させるのではなく、プール。同じアクティビティが別の MyLayout オブジェクトを必要とする場合、利用可能な場合はプールから 1 つ取得します。これにより、実際にアプリが高速化されます。しかし、古いサイズ情報をクリアするのに苦労しています。その結果、ビューを元に戻すと、通常は問題ありませんが、場合によっては、新しいビューが新しいサイズ情報でレイアウトされる前に一時的に表示されます。これは、ビューを階層に戻す直前または直後に新しい LayoutParams を設定しても発生します (両方の方法を試しましたが、どちらも役に立ちません)。したがって、ユーザーは、正しいサイズになる前に、古いサイズの短い (おそらく 100 ミリ秒) フラッシュが表示されます。

これを回避できるかどうか、またはどのように回避できるか疑問に思っています。以下は、C#/Xamarin を介して、私が試したいくつかのことですが、どれも役に立ちません。

リサイクル時:

//Get myLayoutParams, then:
myLayoutParams.Width = 0;
myLayoutParams.Height = 0;
this.SetMeasuredDimension(0, 0);
this.RequestLayout();

戻す直前または直後 -- レイアウトを新しい親に追加する同じイベント ループ内:

// a model object has already computed the desired x, y, width, and height
// It's taken into account screen size and the like; the Model's sizes
// are definitely what I want.
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams (model.width, model.height);
layoutParams.LeftMargin = model.x;
layoutParams.TopMargin = model.y; 
this.LayoutParameters = layoutParams;

また、以下のように元に戻そうとしましたが、問題はまだ残っています:

FrameLayout.LayoutParams layoutParams = . . .  // the same LayoutParams as above
parent.AddView(viewThatIsBeingRecycled, layoutParams);

編集:リクエストごとに、私が試したシーケンスのいくつか。すべて同じ問題に苦しんでいます。基本的な問題は、LayoutParams が正しくても、実際のレイアウトがまだ行われていないため、レイアウト自体が正しくないことです。

リサイクル時間:

試行 A:

this.RemoveFromHierarchy();
// problem is that the width and height are retained

試行 B:

//Get myLayoutParams, then:
myLayoutParams.Width = 0;
myLayoutParams.Height = 0;
this.SetMeasuredDimension(0, 0);
this.RequestLayout();
this.RemoveFromHierarchy();
//problem is that even though layout has been requested, it does not actually happen.  
//Android seems to decide that since the view is no longer in the hierarchy,
//it doesn't need to do the actual layout.  So the width and height
//remain, just as they do in attempt A above.

ビューを追加し直す場合:

すべての試行で、次のサブルーチンのいずれかを呼び出して、LayoutParams をモデルに同期します。

public static void SyncExistingLayoutParamsToModel(FrameLayout.LayoutParams layoutParams, Model model) {
  layoutParams.TopMargin = model.X;
  layoutParams.LeftMargin = model.Y;
  layoutParams.Width = model.Width;
  layoutParams.Height = model.Height;
}

public static FrameLayout.LayoutParams CreateLayoutParamsFromModel(Model model) {
  FrameLayout.LayoutParams r = new FrameLayout.LayoutParams(model.Width, model.Height);
  r.LeftMargin = x;
  r.TopMargin = y;
  return r;
}

試行 A:

newParent.AddView(viewThatIsBeingRecycled);
// get layoutParams of the view, then:
SyncExistingLayoutParamsToModel(myLayoutParams, model);

試行 B: A と同じですが、順序が逆です。

// get layoutParams of the view, then:
SyncExistingLayoutParamsToModel(myLayoutParams, model);
newParent.AddView(viewThatIsBeingRecycled);

試行 C: A と同じですが、新しい layoutParams を使用します。

newParent.AddView(viewThatIsBeingRecycled);
FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.LayoutParams = layoutParams;

試行 D: B と同じですが、新しい layoutParams を使用します:

FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.LayoutParams = layoutParams;
newParent.AddView(viewThatIsBeingRecycled);

試行 E: layoutParams 引数を取る AddView を使用します。

FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
newParent.AddView(viewThatIsBeingRecycled, layoutParams);

5 つのケースすべてにおいて、問題は、layoutParams が正しい場合でも、レイアウトが新しい layoutParams に合わせて調整される前に、ビューがユーザーに表示されることです。

4

5 に答える 5

2

これらのイベント (setLayoutParamsおよびaddView) をメッセージ キューで実行してみてください。

解決策 1 )

FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.setLayoutParams(layoutParams);
viewThatIsBeingRecycled.post(new Runnable() {
            @Override
            public void run() {
                newParent.AddView(viewThatIsBeingRecycled);
            }
        });

解決策 2 )

FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.setLayoutParams(layoutParams);
viewThatIsBeingRecycled.setVisibility(View.INVISIBLE);
newParent.AddView(viewThatIsBeingRecycled);
newParent.post(new Runnable() {
            @Override
            public void run() {
               viewThatIsBeingRecycled.setVisibility(View.VISIBLE); 
            }
        });

これがあなたの場合に機能するかどうかはわかりません。setLayoutParamsorが内部 OS 実装でメッセージと見なされる場合addView、前のイベントが実行されると実行されるように、次のイベントをキューに入れます。

于 2015-06-03T10:09:43.127 に答える
1

いつものように、任意のビューの位置/配置を更新するには、invalidate() を使用する必要があります。

抜け出すためのハックな方法を提供したくありませんが、それでもこの投稿を見てほしい. requestLayout()ビューの無効化を引き起こさない可能性があります。

android:hardwareAccelerated="true"また、マニフェストに追加してみてください。

于 2015-06-03T09:17:07.400 に答える