Перейти к содержанию
Fire Monkey от А до Я

Евгений Корепов

Пользователи
  • Постов

    738
  • Зарегистрирован

  • Посещение

  • Победитель дней

    100

Весь контент Евгений Корепов

  1. Вы можете поступить следующим образом - сразу создать нужное количество итемов и задать им высоту (или среднюю высоту) готово итема. Это будет очень быстро, по крайней мере для нескольких тысяч итемов время менее секунды на среднем телефоне. А потом динамически наполнять их данными. P.S Не забудьте отключить события ListViewUpdatingObjects и ListViewUpdateObjects на время создания итемов.
  2. Попробуйте избавится от ImageList на время тестов, замените на TArray<TBitmap> к примеру. Так же попробуйте после oConnectImage.ImageIndex:=r; делать oConnectImage.Bitmap.SaveToFile('d:\0\'+Автоинкремент+'.jpg'). У меня в подобной ситуации несколько процентов картинок в папке 'd:\0\' были черными, видимо пустые, отказался по этой причине от связки ImageList и ListView.
  3. Вот так сделайте: procedure TForm1.LsvObjectsUpdateObjects(const Sender: TObject; const AItem: TListViewItem); var ... oConnectImage: TListItemImage; r: integer; begin r:=Random(ImageList1.Count); oConnectImage:=aItem.Objects.FindDrawable('ConnectImage') as TListItemImage; if (oConnectImage<>nil) then begin oConnectImage.OwnsBitmap:=True; oConnectImage.ImageIndex:=r; end; ... end; Добавьте строчку oConnectImage.OwnsBitmap:=True. В соседней теме я долго бился над этим.
  4. Напишите свой, "правильный" код если хотите доказать что TThread.ForceQueue работает в андроиде и я ошибаюсь. К чему этот бесполезный флуд?
  5. Все с ней хорошо, ведь там есть TThread.Synchronize(Nil, procedure begin Memo.Lines.Add(LMessage); end); К тому же это упрощенный вариант, в рабочем вместо Memo использовалась отсылка данных на сервер логов. Результат тот же.
  6. Добавил запрос https://quality.embarcadero.com/browse/RSP-17841 , хотя их никто не читает...
  7. TThread.ForceQueue не работает в Android. Но можно утешить себя тем, что отлично работает в Windows ;-) Код следующий: unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo, FMX.Controls.Presentation, FMX.ScrollBox; type TForm1 = class(TForm) Memo: TMemo; procedure FormShow(Sender: TObject); private { Private declarations } public { Public declarations } procedure MyLog(AMessage : String); procedure TestForceQueue; end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.TestForceQueue; begin MyLog('In main thread start'); TThread.ForceQueue(Nil, procedure begin MyLog('In ForceQueue start'); TThread.Sleep(2000); MyLog('In ForceQueue stop'); end); MyLog('In main thread stop'); end; procedure TForm1.FormShow(Sender: TObject); begin TestForceQueue; end; procedure TForm1.MyLog(AMessage : String); Var ATime : String; LMessage : String; begin DateTimeToString(ATime, 'dd.mm.yyyy hh.nn.ss.zzz', Now); LMessage:=ATime + ' ' + AMessage; TThread.Synchronize(Nil, procedure begin Memo.Lines.Add(LMessage); end); end; end. В Windows все работает как ожидается: В андроиде ситуация следующая: Т.е. нифига не работает. Тестовый проект прилагаю. test094 ForceQueue test.7z
  8. Установите свойство ListView.PullToRefresh в True.
  9. Создал запрос https://quality.embarcadero.com/browse/RSP-17813 , проголосуйте кому не лень. Спасибо.
  10. Обнаружил очередной глюк Tokyo - сломали Text в Android. А именно порушили раскраску символов Юникода. Воспроизводится просто : procedure TFormMain.FormCreate(Sender: TObject); Var Text1: TText; begin Text1:=TText.Create(Self); Text1.Text:='|' + Char($2713) + '|'; Text1.Font.Size:=48; Text1.Color:=TAlphaColorRec.Red; Text1.Align:=TAlignLayout.Client; Text1.TextSettings.HorzAlign:=TTextAlign.Center; Text1.TextSettings.VertAlign:=TTextAlign.Center; FormMain.AddObject(Text1); end; На первом скриншоте этот код выполнен в Berlin, все выглядит как задуманно. На втором скриншоте этот же код в Tokyo.
  11. Вы про global.pas? Если про него, то как то так : unit global; interface uses System.Classes, {IdHTTP,}System.Net.HTTPClient, SysUtils, FMX.Notification; /// <summary> /// Процедура регистрации устройства. /// </summary> /// <param name="DeviceID"> /// ID регистрируемого устройства /// </param> /// <param name="DeviceToken"> /// Токен регистрируемого устройства /// </param> procedure RegisterDevice(DeviceID : string; DeviceToken : string); /// <summary> /// Процедура отправки Push сообщения на сервер. /// </summary> /// <param name="MessageText"> /// Текст отправляемого сообщения /// </param> procedure SendPush(MessageText : string); /// <summary> /// Процедура вывода сообщения из приложения. /// </summary> /// <param name="MessageText"> /// Текст выводимого сообщения /// </param> /// <param name="BadgeNumber"> /// Число выводимое на иконку приложения /// </param> procedure ShowNotification(MessageText : string; BadgeNumber : integer); const // Доменное имя сайта DOMAIN: string = 'http://example.ru/'; implementation procedure RegisterDevice(DeviceID : string; DeviceToken : string); var // Подключение для передачи данных httpconnect : THTTPClient; AQuery : String; begin try // Создаём подключение httpconnect := THTTPClient.Create; // Указываем данные для отправки AQuery:='?action=register-device&did=' + DeviceID + '&token=' + DeviceToken; {$ifdef ANDROID} AQuery:=AQuery + '&platform=android'; {$else} AQuery:=AQuery + '&platform=ios'; {$endif} // Отправляем запрос httpconnect.Get(DOMAIN + 'push.php' + AQuery); finally // Отключаемся и освобождаем память httpconnect.free end; end; procedure SendPush(MessageText : string); var // Подключение для передачи данных httpconnect : THTTPClient; AQuery : String; begin try // Создаём подключение httpconnect := THTTPClient.Create; // Указываем данные для отправки AQuery:='?action=send-push&text=' + MessageText; // Отправляем запрос httpconnect.Get(DOMAIN + 'push.php' + AQuery); finally // Отключаемся и освобождаем память httpconnect.Free; end; end; procedure ShowNotification(MessageText : string; BadgeNumber : integer); var NotificationC: TNotificationCenter; Notification: TNotification; begin // Создаём центр уведомлений и уведомление для отправки NotificationC := TNotificationCenter.Create(nil); Notification := NotificationC.CreateNotification; try // Если центр уведомлений поддерживается системой if NotificationC.Supported then begin // Устанавливаем текст сообщения Notification.AlertBody := MessageText; // Включаем звук при выводе сообщение Notification.EnableSound := true; // Устанавливаем цифру на иконке приложения Notification.Number := BadgeNumber; NotificationC.ApplicationIconBadgeNumber := BadgeNumber; // Выводим сообщение из приложения NotificationC.PresentNotification(Notification); end; finally // Очищаем переменные Notification.DisposeOf; NotificationC.Free; NotificationC.DisposeOf; end; end; end.
  12. Отличная статья! Но добавлю один нюанс - функция function pushSend($title, $text, $tokens, $server_key) реализована не до конца, дело в том что у FCM есть одно ограничение - отправка не больше 1000 токенов за раз. Сам на это напоролся и не мог понять почему части пользователей рассылки не приходят (рассылка велась по регионам России, общее количество около 100 тысяч). Пришлось накидать промежуточную функцию для разбивки на пакеты по 1000 штук: function SendGCMMessagesPacket($apiKey, $DevicesTokenArray, $message, $title, $DBLink, $TableName, $MyLog_GCM_file) { if (count($DevicesTokenArray)==0) { MyLog($MyLog_GCM_file, "Token Array is 0, skip sending"); return(0); } $Count_Success = 0; $DeviceCountMax = 1000; $DeviceCountIndex = 0; $DevicesTokenPacketArray = array(); $gcpm = new GCMPushMessage($apiKey); while ($DeviceCountIndex<=count($DevicesTokenArray)) { $DevicesTokenPacketArray = array_slice($DevicesTokenArray, $DeviceCountIndex, $DeviceCountMax); MyLog($MyLog_GCM_file, "Packet send: start index $DeviceCountIndex, count ".count($DevicesTokenPacketArray)); $gcpm->setDevices($DevicesTokenPacketArray); $ResponceJSON = $gcpm->send($message, array('title' => $title)); $Count_Success = $Count_Success + AnalyzeResponse($DevicesTokenPacketArray, $ResponceJSON, $DBLink, $TableName, $MyLog_GCM_file); MyLog($MyLog_GCM_file, $ResponceJSON); $DeviceCountIndex = $DeviceCountIndex + $DeviceCountMax; } return($Count_Success); } Функция AnalyzeResponse анализирует ответ и помечает в базе не зарегистрированные токены как неактивные function AnalyzeResponse($DevicesTokenArray, $ResponceJSON, $DBLink, $TableName, $MyLog_GCM_file) { $Count_Success = 0; $ResponceArray = json_decode($ResponceJSON, true); if (isset($ResponceArray['results'])) { $Index = 0; foreach ($ResponceArray['results'] as $key => $value){ if (isset($value['error'])) { if (isset($DevicesTokenArray[$Index])) { MyLog($MyLog_GCM_file, $DevicesTokenArray[$Index].' : '.$value['error']); $query = "UPDATE $TableName SET Active = 0 WHERE DeviceToken = '$DevicesTokenArray[$Index]'"; $mysql_result = mysqli_query($DBLink, $query); } } else { $Count_Success = $Count_Success + 1; } $Index = $Index + 1; } } return($Count_Success); }
  13. Не используйте TIdHTTP, с ним будут проблемы. Post тоже не обязательно, вот простой работающий код : Var AHTTPClient : THTTPClient; HTTPQuery : String; begin HTTPQuery:=APIURL+'?DeviceID='+HDevicePushParams.DeviceID+'&DeviceToken='+HDevicePushParams.DeviceToken; AHTTPClient:=THTTPClient.Create; AHTTPClient.Get(HTTPQuery); AHTTPClient.Free; end; Вместо AHTTPClient.Get(HTTPQuery), можно использовать асинхронный запрос AHTTPClient.BeginGet(HTTPQuery), тогда приложение не будет записать при недоступности сервера или проблемах с связью.
  14. Кстати, если кто объяснит что делает строчка ListItemImage.OwnsBitmap:=True, буду безмерно благодарен. Не люблю копипастить, без понимания что именно делает код. А лезть в исходники пока некогда.
  15. Блин! У меня нет слов! Проблема решилась многочасовым гугленьем. Самое смешное - решение нашел на этом форуме в сообщении http://fire-monkey.ru/topic/3014-ne-otobrazhaetsya-tlistitemimage/?do=findComment&comment=18113 , спасибо огромное @DimArt за решение! Вся проблема была в недокументированном свойстве OwnsBitmap, достаточно после загрузки изображения в ListItemImage.Bitmap добавить строчку ListItemImage.OwnsBitmap:=True; И все начинает отлично работать под Android. Документация ембаркадеро говорит нам о этом свойстве следущее "Embarcadero Technologies does not currently have any additional information." (http://docwiki.embarcadero.com/Libraries/Tokyo/en/FMX.ListView.Types.TListItemImage.OwnsBitmap). Б*%дь, ну как так то? У меня одни маты, два дня просраны вхолостую... Итоговый, работоспособный код функции SetupImageObject ниже function SetupImageObject(const AName : String; AWidth, AHeight, X , Y : Single; AAlign, AVertAlign: TListItemAlign) : TListItemImage; Var AImageURL : String; begin Result:=TListItemImage(AItem.View.FindDrawable(AName)); if Result=Nil then begin Result:=TListItemImage.Create(AItem); AImageURL:=AItem.Data['ImageURL'].AsString; Result.Bitmap:=LoadImageFromURL(AImageURL); Result.OwnsBitmap:=True; end; Result.Name:=AName; Result.Width:=AWidth; Result.Height:=AHeight; Result.PlaceOffset.X:=X; Result.PlaceOffset.Y:=Y; Result.Align:=AAlign; Result.VertAlign:=AVertAlign; Result.ScalingMode:=TImageScalingMode.StretchWithAspect; end;
  16. Господа и товарищи, помогите тупому мне! Столкнулся с странным. Под windows все отлично работает, а под android не могу добиться загрузки картинок. Мозг уже сломал. Собрал тестовый проект - в ListView (DynamicAppearance) добавляем 4 ListViewItem, в ListViewUpdatingObjects все создаем и грузим картинки из инета (потоки и прочее убрал для упрощения). Картанка слева, текст (URL) справа, проще некуда. Прилагаю к сообщению архив проекта и код. unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, FMX.ListView, System.Net.HTTPClient, FMX.Objects; type TFormMain = class(TForm) ListView: TListView; procedure ListViewUpdatingObjects(const Sender: TObject; const AItem: TListViewItem; var AHandled: Boolean); procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } ListViewUpdate : Boolean; procedure MyListViewUpdateObjects(const AListView: TListView; const AItem: TListViewItem); procedure InitListView(AListView : TListView); function LoadImageFromURL(AURL : String) : TBitmap; end; var FormMain: TFormMain; implementation {$R *.fmx} procedure TFormMain.FormCreate(Sender: TObject); begin ListViewUpdate:=False; end; procedure TFormMain.FormShow(Sender: TObject); begin InitListView(ListView); end; procedure TFormMain.InitListView(AListView : TListView); Var AListViewItem : TListViewItem; AImageURL : String; begin AImageURL:='http://kayfolom.ru/images/test/'; ListViewUpdate:=True; AListViewItem:=AListView.Items.Add; AListViewItem.Data['ImageURL']:=AImageURL + 'logo.png'; ListViewUpdate:=False; AListViewItem.Adapter.ResetView(AListViewItem); ListViewUpdate:=True; AListViewItem:=AListView.Items.Add; AListViewItem.Data['ImageURL']:=AImageURL + '000487806d3a2ab98aeb2c47b810fc8b.jpg'; ListViewUpdate:=False; AListViewItem.Adapter.ResetView(AListViewItem); ListViewUpdate:=True; AListViewItem:=AListView.Items.Add; AListViewItem.Data['ImageURL']:=AImageURL + '0012ef6cb42e95268a4cd1d832a2b93a.jpg'; ListViewUpdate:=False; AListViewItem.Adapter.ResetView(AListViewItem); ListViewUpdate:=True; AListViewItem:=AListView.Items.Add; AListViewItem.Data['ImageURL']:=AImageURL + '0022454ccb4f81a701cb3a3c89d52d2f.jpg'; ListViewUpdate:=False; AListViewItem.Adapter.ResetView(AListViewItem); end; procedure TFormMain.ListViewUpdatingObjects(const Sender: TObject; const AItem: TListViewItem; var AHandled: Boolean); begin if Not ListViewUpdate then begin MyListViewUpdateObjects(Sender as TListView, AItem); AHandled:=True; end; end; procedure TFormMain.MyListViewUpdateObjects(const AListView: TListView; const AItem: TListViewItem); Var AName : TListItemText; AImage : TListItemImage; AvailableWidth, ImageWidth, ImageHeight : single; function SetupTextObject(const AName, AText : String; AFontSize : Single; AFontStyles : TFontStyles; AWidth, AHeight, X , Y : Single; AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText; begin Result:=TListItemText(AItem.View.FindDrawable(AName)); if Result=Nil then Result:=TListItemText.Create(AItem); Result.Name:=AName; Result.Width:=AWidth; Result.WordWrap:=True; Result.Font.Size:=AFontSize; Result.Font.Style:=Result.Font.Style + AFontStyles; Result.Trimming:=TTextTrimming.None; Result.Text:=AText; Result.PlaceOffset.X:=X; Result.PlaceOffset.Y:=Y; Result.Align:=AAlign; Result.VertAlign:=AVertAlign; Result.TextAlign:=ATextAlign; Result.TextVertAlign:=ATextVertAlign; Result.Height:=AHeight; end; function SetupImageObject(const AName : String; AWidth, AHeight, X , Y : Single; AAlign, AVertAlign: TListItemAlign) : TListItemImage; Var AImageURL : String; begin Result:=TListItemImage(AItem.View.FindDrawable(AName)); if Result=Nil then begin Result:=TListItemImage.Create(AItem); AImageURL:=AItem.Data['ImageURL'].AsString; Result.Bitmap:=LoadImageFromURL(AImageURL); end; Result.Name:=AName; Result.Width:=AWidth; Result.Height:=AHeight; Result.PlaceOffset.X:=X; Result.PlaceOffset.Y:=Y; Result.Align:=AAlign; Result.VertAlign:=AVertAlign; Result.ScalingMode:=TImageScalingMode.StretchWithAspect; end; begin AvailableWidth:=AListView.Width - AListView.ItemSpaces.Left - AListView.ItemSpaces.Right; // Изображение размещаем слева ImageWidth:=AvailableWidth / 3; ImageHeight:=AvailableWidth / 3; AImage:=SetupImageObject('Image', ImageWidth, ImageHeight, 0, 0, TListItemAlign.Leading, TListItemAlign.Leading); // Текст справа AName:=SetupTextObject('Name', AItem.Data['ImageURL'].AsString, 14, [], AvailableWidth - ImageWidth, ImageHeight, ImageWidth, 0, TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Center, TTextAlign.Center); AItem.Height:=Round(ImageHeight + AListView.ItemSpaces.Top + AListView.ItemSpaces.Bottom); end; function TFormMain.LoadImageFromURL(AURL : String) : TBitmap; Var AHTTPClient : THTTPClient; AStream : TMemoryStream; HTTPResponse : IHTTPResponse; begin Result:=Nil; AHTTPClient:=THTTPClient.Create; AStream:=TMemoryStream.Create; try HTTPResponse:=AHTTPClient.Get(AURL, AStream); finally if HTTPResponse.StatusCode=200 then Result:=TBitmap.CreateFromStream(AStream); end; end; end. test092 ListView with Image.7z
  17. Вы уже перешли на FCM, просто не знаете об этом. GCM давно уже нет и пуши работают через FCM.
  18. Покажите скриншот из консоли разработчика, вот как у меня, тогда будет проще понять. И файл манифеста из деплоя. Так же обратите внимание - если у вас, в консоли разработчика, в описании приложения, не загружен скриншот для планшетных ПК, то гугль может все планшеты отнести к не поддерживаемым устройствам.
  19. Огромнейшее спасибо!!! Как раз этим сейчас занимаюсь, как будто мысли мои прочли!
  20. Вроде это возможно при использовании XMPP Protocol, сам не пробовал. Подробнее тут https://firebase.google.com/docs/cloud-messaging/xmpp-server-ref Если получится разобраться, поделитесь решением с сообществом. P.S. Вот есть хорошая штука для этого https://github.com/sourc7/FCMStream
  21. А какая у вас версия Firebird? Тут http://tracker.firebirdsql.org/browse/CORE-982 таже проблема, но пишут что она решена "Fixed in both 2.0.1 and HEAD"
  22. Покажите кусок кода в котором делаете запросы. Ну и перед запросом перепроверяйте соединение с базой "If MyCoolDBProvider.Connected Then MyCoolDBQuery.Execute"...
  23. Спасибо! Не знал как это делается, хотя в других постах видел отсылки. Может создать тему с FAQ по форуму?
  24. Статья странная... Он каким то кодом как то протестировал парсинг. Что именно делалось не понятно. В разных библиотеках парсинг трактуется по разному, это может быть вообще проверка на валидность JSON (подсчет скобочек и двоеточий), а может быть полный разбор содержимого и загрузка в память.
  25. У них для дельфи issue месяцами игнорятся, для билдера наверное вообще никто не смотрит. Но проголосовал.
×
×
  • Создать...