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

Поток в Firemonkey Android


lala4a

Вопрос

Доброе время суток .

Я только начал знакомится с потоками , не судите строго .

Вот код . Смысл которого через отдельный поток загружать изображение с сервера .

unit Unit5;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,iduri,idhttp,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
  FMX.Controls.Presentation, FMX.StdCtrls;
    type
 ThreadHTTP=class(TThread)
 private
  Stream:TMemoryStream;
  bmp:tbitmap;
  url:string;
 public
    constructor Create(abmp:tbitmap; aurl: String);
  procedure Execute;override;
 // procedure ShowResult;
end;
type
  TForm5 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure getpic(pic: string; img: Tbitmap);
  end;

var
  Form5: TForm5;

implementation

{$R *.fmx}
constructor ThreadHTTP.Create(abmp:tbitmap;aurl:string);
begin
 inherited Create(false);
  bmp := abmp;
  url:=aurl;
end;

procedure ThreadHTTP.Execute;
var
 j:integer;
   idhttp : TIdHTTP;
   ms:tmemorystream;
   png:tbitmap;
begin
  ms := TMemoryStream.Create;
  IdHTTP := TIdHTTP.Create(nil);
  url:=TIdURI.URLEncode(url);

    try
idhttp.Get(url,ms);
    ms.Position := 0;
  finally
  bmp.LoadFromStream(ms);

    idhttp.Free;
    ms.Free;

  end;
end;


procedure TForm5.Button1Click(Sender: TObject);
begin
getpic('krovat1',form5.Image1.Bitmap);
end;

procedure TForm5.getpic(pic: string; img: Tbitmap);
var
zapros:string;
idhttp:tidhttp;
MyHTTP:ThreadHTTP;
begin
zapros:='http://127.0.0.1/getimage_'+pic;
MyHTTP:=ThreadHTTP.Create(img,zapros);
MyHTTP.FreeOnTerminate := true;
MyHTTP.resume;
end;

end.

Код корявый , но работает в win32 .  В Android ничего не происходит .

Помогите разобраться , пожалуйста .

 

Изменено пользователем lala4a
Ссылка на комментарий

Рекомендуемые сообщения

  • 0
  • Администраторы

После окончания метода 

getpic

ARC удаляет ваш поток, так как ссылок на него нету. Нужно вынести переменную потока в поле класса, чтобы гарантировать наличие одной ссылки на ваш поток.

Ссылка на комментарий
  • 0
2 часа назад, lala4a сказал:

Код корявый , но работает в win32

И работать будет коряво :( TImage не поток безопасный компонент поэтому присваивать ему значение в потоке без синхронизации нельзя.

Ссылка на комментарий
  • 0
1 час назад, Brovin Yaroslav сказал:

После окончания метода 


getpic

ARC удаляет ваш поток, так как ссылок на него нету. Нужно вынести переменную потока в поле класса, чтобы гарантировать наличие одной ссылки на ваш поток.

Подскажите пожалуйста примером .

43 минуты назад, GASCHE сказал:

И работать будет коряво :( TImage не поток безопасный компонент поэтому присваивать ему значение в потоке без синхронизации нельзя.

А если Tbitmap ?

Я читал про потоки , но так и не понял как синхронизировать графический компонент .   Попробую описать , для чего конкретно мне надо , может направите в другое русло .

С сервера получаем список вещей . К каждой вещи есть картинка .  Для отображения списка используется компонент

Цитата

tkstableview

 В процессе заполнения списка загружаются картинки .

Цитата

AItem: tkstableviewitem;

pic:string;

getpic(pic,AItem.Image.bitmap);

В главном потоке это очень долго и подвисает основная форма . 

Цитата

application.HandleMessage;

Не спасает .

Поэтому хочу сначала получить список , а потом плавненько загрузить изображения .

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

Вот накатал пример с использованием Timage , так сказать для пробы и дальнейшего переноса в основную программу , но с потоками дел до этого не имел . В интернете уйма примеров по скачке и сохранению файлов , по расчетам  и прочему . По своей задаче не нашел .  Надеюсь вы мне поможите )

 

Ссылка на комментарий
  • 0
procedure ThreadHTTP.Execute;
var
 j:integer;
   idhttp : TIdHTTP;
   ms:tmemorystream;
   png:tbitmap;
begin
  ms := TMemoryStream.Create;
  IdHTTP := TIdHTTP.Create(nil);
  url:=TIdURI.URLEncode(url);

    try
idhttp.Get(url,ms);
    ms.Position := 0;
  finally
 TThread.Synchronize(nil, procedure
           begin
              bmp.LoadFromStream(ms);
           end);

    idhttp.Free;
    ms.Free;

  end;
end;

Хм . Вот так работает на Android  .

Ссылка на комментарий
  • 0
  • Модераторы
procedure LoadResizeBitmapFromURL(const AURL: string; aBitmap: TBitmap; const aWidth, aHeight: integer);
// uses System.Net.HTTPClient, System.Net.HTTPClientComponent
var
  thread: TThread;
begin
  thread := TThread.CreateAnonymousThread(
    procedure
    var
      Http: THTTPClient;
      Result: TMemoryStream;
    begin
      Result := TMemoryStream.Create;
      Http := THTTPClient.Create;
      try
        try
          Http.Get(AURL, Result);
          TThread.Synchronize(TThread.CurrentThread,
            procedure
            var
              aSourceBmp, aResizeBmp: TBitmap;
              aSrcRect, aDestRect: TRectF;
            begin
              aSourceBmp := TBitmap.Create;
              aSourceBmp.LoadFromStream(Result);
              if not aSourceBmp.IsEmpty then
              begin
                aResizeBmp := TBitmap.Create(aWidth, aHeight - 2);
                aResizeBmp.Canvas.BeginScene;
                
		if aSourceBmp.Width > aWidth then
                  aSourceBmp.Resize(aWidth, round(aSourceBmp.Height * aWidth / aSourceBmp.Width));
                aSrcRect := RectF(0, round((aSourceBmp.Height - aHeight - 2) / 2), aWidth,
                  round((aSourceBmp.Height - aHeight - 2) / 2)  aHeight - 2);
                aDestRect := RectF(0, 0, aWidth, aHeight - 2);
                
                aResizeBmp.Clear(0);
                aResizeBmp.Canvas.DrawBitmap(aSourceBmp, aSrcRect, aDestRect, 1, false);
                aResizeBmp.Canvas.EndScene;

                aBitmap.Clear(0);
                aBitmap.SetSize(aWidth, aHeight - 2);
                aBitmap.CopyFromBitmap(aResizeBmp);

                FreeAndNil(aResizeBmp)
              end;
              FreeAndNil(aSourceBmp);
            end);
        except
          FreeAndNil(Result);
        end;
      finally
        FreeAndNil(Result);
        FreeAndNil(Http);
      end;
    end);
  thread.FreeOnTerminate := true;
  thread.start;
end;

я использую вот такой код, сразу с ресайзом под нужный размер

использовать так, НЕ В ПОТОКЕ

LoadResizeBitmapFromURL('image-url', Image1.Bitmap, 120, 120);

 

Ссылка на комментарий
  • 0
2 часа назад, ZuBy сказал:

я использую вот такой код, сразу с ресайзом под нужный размер

До сих пор думал, что метод Synchronize выполняется в главном потоке приложения, если это так, то почему ресайз не сделать в потоке? 

 

Ссылка на комментарий
  • 0
  • Модераторы
11 минут назад, GASCHE сказал:

До сих пор думал, что метод Synchronize выполняется в главном потоке приложения, если это так, то почему ресайз не сделать в потоке? 

Потому что TBitmap не потокобезопасный! и все операции с ним должны быть в главном потоке

Ссылка на комментарий
  • 0
22 минуты назад, ZuBy сказал:

Потому что TBitmap не потокобезопасный

Я понимаю с aBitmap, но aSourceBmp, aResizeBmp можно сделать локальными переменными потока. Зачем их синхронизировать?

Ссылка на комментарий
  • 0
  • Модераторы
1 минуту назад, GASCHE сказал:

Я понимаю с aBitmap, но aSourceBmp, aResizeBmp можно сделать локальными переменными потока. Зачем их синхронизировать?

эм, для чего? если весь код выполняется в синхронизации? в потоке нельзя работать с TBitmap

Ссылка на комментарий
  • 1
  • Модераторы

тут такое дело... нельзя работать с TBitmap в доп. потоке - так проще и безболезненно.

на самом деле можно, но есть ряд правил.

1) Писать нужно аккуратно, использовать правильно Bitmap.Canvas.Lock/Unlock

2) Читать можно с любых потоков, но не запись

3) Если получить TBitmapData, то можно работать с памятью в доп. потоке

4) может что-то еще...

НО ещё раз, работать нужно с TBitmap в синхронизации (в главном потоке)

 

 

Ссылка на комментарий
  • 0

Спасибо! Еще спрошу

3 часа назад, ZuBy сказал:

использовать так, НЕ В ПОТОКЕ


LoadResizeBitmapFromURL('image-url', Image1.Bitmap, 120, 120);

если нужно загрузить не одну, а несколько картинок то как узнать, что первая загрузилась, или можно подряд вызывать LoadResizeBitmapFromURL меняя соответственно url и image?

Ссылка на комментарий
  • 0
  • Модераторы
2 минуты назад, GASCHE сказал:

если нужно загрузить не одну, а несколько картинок то как узнать, что первая загрузилась, или можно подряд вызывать LoadResizeBitmapFromURL меняя соответственно url и image?

да хоть циколом, там внутри для каждого битмапа свой поток. отработает вернёт и умрёт.

но не злоупотреблять, память не резиновая

Ссылка на комментарий
  • 0
9 часов назад, ZuBy сказал:

использовать так, НЕ В ПОТОКЕ


LoadResizeBitmapFromURL('image-url', Image1.Bitmap, 120, 120);

 

Вылетает приложение с ошибкой

Цитата

segmentation fault 11

Первый раз такую ошибку вижу

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...