Wil*_*sch 12 c# layout android object-pooling android-layout
编辑:还有一条可能相关的信息:我看到问题的用例是制表切换.也就是说,我在选项卡A上创建视图X,在离开选项卡A时将其删除,然后将其回收到选项卡B.这就是问题发生的时候.这也正是我需要性能提升的时候...
我正在研究我的Android应用程序的性能.我注意到我可以通过重用我们称之为MyLayout的类的View对象来加快速度.(它实际上是一个自定义的FrameLayout子类,但这可能无关紧要.而且,这与ListView无关.)也就是说,当我完成View时,而不是让GC得到它,我把它放入一个游泳池.当同一活动想要另一个MyLayout对象时,我从池中抓取一个,如果可用的话.这确实加快了应用程序的速度.但是我很难清除旧的尺寸信息.结果是当我抓回View时,事情通常很好,但在某些情况下,新视图会在使用新的大小信息布局之前短暂出现.即使我在将View添加回层次结构之前或之后不久设置了新的LayoutParams,也会发生这种情况(我已尝试过两种方式;但都没有帮助).因此,在尺寸达到正确尺寸之前,用户会看到旧尺寸的短暂(可能是100毫秒)闪光.
我想知道是否/如何解决这个问题.下面,通过C#/ Xamarin,我尝试了一些东西,但没有一个有用:
回收时:
//Get myLayoutParams, then:
myLayoutParams.Width = 0;
myLayoutParams.Height = 0;
this.SetMeasuredDimension(0, 0);
this.RequestLayout();
Run Code Online (Sandbox Code Playgroud)
在返回之前或之后 - 在同一个事件循环中,将布局添加到其新父级:
// 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;
Run Code Online (Sandbox Code Playgroud)
我也试过把它带回来,但问题仍然存在:
FrameLayout.LayoutParams layoutParams = . . . // the same LayoutParams as above
parent.AddView(viewThatIsBeingRecycled, layoutParams);
Run Code Online (Sandbox Code Playgroud)
编辑:每个请求,我尝试过的一些序列.所有人都遇到同样的问题.基本问题是即使LayoutParams是正确的,布局本身也不正确,因为实际布局还没有发生.
回收时间:
尝试A:
this.RemoveFromHierarchy();
// problem is that the width and height are retained
Run Code Online (Sandbox Code Playgroud)
尝试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.
Run Code Online (Sandbox Code Playgroud)
添加视图时:
所有尝试都会调用以下子例程之一来将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;
}
Run Code Online (Sandbox Code Playgroud)
尝试A:
newParent.AddView(viewThatIsBeingRecycled);
// get layoutParams of the view, then:
SyncExistingLayoutParamsToModel(myLayoutParams, model);
Run Code Online (Sandbox Code Playgroud)
尝试B:与A相同,但顺序相反:
// get layoutParams of the view, then:
SyncExistingLayoutParamsToModel(myLayoutParams, model);
newParent.AddView(viewThatIsBeingRecycled);
Run Code Online (Sandbox Code Playgroud)
尝试C:与A相同,但使用新的layoutParams:
newParent.AddView(viewThatIsBeingRecycled);
FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.LayoutParams = layoutParams;
Run Code Online (Sandbox Code Playgroud)
尝试D:与B相同,但是有了新的layoutParams:
FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
viewThatIsBeingRecycled.LayoutParams = layoutParams;
newParent.AddView(viewThatIsBeingRecycled);
Run Code Online (Sandbox Code Playgroud)
尝试E:使用带有layoutParams参数的AddView:
FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
newParent.AddView(viewThatIsBeingRecycled, layoutParams);
Run Code Online (Sandbox Code Playgroud)
在所有五种情况下,问题是即使layoutParams是正确的,在布局将自身调整为新的layoutParams之前,视图也会对用户可见.
我遇到了完全相同的问题,除了在本机 android 上,而不是在 xamarin 上。
拥有自己的测试场景,使调试问题变得更加容易。我似乎已经通过将特定视图的右侧和左侧设置为 0 来修复它,就在将其从其父级中删除之后并将其添加到另一个视图之前:
((ViewGroup)view.getParent()).removeView(view);
view.setRight(0);
view.setLeft(0);
otherLayout.addView(view);
Run Code Online (Sandbox Code Playgroud)