EDIT: Еще одна часть, возможно, релевантная информация: Вариант использования, в котором я вижу проблему, - это переключение табуляции. То есть, я создаю представление X на вкладке А, удаляю его, оставляя вкладку А, а затем перерабатываю ее в вкладку В. Это происходит при возникновении проблемы. Это также точно, когда мне нужно увеличение производительности.,.
Я работаю над производительностью своего Android-приложения. Я заметил, что могу ускорить процесс повторного использования объектов вида класса, которые мы будем называть MyLayout. (Это фактически собственный подкласс FrameLayout, но это, вероятно, не имеет значения. Кроме того, это не связанный с ListView.) То есть, когда я закончил просмотр, вместо того, чтобы позволить GC получить его, я положил его в бассейн. Когда тот же самый объект требует другого объекта MyLayout, я хватаю его из пула, если он доступен. Это действительно ускоряет работу приложения. Но мне нелегко очистить информацию о старом размере. В результате, когда я захватываю представление назад, все нормально, но в некоторых случаях новый вид кратко появляется до того, как он будет выложен с новой информацией о размере. Это происходит, даже если я установил новые LayoutParams незадолго до или после добавления представления обратно в иерархию (я пробовал в обоих направлениях, ни один из них не помогает). Таким образом, пользователь видит кратковременную (возможно, 100 мс) вспышку старого размера, прежде чем она вернется к правильному размеру.
Мне интересно, как и как я могу обойти это. Ниже, через С#/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 taken into account screen size and the like; the Model 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);
EDIT: по запросу некоторые из последовательностей, которые я пробовал. Все страдают от одной и той же проблемы. Основная проблема заключается в том, что, хотя 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: использование AddView, которое принимает аргумент layoutParams:
FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model);
newParent.AddView(viewThatIsBeingRecycled, layoutParams);
Во всех пяти случаях проблема заключается в том, что даже если layoutParams верны, представление становится видимым пользователю до того, как макет настраивается на новые layoutParams.