[Android]TIdHTTP and TThread

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Re: [Android]TIdHTTP and TThread

Postby Lena » Fri Jan 06, 2017 1:24 am

You MUST synchronize...
Sync with the main UI thread when loading the Bitmap


Can you show С++ example of the combined use TThread::CreateAnonymousThread and synchronize loading the Bitmap for my case?

TBitmap class is not thread-safe


Some people say that it is better to use TBitmapSurface for loading the bitmap thread-safe:
http://docwiki.embarcadero.com/Librarie ... mapSurface
However, there is no example for C++ Builder.
Lena
BCBJ Master
BCBJ Master
 
Posts: 459
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]TIdHTTP and TThread

Postby rlebeau » Fri Jan 27, 2017 3:56 pm

Lena wrote:
You MUST synchronize...
Can you show С++ example of the combined use TThread::CreateAnonymousThread and synchronize loading the Bitmap for my case?


Something like this:

Code: Select all
//Try in WIN64 for test
/*
my images here:
http://welcome.um.la/myimg/1.png
http://welcome.um.la/myimg/2.png
***
*/
#include <fmx.h>
#pragma hdrstop

#include <memory>
#include "UnitHTTP.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

int ThreadsRunning = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   TListBoxItem *ListBoxItem;
   TListBoxGroupHeader *ListBoxGroupHeader;

   AniIndicator1->Enabled = true;

   ListBox1->BeginUpdate();
   try
   {
      //test for 5 images:
      for (int i = 1; i <= 5; i++)
      {
         ListBoxGroupHeader = new TListBoxGroupHeader(ListBox1);
         ListBoxGroupHeader->Text = L"Custom header";
         ListBox1->AddObject(ListBoxGroupHeader);

         ListBoxItem = new TListBoxItem(ListBox1);
         ListBoxItem->StyleLookup = L"listboxitemleftdetail";
         ListBoxItem->Height = 44; //image heigth
         ListBoxItem->TextSettings->Trimming = TTextTrimming::None;
         ListBoxItem->TextSettings->WordWrap = true;
         ListBoxItem->Text = L"Custom text";
         ListBox1->AddObject(ListBoxItem);
         ListBoxItem->ApplyStyleLookup();

         String URLLink = L"http://welcome.um.la/myimg/" + IntToStr(i) + ".png";
         TThread *thread = TThread::CreateAnonymousThread(
           [URLLink, ListBoxItem, this]()
           {
              std::unique_ptr<TMemoryStream> WelcomeINI(new TMemoryStream);
              std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP);

              try
              {
                 HTTP->Get(URLLink, WelcomeINI.get());
              }
              catch(...)
              {
                 WelcomeINI->LoadFromFile("44x44.png"); //image by default
              }

              WelcomeINI->Position = 0;

               TThread::Synchronize(NULL,
                 [ListBoxItem, WelcomeINI&]()
                 {
                    //ListBoxItem->ItemData->Bitmap->LoadFromStream(WelcomeINI.get());
                    TValue value = ListBoxItem->StylesData["ItemData.Bitmap"];
                    if (!value.IsEmpty)
                    {
                       TBitmap *bitmap = value.AsType<TBitmap*>();
                       bitmap->LoadFromStream(WelcomeINI.get());
                    }
                 }
               );
           }
         );
         thread->OnTerminate = &ThreadTerminated;
         thread->Start();

         ++ThreadsRunning;
      }
   }
    __finally
   {
      ListBox1->EndUpdate();
   }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
    if (--ThreadsRunning <= 0)
      AniIndicator1->Enabled = false;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1403
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]TIdHTTP and TThread

Postby Lena » Sun Jan 29, 2017 3:37 am

TThread::Synchronize([NULL, ListBoxItem, WelcomeINI&]()


[bcc64 Error] UnitHTTP.cpp(63): expected variable name or 'this' in lambda capture list

I try
Code: Select all
TThread::Synchronize([NULL, ListBoxItem, WelcomeINI&, this]()


[bcc64 Error] UnitHTTP.cpp(63): expected variable name or 'this' in lambda capture list

:(
C++ Builder 10.2
Lena
BCBJ Master
BCBJ Master
 
Posts: 459
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]TIdHTTP and TThread

Postby rlebeau » Sun Jan 29, 2017 11:26 am

Lena wrote:
TThread::Synchronize([NULL, ListBoxItem, WelcomeINI&]()


[bcc64 Error] UnitHTTP.cpp(63): expected variable name or 'this' in lambda capture list


Look more closely at what I showed you in my last example. You put the opening '[' in the wrong place. It should be:

Code: Select all
TThread::Synchronize(NULL, [ListBoxItem, WelcomeINI&](){...});


Not:

Code: Select all
TThread::Synchronize([NULL, ListBoxItem, WelcomeINI&](){...});


Don't include NULL in the lambda's capture list. The NULL is the first parameter of Synchronize(), the lambda is the second parameter.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1403
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]TIdHTTP and TThread

Postby Lena » Sun Jan 29, 2017 12:20 pm

Hi.
You put the opening '[' in the wrong place


This was my first attempt but:
Code: Select all
TThread::Synchronize(NULL, [ListBoxItem, WelcomeINI&](){


[bcc64 Error] UnitHTTP.cpp(63): expected ',' or ']' in lambda capture list
Lena
BCBJ Master
BCBJ Master
 
Posts: 459
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]TIdHTTP and TThread

Postby rlebeau » Sun Jan 29, 2017 12:45 pm

Lena wrote:This was my first attempt but:
Code: Select all
TThread::Synchronize(NULL, [ListBoxItem, WelcomeINI&](){


[bcc64 Error] UnitHTTP.cpp(63): expected ',' or ']' in lambda capture list


Sorry, my bad, I had the '&' in the wrong place! In a lambda capture list, when declaring a variable to be captured by reference, the '&' needs to be in front of the variable name instead of behind it:

Code: Select all
TThread::Synchronize(NULL, [ListBoxItem, &WelcomeINI](){...});


See Lambda Expressions.
Last edited by rlebeau on Mon Jan 30, 2017 11:30 am, edited 1 time in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1403
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]TIdHTTP and TThread

Postby Lena » Mon Jan 30, 2017 3:25 am

Thank You very much!
No errors now.

I try in WIN64 and Android but no pictures in ListBox. This code is not executed:
Code: Select all
TBitmap *bitmap = value.AsType<TBitmap*>();
bitmap->LoadFromStream(WelcomeINI.get());

Will wait fix for properties ItemData.Bitmap from Embarcadero.

P.S.
In the future I want to use your code in WIN32. Can you show how it will look your code without lambda?
For WIN32 lambda is not supported. Thank You!
Lena
BCBJ Master
BCBJ Master
 
Posts: 459
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]TIdHTTP and TThread

Postby rlebeau » Mon Jan 30, 2017 11:57 am

Lena wrote:In the future I want to use your code in WIN32. Can you show how it will look your code without lambda?
For WIN32 lambda is not supported.


C++11, and thus lambdas, are supported in the CLang-based Win32 compiler.

For the classic Borland Win32 compiler, you have some alternative choices:

1. use a wrapper class for anonymous procedures (see How to Handle Delphi Anonymous Methods in C++):

Code: Select all
#include <fmx.h>
#pragma hdrstop

#include <memory>
#include "UnitHTTP.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

int ThreadsRunning = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------
class MyThreadFunctor
{
private:
   String URLLink;
   TListBoxItem *ListBoxItem;
   std::unique_ptr<TMemoryStream> WelcomeINI;

   void __fastcall Finished()
   {
      //ListBoxItem->ItemData->Bitmap->LoadFromStream(WelcomeINI.get());
      TValue value = ListBoxItem->StylesData[L"ItemData.Bitmap"];
      if (!value.IsEmpty)
      {
         TBitmap *bitmap = value.AsType<TBitmap*>();
         bitmap->LoadFromStream(WelcomeINI.get());
      }
   }

public:
   MyThreadFunctor(const String &URL, TListBoxItem *Item)
      : URLLink(URL), ListBoxItem(Item), WelcomeINI(new TMemoryStream)
   {
   }

   void operator()()
   {
      std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP);

      try
      {
         HTTP->Get(URLLink, WelcomeINI.get());
      }
      catch(...)
      {
         WelcomeINI->LoadFromFile("44x44.png"); //image by default
      }

      WelcomeINI->Position = 0;

      TThread::Synchronize(NULL, &Finished);
   }
};

typedef TMethodRef<TThreadProcedure, MyThreadFunctor, void> MyThreadMethRef;

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   TListBoxItem *ListBoxItem;
   TListBoxGroupHeader *ListBoxGroupHeader;

   AniIndicator1->Enabled = true;

   ListBox1->BeginUpdate();
   try
   {
      //test for 5 images:
      for (int i = 1; i <= 5; i++)
      {
         ListBoxGroupHeader = new TListBoxGroupHeader(ListBox1);
         ListBoxGroupHeader->Text = L"Custom header";
         ListBox1->AddObject(ListBoxGroupHeader);

         ListBoxItem = new TListBoxItem(ListBox1);
         ListBoxItem->StyleLookup = L"listboxitemleftdetail";
         ListBoxItem->Height = 44; //image heigth
         ListBoxItem->TextSettings->Trimming = TTextTrimming::None;
         ListBoxItem->TextSettings->WordWrap = true;
         ListBoxItem->Text = L"Custom text";
         ListBox1->AddObject(ListBoxItem);
         ListBoxItem->ApplyStyleLookup();

         TThread *thread = TThread::CreateAnonymousThread(
            _di_TThreadProcedure(
               new MyThreadMethRef(
                  L"http://welcome.um.la/myimg/" + IntToStr(i) + ".png", ListBoxItem
               )
            )
         );
         thread->OnTerminate = &ThreadTerminated;
         thread->Start();

         ++ThreadsRunning;
      }
   }
    __finally
   {
      ListBox1->EndUpdate();
   }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
    if (--ThreadsRunning <= 0)
      AniIndicator1->Enabled = false;
}


2. avoid anonymous procedures and just define a custom TThread class instead:

Code: Select all
#include <fmx.h>
#pragma hdrstop

#include <memory>
#include "UnitHTTP.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

int ThreadsRunning = 0;

class TMyThread : public TThread
{
private:
   String URLLink;
   TListBoxItem *ListBoxItem;
   std::auto_ptr<TMemoryStream> WelcomeINI;

   void __fastcall Finished()
   {
      //ListBoxItem->ItemData->Bitmap->LoadFromStream(WelcomeINI.get());
      TValue value = ListBoxItem->StylesData[L"ItemData.Bitmap"];
      if (!value.IsEmpty)
      {
         TBitmap *bitmap = value.AsType<TBitmap*>();
         bitmap->LoadFromStream(WelcomeINI.get());
      }
   }

protected:
   void __fastcall Execute()
   {
      std::auto_ptr<TIdHTTP> HTTP(new TIdHTTP);

      try
      {
         HTTP->Get(URLLink, WelcomeINI.get());
      }
      catch(...)
      {
         WelcomeINI->LoadFromFile("44x44.png"); //image by default
      }

      WelcomeINI->Position = 0;

      Synchronize(&Finished);
   }

public:
   TMyThread(const String &URL, TListBoxItem *Item)
      : URLLink(URL), ListBoxItem(Item), WelcomeINI(new TMemoryStream)
   {
   }
};

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   TListBoxItem *ListBoxItem;
   TListBoxGroupHeader *ListBoxGroupHeader;

   AniIndicator1->Enabled = true;

   ListBox1->BeginUpdate();
   try
   {
      //test for 5 images:
      for (int i = 1; i <= 5; i++)
      {
         ListBoxGroupHeader = new TListBoxGroupHeader(ListBox1);
         ListBoxGroupHeader->Text = L"Custom header";
         ListBox1->AddObject(ListBoxGroupHeader);

         ListBoxItem = new TListBoxItem(ListBox1);
         ListBoxItem->StyleLookup = L"listboxitemleftdetail";
         ListBoxItem->Height = 44; //image heigth
         ListBoxItem->TextSettings->Trimming = TTextTrimming::None;
         ListBoxItem->TextSettings->WordWrap = true;
         ListBoxItem->Text = L"Custom text";
         ListBox1->AddObject(ListBoxItem);
         ListBoxItem->ApplyStyleLookup();

         TThread *thread = new TMyThread(L"http://welcome.um.la/myimg/" + IntToStr(i) + ".png", ListBoxItem);
         thread->OnTerminate = &ThreadTerminated;
         thread->Start();

         ++ThreadsRunning;
      }
   }
    __finally
   {
      ListBox1->EndUpdate();
   }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
    if (--ThreadsRunning <= 0)
      AniIndicator1->Enabled = false;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1403
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]TIdHTTP and TThread

Postby Lena » Tue Jan 31, 2017 10:42 am

Thank You very much for help and support!
Lena
BCBJ Master
BCBJ Master
 
Posts: 459
Joined: Sun Feb 06, 2011 1:28 pm

Previous

Return to Technical

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 4 guests

cron