![](https://fire-monkey.ru/uploads/set_resources_12/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
Евгений Корепов
-
Постов
738 -
Зарегистрирован
-
Посещение
-
Победитель дней
100
Сообщения, опубликованные Евгений Корепов
-
-
Попробуйте избавится от ImageList на время тестов, замените на TArray<TBitmap> к примеру. Так же попробуйте после oConnectImage.ImageIndex:=r; делать oConnectImage.Bitmap.SaveToFile('d:\0\'+Автоинкремент+'.jpg'). У меня в подобной ситуации несколько процентов картинок в папке 'd:\0\' были черными, видимо пустые, отказался по этой причине от связки ImageList и ListView.
-
Вот так сделайте:
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. В соседней теме я долго бился над этим.
-
В 13.04.2017 в 19:06, GASCHE сказал:
Думаю нет, вы не знаете какой поток к ней обратиться в тот или иной момент времени. В Windows у вас отрабатывает сначала основной поток потом ForceQueue в андроид ForceQueue вклинивается в основной поток.
Напишите свой, "правильный" код если хотите доказать что TThread.ForceQueue работает в андроиде и я ошибаюсь. К чему этот бесполезный флуд?
-
1 минуту назад, GASCHE сказал:
А может не работает потому что неправильно написано? На мой взгляд MyLog не потокобезопасная процедура, а вы к ней обращаетесь из разных потоков. Из своего опыта я бы даже для Windows так делать не стал бы, один раз прокатит другой нет.
Все с ней хорошо, ведь там есть
TThread.Synchronize(Nil, procedure begin Memo.Lines.Add(LMessage); end);
К тому же это упрощенный вариант, в рабочем вместо Memo использовалась отсылка данных на сервер логов. Результат тот же.
-
Добавил запрос https://quality.embarcadero.com/browse/RSP-17841 , хотя их никто не читает...
-
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 все работает как ожидается:
Цитата13.04.2017 16.08.17.028 In main thread start
13.04.2017 16.08.17.028 In main thread stop
13.04.2017 16.08.17.028 In ForceQueue start
13.04.2017 16.08.19.029 In ForceQueue stopВ андроиде ситуация следующая:
Цитата13.04.2017 16.06.58.554 In main thread start
13.04.2017 16.06.58.580 In ForceQueue start
13.04.2017 16.07.00.586 In ForceQueue stop
13.04.2017 16.07.00.770 In main thread stopТ.е. нифига не работает.
Тестовый проект прилагаю.
-
Установите свойство ListView.PullToRefresh в True.
-
Создал запрос https://quality.embarcadero.com/browse/RSP-17813 , проголосуйте кому не лень. Спасибо.
-
Обнаружил очередной глюк 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.
-
17 часов назад, Kitty сказал:
Я пытаюсь адаптировать статью этого топика. Т.е в статье присутствует .pas файл с нужным функционалом. Как этот файл будут выглядеть в окончательном виде с THTTPClient?
Вы про 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.
-
В 28.03.2017 в 18:30, Равиль Зарипов (ZuBy) сказал:
в статье описано как нужно настраивать проект
Отличная статья! Но добавлю один нюанс - функция
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); }
-
Не используйте 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), тогда приложение не будет записать при недоступности сервера или проблемах с связью.
-
Кстати, если кто объяснит что делает строчка ListItemImage.OwnsBitmap:=True, буду безмерно благодарен. Не люблю копипастить, без понимания что именно делает код. А лезть в исходники пока некогда.
-
Блин! У меня нет слов! Проблема решилась многочасовым гугленьем. Самое смешное - решение нашел на этом форуме в сообщении 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;
-
Господа и товарищи, помогите тупому мне! Столкнулся с странным. Под 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.
-
23 часа назад, FeLDMARShaL сказал:
надо будет посмотреть, но сначала придется сделать переход на фсм. если получится обязательно отпишусь
Вы уже перешли на FCM, просто не знаете об этом. GCM давно уже нет и пуши работают через FCM.
-
Покажите скриншот из консоли разработчика, вот как у меня, тогда будет проще понять. И файл манифеста из деплоя. Так же обратите внимание - если у вас, в консоли разработчика, в описании приложения, не загружен скриншот для планшетных ПК, то гугль может все планшеты отнести к не поддерживаемым устройствам.
-
Огромнейшее спасибо!!! Как раз этим сейчас занимаюсь, как будто мысли мои прочли!
-
Вроде это возможно при использовании XMPP Protocol, сам не пробовал. Подробнее тут https://firebase.google.com/docs/cloud-messaging/xmpp-server-ref
Если получится разобраться, поделитесь решением с сообществом.
P.S. Вот есть хорошая штука для этого https://github.com/sourc7/FCMStream
ЦитатаFCMStream
FCMStream является сервер приложений для отправки и получения сообщений от Firebase Cloud Messaging (ТСМ) с использованием XMPP протокола.
Применение
FCMStream будет течь сервер Firebase Облака сообщений (ТСМ) через протокол XMPP для входящих сообщений и регистрирует функцию обратного вызова для обработки сообщений и подтверждений, когда сообщения прибывают.
вопросы
Сервер Firebase Cloud Messaging иногда задерживала вопрос о доставки сообщений на сервер приложений или клиентских приложений, так что сообщения будут получены на конечного пользователя после того, как в среднем 2 минуты.
-
1 час назад, Antonyan сказал:
Try
FDConnection1.Params.Database:=Pchar(Extractfilepath(paramstr(0))+'TEST.FDB');
FDConnection1.Connected:=true;
exceptShowmessage('Error');
Exit;
end;
If FDConnection1.Connected then
Temp.Open('Select Field1 from TableName') - вот здесь возникает непостоянная ошибка, о чем и писал выше
else Showmessage('No Connected');
Благодарю всех откликнувшихся
А какая у вас версия Firebird? Тут http://tracker.firebirdsql.org/browse/CORE-982 таже проблема, но пишут что она решена "Fixed in both 2.0.1 and HEAD"
-
-
Спасибо! Не знал как это делается, хотя в других постах видел отсылки. Может создать тему с FAQ по форуму?
-
Статья странная... Он каким то кодом как то протестировал парсинг. Что именно делалось не понятно. В разных библиотеках парсинг трактуется по разному, это может быть вообще проверка на валидность JSON (подсчет скобочек и двоеточий), а может быть полный разбор содержимого и загрузка в память.
-
2 часа назад, Kitty сказал:
Просьба проголосовать, может эмбакадеро предложит фикс: https://quality.embarcadero.com/plugins/servlet/mobile#issue/RSP-17714
Спасибо.
У них для дельфи issue месяцами игнорятся, для билдера наверное вообще никто не смотрит. Но проголосовал.
ListView задать размер скроллбара
в TListView
Опубликовано · Изменено пользователем Евгений Корепов
Вы можете поступить следующим образом - сразу создать нужное количество итемов и задать им высоту (или среднюю высоту) готово итема. Это будет очень быстро, по крайней мере для нескольких тысяч итемов время менее секунды на среднем телефоне. А потом динамически наполнять их данными.
P.S Не забудьте отключить события ListViewUpdatingObjects и ListViewUpdateObjects на время создания итемов.