gpt4 book ai didi

c# - Android View 对象复用--防止View重现时显示旧尺寸

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:42:57 25 4
gpt4 key购买 nike

编辑:另一条可能相关的信息:我看到问题的用例是选项卡切换。也就是说,我在选项卡 A 上创建 View X,离开选项卡 A 时将其删除,然后将其回收到选项卡 B。这就是问题发生的时候。这也正是我需要提高性能的时候。 . .

我正在研究我的 Android 应用程序的性能。我注意到我可以通过重用我们称为 MyLayout 的类的 View 对象来加快速度。 (它实际上是一个自定义的 FrameLayout 子类,但这可能并不重要。此外,这与 ListView 无关。)也就是说,当我完成一个 View 时,我没有让 GC 获取它,而是将它放入一个水池。当同一 Activity 需要另一个 MyLayout 对象时,我会从池中获取一个(如果可用)。这确实加快了应用程序的速度。但是我很难清除旧的尺寸信息。结果是,当我取回 View 时,一切正常,但在某些情况下,新 View 在使用新的大小信息进行布局之前会短暂出现。即使我在将 View 添加回层次结构之前或之后不久设置了新的 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.

添加 View 时:

所有尝试都调用以下子例程之一将 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 相同,但使用新的布局参数:

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

尝试 D:与 B 相同,但使用新的布局参数:

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

尝试 E:使用带有 layoutParams 参数的 AddView:

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

在所有五种情况下,问题在于即使 layoutParams 是正确的,在布局调整自身以适应新的 layoutParams 之前 View 对用户可见。

最佳答案

尝试在消息队列中执行这些事件(setLayoutParamsaddView)。

方案一)

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

方案二)

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);
}
});

我不确定这是否适用于您的情况。如果 setLayoutParamsaddView 被认为是内部 OS 实现中的消息,那么它会将下一个事件放入队列中,以便在执行前一个事件后执行。

关于c# - Android View 对象复用--防止View重现时显示旧尺寸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30547487/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com