Советы новичкам

Posted by - December 12, 2008

В основном это список произвольных мелких нюансов без сортировки и развития. Рекомендуется к быстрому прочтению, что-бы задействовалось подсознание :-).

Реализация itemRenderer-ов для грида

Никогда не ленитесь и создавайте все свои рендереры наследуя UIComponent или соответствующих контролов Label, CheckBox, TextInput. Никогда не используйте в рендерерах Box, Canvas — они безбожно тормозят.

Что такое mxml?

Что-бы понять суть, добавте параметр -keep-generated-actionscript компилятору флекса. После этого большинство вопросов как это работает, когда допустим биндинг и т.п. исчезнут сами собой.

Слушание событий

По возможности всегда подписывайтесь на события через mxml. Это плохой код:

private function onCreationComplete() : void {
	listView.addEventListener(RotatorsEvent.NEW_ROTATOR, baseEventsHandler);
	listView.addEventListener(RotatorsEvent.EDIT_ROTATOR, baseEventsHandler);
	listView.addEventListener(RotatorsEvent.DELETE_ROTATOR, baseEventsHandler);
	editView.addEventListener(RotatorsEvent.SAVE_ROTATOR, baseEventsHandler);
	editView.addEventListener(RotatorsEvent.CANCEL_ROTATOR, baseEventsHandler);
}

private function baseEventsHandler(event : RotatorsEvent) : void {
	switch (event.type) {
		case RotatorsEvent.NEW_ROTATOR : newRotatorAction(); break;
		case RotatorsEvent.EDIT_ROTATOR : editRotatorAction(); break;
		case RotatorsEvent.SAVE_ROTATOR : saveRotatorAction(event); break;
		case RotatorsEvent.DELETE_ROTATOR : deleteRotatorAction(); break;
		case RotatorsEvent.CANCEL_ROTATOR :
		default  : currentState = LIST_VIEW_STATE;
	}
}

Нужно писать так:

<view:RateCardListToolBar
	newRateCard="onNewRateCard(event)"
	loadRateCardSimpleItems="onLoadRateCardSimpleItems(event)"
	editRateCard="onEditRateCard(event)"/>

Жизненный цикл компонента

Обязательно найдите время для знакомства с очерёдностью и смыслом методов invalidateProperties(), commitProperties(), measure(), invalidateDisplayList(), updateDisplayList() и т.п. Не нужно пытаться что-либо рисовать в объекте graphics в конструкторе, для этого есть другое, более удачное место. Интересуйтесь!

Используйте code-behind

Зачастую использование тега <mx:Script /> допустимо только тогда, когда в нём будет не более одного-двух екранов кода. Если у вас огромный компонент обязательно выносите код в отдельный базовый класс:

Component.mxml:
<ComponentBase
	xmlns="*"
	xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Button
		label="button"
		click="onClick()" />
</ComponentBase>

ComponentBase.as:
package
{
	import mx.controls.Alert;

	public class ComponentBase
	{
		protected function onClick() : void
		{
			Alert.show("Я буду больше интересоваться внутренностями флекса",
				"Напоминание");
		}
	}
}

Event handlers

По-момему, нет ничего лучше чем называть методы хендлеров по такому конвеншену:

Для MouseEvent.CLICK — метод:

onClick(event : MouseEvent) : void

Для ListEvent.CHANGE для объекта с id=”customComponent” — метод:

onCustomComponentChange(event : ListEvent) : void

Избавляемся от противных предупреждений

Если у вас накопилось больше нуля предупреждений — срочной начинайте чистку. Вот, кстати, пример нелогичности Action Script, но тем не менее решаемый:

for each (var item : ItemType in items) {
	...code...
}

...code...

for each (var item : ItemType in items) {
	...code...
}

В таком коде вас ожидает Duplicate code definition warning. Исправить можно заменив последний цикл на такое:

for each (item in items) {
	...code...
}

Непреодолимый public

Все контролы в компоненте mxml имеют область видимости public, к сожалению так устроен мир. Это не значит что к ним можно свободно обращаться снаружи: customComponent.customButton.label = “very bad”, всегда нужно создавать соответствующие гетеры и сетеры: customComponent.buttonLabel = “very well”.

Binding

Во-первых, его нужно использовать. Подходы типа «Мы любим сами контролировать процесc присваивания данных» — пафос и лишняя головная боль. Пример максимально не эффективного кода:

if (!isExpand)
{
	activeDates.visible = false;
	hiatus.visible = false;
	startAirTime.visible = false;
	endAirTime.visible = false;
	daysAirTime.visible = false;
}
else
{
	activeDates.visible = true;
	hiatus.visible = true;
	startAirTime.visible = true;
	endAirTime.visible = true;
	daysAirTime.visible = true;
}

Нужно всего лишь пометь isExpand как [Bindable] и связать все контролы с ним в mxml.

Использование for each

Странно, но многие начинающие флексеры не знают о нём, что приводит к проблемам производительности. Нельзя:

for (var i : int = 0; i < result.length; i++)
{
	result[i].children = rateCard.rateCardsComparison;
}

Нужно:

for each(var item : DataType in result)
{
	item.children = rateCard.rateCardsComparison;
}

Изменение размера и позиции в updateDisplayList()

Глянем пример кода:

protected override  function updateDisplayList(unscaledWidth : Number,
	unscaledHeight : Number) : void
{
	super.updateDisplayList(unscaledWidth, unscaledHeight);

	if (horizontalScrollBar != null)
	{
		horizontalScrollBar.x = watchColumnEdge;
		horizontalScrollBar.width = width - watchColumnEdge;
	}
}

Так делать нельзя (диспачатся лишние события), нужно использовать методы move() и setActualSize().

Dynamic классы

Желательно отказаться от использования этого механизма. Только если нужно бысто заполнять коллекции или что-либо объектами типа {label : “Label”, handler : onSomething}.

11 Comments on Советы новичкам

Respond | Trackback

  1. Попробую еще больше повысить полезность статьи следующими комментариями:

    > Реализация itemRenderer-ов для грида томозит

    Да, конкретно – в 2-2.5 раза, что в большинстве случаев допустимо.
    http://riapriority.com/blogs/slon-vsapogah.php/2008/09/03/advanced_datagrid_itemrenderers_speed_ef

    > Используйте code-behind

    В текущей версии MXML таким способом я бы пользовался, только если есть человек mxml-дизайнер. Если такового нет – не стал (и не пользуюсь).

    > Event handlers

    Какие ни спорные Adobe Coding Conventions, но все же они есть:
    http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions
    И они предлагают другой вариант – button_clickHandler(…)

    > Использование for each

    Данный способ не дает никаких гарантий о порядке перебора объектов. Классический вариант (имхо):
    var array:Array = …;
    var n:int = array.length;
    var item:SomeType;
    for (var i:int = 0; i < n; i++)
    {
    item = SomeType(array[i]);

    }

    • tearaway_Tea says:

      Твоё тестирование рендереров запускали – классное! А code-behind нужен не для дизайнеров, а для разделения и властвования (хотя может быть это после ASP.NET такой подход принимается как единственный рациональный). Конвенш от Адоби – позорный, как и внутренность фреймворка, так что их предложения можно смело отвергать. И брать например от Microsoft или Sun.

      На сколько мне известно for each дает все гарантии, он перебирает елементы в том же порядке в каком они находятся в коллекции. А использование индекса, делает как минимум одно лишнее пробегание коллекци на каждой итерации цикла.

      • shish says:

        нет – for each не дает гарантии (так написано в стандарте) – то что оно сохраняет порядок – это особенность текущей реализации

        • tearaway_Tea says:

          Ну, я практически уверен, что эта особенность останется и во всех следующих реализациях =)

          • shish says:

            что-то я когда-то в каком-то треде читал: чувак писал что ему удалось создать условия когда порядок был не тот уже в текущей реализации…
            (подозреваю что достаточно использовать отсортированную коллекцию для того чтобы эти варианты начали различаться ;-) )

  2. Hi,

    I guess that some of these tips are obsolete in these days.

    1.По возможности всегда подписывайтесь на события через mxml

    Subscribing event listeners in MXML is good as soon as you have no intention to destroy the object in the future. This is a once-and-forever type of subscription.
    If you subscribe to events in AS, you can unsubscribe and most importantly, you can use subscription as a weak reference, so the subscription alone will not stop the GC from reclaiming the referred object.

    http://www.gskinner.com/blog/archives/2006/07/as3_weakly_refe.html

    2. Использование for each
    Do not use for each fro everything :)

    http://tech.groups.yahoo.com/group/flexcoders/message/132165

    There were plenty of discussions, like: do not use uint in for loops etc. Very simple tests are showing that this is not a case any more under FP version >=9.

    Cheers,
    Dmitri.

  3. Dmitriy says:

    На счёт itemRenderer: Если есть необходимость рендерить в гриде CheckBox и прочий фарш, оговоренный выше, моё имхо – делаем custom component на базе Canvas и пихаем туда все нужные примочки и itemRenderer делаем по нашей компоненте, еинственный момент : нужно создать класс на основе DataGrid где в теге Metadata описать события которые диспатчатся в нашей компоненте, и можем свободно ловить события и оперировать ими. Кстати лучше диспатчить пузырьковым методом :
    dispatchEvent(new Event(”Some_button_in our component_click”,true,true));
    (true,true – суть пузырькового метода)

    Такой вариант опробован нашей компанией и реализован в ряде проэктов.
    И не тупит

    • tearaway_Tea says:

      Есть мнение, что наследуя рендерер от Canvas мы будем тормозить. А другого нормального способа оповещения о изменениях рендерера, как только через пузырьковые события и нету.

  4. Mokus says:

    >>другого нормального способа оповещения о изменениях рендерера, как только через пузырьковые события и нету.

    Є ще тег component і outerDocument. Як на мене – найкращий варіант аідписки на події рендерера.

  5. foreground says:

    Мужики. . спасибо, класный обзор для начинающих мучиться с флекс )

Respond

Comments

Comments