Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 24.03.2011, 02:46
VitaliyKrivtsov вне форума Посмотреть профиль Отправить личное сообщение для VitaliyKrivtsov Посетить домашнюю страницу VitaliyKrivtsov Найти все сообщения от VitaliyKrivtsov
  № 1  
Ответить с цитированием
VitaliyKrivtsov
 
Аватар для VitaliyKrivtsov

блогер
Регистрация: Apr 2010
Сообщений: 99
Записей в блоге: 5
Отправить сообщение для VitaliyKrivtsov с помощью ICQ Отправить сообщение для VitaliyKrivtsov с помощью Skype™
Post Как улучшить класс APIConnection. Вопрос по обработке полученных данных.

Недавно в своем блоге писал о библиотеке для роботы с Вконтакте API. В библиотеке единственным обязательным классом служит APIConnection, который занимается контролем над потоком вызовов, а сами вызовы это VkontakteCall с самим сформированым запросом и обработчиками этого запроса. На экземпляры класса вешаются события успешной загрузки и ошибки в ответе а так же ошибки загрузки. Так вот товарищ cleptoman написал, что создания отдельного кола - это не то что совсем бы хотелось от библиотеки и лучше бы если был класс который рулит запросами и диспатчит события . Идея отличная только вот не могу остановиться на реализации.
Переписал APIConnection и теперь он выглядит вот так:
Смотрите следующий пост ( есть ограничения форума на количество символов в посте, пришлось даже удалить даже часть вода в классе ).

APIConnection теперь не наследует класс EventDispatcher, а реализует интерфейс IEventDispatcher. Сделано было для того что бы можно было использовать привычные addEventListener() и removeEventListener() но с другой реализацией. Теперь у каждого кола есть уникальный тип события который есть же сигом запроса это кола.
События вешаются как обычно, но тип события же не имеет ни какого значения так как формируеться совсем другой и нужен скорее для ясности происходящего. Событие вешается только после того как добавили в поток вызовов кол.
Много думал может просто сделать обычные колбеки и не заморачиватся с событиями. Или же вешать события на класс сколько будет удобно а в самом обработчике события проверять от какого вызова метода пришол ответ и потом выполнять действия. Или же отставить все как есть и нечего не изменять.
Код AS3:
private function responseHandler1(e:VKResponseEvent):void 
		{
			if ( e.method ) {
				trace( e.method );
			}
			e.target.removeEventListener( VKResponseEvent.RESPONSE, responseHandler1 );
		}
Хотелось бы услышать какие-нить мнения по этому поводу. Хочеться сделать либу максимально удобной в использовании.


Последний раз редактировалось VitaliyKrivtsov; 24.03.2011 в 02:52.
Старый 24.03.2011, 02:49
VitaliyKrivtsov вне форума Посмотреть профиль Отправить личное сообщение для VitaliyKrivtsov Посетить домашнюю страницу VitaliyKrivtsov Найти все сообщения от VitaliyKrivtsov
  № 2  
Ответить с цитированием
VitaliyKrivtsov
 
Аватар для VitaliyKrivtsov

блогер
Регистрация: Apr 2010
Сообщений: 99
Записей в блоге: 5
Отправить сообщение для VitaliyKrivtsov с помощью ICQ Отправить сообщение для VitaliyKrivtsov с помощью Skype™
Код AS3:
package phantom.api.vkontakte 
{	
 
	public class APIConnection implements IEventDispatcher
	{		
		private var dispatcher:EventDispatcher;
		// -- //		
		public static var httpMethod: String = "POST";		
 
		//public static const XML  :String = "XML";
		//spublic static const JSON :String = "JSON";		
 
		public static const POST :String = "POST";
		public static const GET  :String = "GET";
 
		private var wrapper:Object;
		private var flashVars:Object;	
		// -- //
		private static var instance:APIConnection;
		// -- //
		private static var _apiUrl   :String = "http://api.vkontakte.ru/api.php";
		private static var _format   :String = "XML";
		private static var _version  :String = "3.0"; 
		// -- // 
		private static var _apiId    :String;
		private static var _viewerId :String;
		private static var _userId   :String;
		private static var _secret   :String;
		private static var _sid      :String;		
		private static var _authKey  :String;
		private static var _group    :String;
		private static var _lcName   :String;
		// -- //
		private static var _domain   :String;
		private static var _scale    :int;
		private static var _width    :int;
		private static var _height   :int;
		private static var _swfUrl   :String;
		private static var _debug    :int;
		// -- // 
		private static var _test     :Boolean;
		private static var _isAppUser   :Boolean;
		private static var _viewerType  :int;		
		private static var _settings    :int;
		private static var _language    :int;
 
		private static var _delay:int = 300;
 
		//private var params:Array = new Array()/* of Parameter */;			
 
		private var commandQueues:Array = new Array()/* of VkontakteCall */;
		private var current:int = 0;
		private var timer:Timer;	
		// -- //		
		//private var requests:Vector.<URLLoader> = new Vector.<URLLoader>();
		private var requests:Array = new Array()/* of URLLoader */;
		private var listeners:Dictionary = new Dictionary()/* of Function */;
		// -- //
		private var loaders:Dictionary = new Dictionary()/* of URLLoader */;
 
		public function APIConnection() {
			dispatcher = new EventDispatcher( this );			
		}
 
		public function init( params:Object ):void 		
		{	
			timer = new Timer( _delay );	
			timer.addEventListener( TimerEvent.TIMER, timerHandler );	
 
			if ( params.wrapper ) wrapper = Object(params.wrapper);
			// -- //
			if ( params.auth_key ){
				_viewerType = new int( params.viewer_type );
				_settings   = new int( params.api_settings );
				_isAppUser  = new Boolean( params.is_app_user );
				_lcName     = new String(params.lc_name);	
				_userId     = new String(params.user_id);
				_group      = new String(params.group_id);
				_authKey    = new String(params.auth_key);
			}
			// -- //		
			if ( params.test ) _test              = new Boolean(params.test);	
			if ( params.api_url ) _apiUrl         = new String(params.api_url); 			 
			if ( params.api_id ) _apiId           = new String(params.api_id);	
			if ( params.viewer_id ) _viewerId     = new String(params.viewer_id);
			if ( params.secret ) _secret          = new String(params.secret);
			if ( params.version ) _version        = new String(params.version) else _version = new String("3.0");
			if ( params.sid ) _sid                = new String(params.sid);						   
			if ( params.format ) _format          = new String(params.format);
			// -- // 
 
		}
 
		public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false ):void
		{								
		    var loader:URLLoader = requests[requests.length - 1];/* requests as Vector.<URLLoader> */;	
			// -- //
			if ( !loaders[loader].flag/* loaders[loader] as Object */) return;	
			// -- //
			var str:String = loaders[loader].type;/* type события, для каждого запроса формируется уникальное имя события по его sig*/				
			listeners[listener] = str;/* запоминаем type события */
			loaders[loader].flag = false;		
			// -- //	
			dispatcher.addEventListener( str, listener, useCapture, priority, useWeakReference );					
		}
 
		public function removeEventListener( type:String, listener:Function, useCapture:Boolean = false ):void
		{
			var type:String = listeners[listener];				
			dispatcher.removeEventListener( type, listener, useCapture );
			// -- //
			delete listeners[listener];	
			// -- //
	    }
 
		public function dispatchEvent( event:Event ):Boolean
		{
			return dispatcher.dispatchEvent( event );
	    }    
 
        public function hasEventListener( type:String ):Boolean
		{
            return dispatcher.hasEventListener( type );
        }
 
		public function willTrigger( type:String ):Boolean
		{
			return dispatcher.willTrigger( type );
        }
		//////////////////////////////////////////////////////////////////////
		//
		// public methods
		//
		//////////////////////////////////////////////////////////////////////
 
		public function call( vkcall:*/*URLRequest else VkontakteCall*/ ):void
		{	
			if ( vkcall is URLRequest ) {				
				var loader:URLLoader = new URLLoader();					
				loader.addEventListener( Event.COMPLETE, completeHandler );
				loader.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
				// -- // 
				requests.push( loader );
				// -- //
				loaders[loader] = {flag:true, request:vkcall, method:vkcall.data.method, type:vkcall.data.sig}; 
				// -- //
				commandQueues.push( loader );
			} else if ( vkcall is VkontakteCall ) {
				commandQueues.push( vkcall );								
			}			
			// -- //
			if ( !timer.running ) {				
				timerHandler( );
				timer.start( );	
				timer.addEventListener( TimerEvent.TIMER, timerHandler );
			}			
		}
 
		private function completeHandler( e:Event ):void 
		{
			var loader:URLLoader = URLLoader(e.target);
			// -- //
			var object:Object = loaders[loader];
			// -- //
			var urlRequest:URLRequest = object.request;
			var data:String = String(e.target.data);
 
			if ( urlRequest.data.format == "XML" ) {
				var fxml:XML = XML( data );		
				//trace( fxml );
				//if ( fxml.name() == "response" ) xmlResponseHandler( fxml );
				//else if ( fxml.name() == "error" ) xmlErrorHandler( data, fxml );	
			} else if ( urlRequest.data.format == "JSON" ) {				
	            var fjson:Object = JSON.decode( data );					
				//if ( fjson.response != undefined ) jsonResponseHandler( fjson );
				//else if ( fjson.error != undefined ) jsonErrorHandler( data, fjson );
			}	
			// -- // 		
			dispatchEvent( new VKResponseEvent( object.type, this, data, object.method, false, false) );
			// -- //
			object = null;/* обнуляем object */		
			delete loaders[loader];/* удаляем object из loaders, в противном случаи object не удалиться из памяти */
			// -- // 
			loader.removeEventListener( Event.COMPLETE, completeHandler );			
		}
 
		private function ioErrorHandler( e:IOErrorEvent ):void 
		{
			dispatchEvent( new IOErrorEvent(e.type, false, false) );			
		}
 
		public function close( ):void
		{
			timer.stop( );			
			// -- //
			for ( var i:int = 0; i < commandQueues.length; i++ ) {
				var vkcall:VkontakteCall = commandQueues[i] as VkontakteCall;
				vkcall.close( );
			}
			// -- //
			commandQueues.length = 0;
			current = 0; 
		}
 
		private function timerHandler( e:TimerEvent = null ):void
		{	
			if ( current != commandQueues.length ) {
				/* */
				if ( commandQueues[current] is URLLoader ) {
					var loader:URLLoader = commandQueues[current];
					loader.load( loaders[loader].request/*as URLRequest*/ );
				} else {
					var vkontakteCall:VkontakteCall = commandQueues[current];
			        vkontakteCall.load( );
				}				
				// -- //
				current++;	
				// -- //
			} else {
				timer.stop( );
				commandQueues.length = 0;
				current = 0;
				timer.removeEventListener( TimerEvent.TIMER, timerHandler );				
			}
		}				
		//////////////////////////////////////////////////////////////////////
		//
		// public static functions 
		//
		///////////////////////////////////////////////////////////////////////
		/**
		 * 
		 * @return
		 */	
		public static function getInstance( ):APIConnection 
		{
			if ( !instance ) { instance = new APIConnection() };
			return instance;						
		}
 
		/**
		 *  
		 * @param  parameters 
		 * @return URLRequest
		 */
		public static function req( parameters:Vector.<Parameter> ):URLRequest 
		{	
			// -- //
			var params:Array = []; 
 
			for ( var j:int = 0; j < parameters.length; j++ ) {
				params.push( parameters[j] as Parameter );
			}
			// -- //		
			params.push( new Parameter("api_id", _apiId) );			
			params.push( new Parameter("format", _format) );
			params.push( new Parameter("v", _version) );
		    if ( _test ) params.push( new Parameter("test_mode", "1") );
			// -- // 
			params.sortOn( "name" );				
			// -- //
			//params.push( new Parameter("sig", getSig(params)) );
			params.push( new Parameter("sig", MD5.hash(new String( _viewerId + params.join("") + _secret)) ) );
			//;
			if( _version != "2.0" ) params.push( new Parameter("sid", _sid) );
			// -- //
			var urlRequest:URLRequest = new URLRequest( );
			urlRequest.url    = _apiUrl;
			urlRequest.method = httpMethod;
 
			var urlVariables:URLVariables = new URLVariables( );
			// -- //	
			for ( var i:int = 0; i < params.length; i++ ){
			    urlVariables[params[i].name] = params[i].value;	
			}
			// -- //
			urlRequest.data = urlVariables;
			//--//
			params.length = 0;
			params = null;
			// -- //
			return urlRequest;
		}
}
}
Добавлено через 18 часов 16 минут
Неужели вот это всем все равно? Как бы не только для себя делаю.

Старый 24.03.2011, 21:07
VitaliyKrivtsov вне форума Посмотреть профиль Отправить личное сообщение для VitaliyKrivtsov Посетить домашнюю страницу VitaliyKrivtsov Найти все сообщения от VitaliyKrivtsov
  № 3  
Ответить с цитированием
VitaliyKrivtsov
 
Аватар для VitaliyKrivtsov

блогер
Регистрация: Apr 2010
Сообщений: 99
Записей в блоге: 5
Отправить сообщение для VitaliyKrivtsov с помощью ICQ Отправить сообщение для VitaliyKrivtsov с помощью Skype™
Неужели вот это всем все равно? Как бы не только для себя делаю.

Старый 24.03.2011, 23:48
maxkar вне форума Посмотреть профиль Отправить личное сообщение для maxkar Найти все сообщения от maxkar
  № 4  
Ответить с цитированием
maxkar

Регистрация: Nov 2010
Сообщений: 497
Ну могу покритиковать. Берем пример из блога и смотрим, что приходится писать при каждом вызове:
Код AS3:
/*>>*/var vkcall:VkontakteCall = new VkontakteCall(); /*<<*/
var fields:Array = [...];
vkcall./*>>*/call(/*<<*/ Users.getProfiles( [APIConnection.viewerId], fields /*>>*/) as URLRequest /*<<*/);			
 
/*>>*/vkcall.addEventListener( VKResponseEvent.RESPONSE, /*<<*/responseHandler );
/*>>*/vkcall.addEventListener( VKErrorEvent.ERROR, /*<<*/ errorHandler );
Все выделенное нужно писать на каждый вызов. При этом никакой информации о том, что же мы хотим делать, данные фрагменты не несут. Кстати, что там vkresponseEvent в данном случае передается? Не нужно ли там кучу всего вручную разбирать?

Пример того, как это могло бы быть:
Код AS3:
APIConection.users.getProfiles([UserField.NAME, UserField.NICKNAME, UserField.UID, UserField.PHOTO_BIG], usersReceived, errorHandler);
 
function usersReceived(users : Array /* or Object */) {
  for each (var o : Object in users)
    trace(o[UserField.NAME] + " " +  o[UserField.NICKNAME] + " " + o[UserField.UID] + o[UserField.PHOTO_BIG]);
}
Там в результате - список пользователей (может быть object с ID пользователей в качестве ключей). У каждого пользователя - запрошенные поля. Не парсить же ответ вручную. Более того, если парсить вручную, нужно сразу же писать и обработчик "не распарсилось"...

Итого - ровно одна строчка на запрос вместо 5. И в обработчике результата работа идет не с абстрактными row (или что там еще есть) а со вполне конкретными пользователями, которых мы запрашивали (или не запрашивали).

По поводу событий. Скажите, а как вы собираетесь обрабатывать события в обработчиках? Точно хочется получать весь спам от "неизвестных" запросов? Потому что для "своих" запросов обработчики то известны и их можно коллбэком передать.

Так как методов много, сразу все писать будет долго. Я бы делал удобное (именно удобное для использования в количестве 20-30 раз в проекте) API с минимумом удобных методов - полным разбором результатов, говорящими параметрами и т.п. А затем все это при необходимости расширял (практически все затем делается достаточно просто). Собственно, именно так и делаю

Создать новую тему Ответ Часовой пояс GMT +4, время: 17:03.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 17:03.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.