Android Tutorial ImageDownloader - The simple way to download images

Status
Not open for further replies.
Don't use this. SimpleMediaManager is 100 times more powerful: [B4X] SimpleMediaManager (SMM) - framework for images, videos and more

Downloading images with HttpUtils2 is quite simple.

However correctly managing multiple downloads without downloading the same image multiple times, for example when the user changes the screen orientation, is more complicated.

ImageDownloader makes it very simple to efficiently download images and show them in ImageViews.

Example code:
B4X:
Sub Globals
   Dim ImageView3 As ImageView
   Dim ImageView2 As ImageView
   Dim ImageView1 As ImageView
   Dim ImageView4 As ImageView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
End Sub

Sub Activity_Resume
   Dim links As Map
   links.Initialize
   links.Put(ImageView1, "http://www.b4x.com/basic4android/images/SS-2012-08-29_12.55.42.png")
   links.Put(ImageView2, "http://www.b4x.com/basic4android/images/SS-2013-03-04_11.42.38.png")
   links.Put(ImageView3, "http://www.b4x.com/basic4android/images/SS-2013-03-04_11.52.19.png")
   links.Put(ImageView4, "http://www.b4x.com/basic4android/images/SS-2012-02-06_12.45.56.png")
   CallSubDelayed2(ImageDownloader, "Download", links)
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   CallSub(ImageDownloader, "ActivityIsPaused")
End Sub

How to use?

1. In Activity_Resume you should create a Map with the ImageViews as keys and the links as values. Use CallSubDelayed to call ImageDownloader.Download.
2. In Activity_Pause you should use CallSub to call ImageDownloader.ActivityIsPaused.
3. That's it.

SS-2013-07-09_16.03.45.png
 

Attachments

  • ImageDownloader.zip
    8.1 KB · Views: 7,356
Last edited:

Ratna Fang

Member
Licensed User
Longtime User
Here's some edits i've done to update it to do auto fit and center.
First it makes it fit the target view's dimensions keeping aspect ratio, then caches the resulting image so cache hits are only memory, not cpu.

B4X:
Sub JobDone(Job As HttpJob)
    ongoingTasks.Remove(Job.JobName)
    If Job.Success Then
        Dim bmp As Bitmap = Job.GetBitmap
            
    
        If tasks.IsInitialized Then
            For i = 0 To tasks.Size - 1
            
                Dim link As String = tasks.GetValueAt(i)
                If link = Job.JobName Then
            
                    Dim iv As ImageView = tasks.GetKeyAt(i)
                
                    Dim b2 As Bitmap
                    b2.InitializeMutable(iv.Width,iv.Height)
    
                    Dim c As Canvas
                    c.Initialize2(b2)
                
                    Dim r1 As Rect
                    r1.Initialize(0,0,bmp.Width,bmp.Height)
                                
                    Dim xdif As Float = iv.Width / bmp.Width
                    Dim ydif As Float = iv.Height / bmp.Height

                    Dim NewX As Float = bmp.Width * xdif
                    Dim NewY As Float = bmp.Height * ydif
                
                    Dim NewZ As Float = (iv.Width + iv.Height) / (bmp.Width + bmp.Height)
                
                    Dim r2X As Float
                    Dim r2Y As Float
                    
                    If NewX > NewY Then
                        'Log("X")
                        r2X = bmp.Width * ydif
                        r2Y = NewY
                    Else
                        'Log("Y")
                          r2X = NewX
                        r2Y = bmp.Height * xdif
                    End If
                
                    If r2X > iv.Width Then
                        Dim NewRatio As Float = (iv.Width / r2X)
                        r2X = r2X * NewRatio
                        r2Y = r2Y * NewRatio
                    End If

                    Dim NewLeft As Float = ((iv.Width - b2.Width) / 2)
                    Dim NewTop As Float = ((iv.Height - b2.Height) / 2)
                
                    Dim r2 As Rect
                    r2.Initialize(NewLeft,NewTop,r2X,r2Y)
                                    
                    c.DrawColor(Colors.White)
                    c.DrawBitmap(bmp,r1,r2)
                    c = Null
                    cache.Put(Job.JobName, b2)
                    iv.SetBackgroundImage(b2)
                End If
        
            Next
        End If
    Else
        cache.Put(Job.JobName, NotFoundBmp)
    
        If tasks.IsInitialized Then
            For i = 0 To tasks.Size - 1
            
                Dim link As String = tasks.GetValueAt(i)
                If link = Job.JobName Then
                    Dim iv As ImageView = tasks.GetKeyAt(i)
                    iv.SetBackgroundImage(NotFoundBmp)
                End If
            Next
        End If
    
        'Log("Error downloading image: " & Job.JobName & CRLF & Job.ErrorMessage)
    End If
    Job.Release
End Sub

This is a bit crude for cache management, but stops crashes and errors from spaces in URLs.
B4X:
Sub Download (ImageViewsMap As Map)

    For i = 0 To ImageViewsMap.Size - 1
        tasks.Put(ImageViewsMap.GetKeyAt(i), ImageViewsMap.GetValueAt(i))
        Dim link As String = ImageViewsMap.GetValueAt(i)
        link = link.Replace(" ","%20")
        If cache.ContainsKey(link) Then
            Dim iv As ImageView = ImageViewsMap.GetKeyAt(i)
            iv.SetBackgroundImage(cache.Get(link))
         
        Else If ongoingTasks.ContainsKey(link) = False Then
            Log("Cache Size: " & cache.Size)
            If cache.Size > MAX_CACHE_SIZE Then
                cache.Clear
            End If
            ongoingTasks.Put(link, "")
            Dim j As HttpJob
            j.Initialize(link, Me)
            j.Download(link)
        End If 
    Next
 
End Sub

i'm sorry perhaps i missed something
for variable MAX_CACHE_SIZE, is there any part to declare the variable?
dim MAX_CACHE_SIZE as int or dim MAX_CACHE_SIZE as long?

or MAX_CACHE_SIZE is a system variable which is determined by each handheld?
 

Blue.Sky

Active Member
Licensed User
Longtime User
Hi
I have a 200 picture that load with imagedownloader
But when i start it,my app show isn't responding
what is problem?
 

Douglas Farias

Expert
Licensed User
Longtime User
200 Imagens is too much for one app.
what the sizes of the imagens?
 

DonManfred

Expert
Licensed User
Longtime User
No one see 200 images at once on the screen. You should consider a pagination if there are much images. Show 10 Images and but a button for ex. which then loads 10 more images. Or something similar.

Additional the FILESIZES does not matter. The Image-DIMENSIONS (Width * Height) DOES

What dimensions does the images have (witdh/height)?
 

Blue.Sky

Active Member
Licensed User
Longtime User
No one see 200 images at once on the screen. You should consider a pagination if there are much images. Show 10 Images and but a button for ex. which then loads 10 more images. Or something similar.

Additional the FILESIZES does not matter. The Image-DIMENSIONS (Width * Height) DOES

What dimensions does the images have (witdh/height)?
Different size.Please visit AppYet website,This website download rss and image synchronize and not problem(no pagination)
 

Mashiane

Expert
Licensed User
Longtime User
SS-2013-07-09_16.34.28.png


In this example the list of images is first extracted from an online page and then all the images are downloaded. This example is based on: Download list of images with HttpUtils2 and CustomListView

However as the code is based on the ImageDownloaded service it is much simpler.
Is it possible to have the ImageDownloader to reflect the percentage progress of the downloaded image or current file size / total file size variable? I want to show a placeholder image in place showing loading progress until the image is fully loaded. Anyone?
 

Declan

Well-Known Member
Licensed User
Longtime User
How can I adapt the code in ImageDownloader2 to load an image and text from a remote MySQL database?
I am successfully downloading and displaying the image (BLOB) in an ImageView and the text in a Label with this code in my JobDone sub:
B4X:
       If result.Tag = "select_img" Then
                    For Each records() As Object In result.Rows
                        Dim Buffer() As Byte
                        Dim HeaderTxt As String
                        Buffer = records(result.Columns.Get("img02"))
                        HeaderTxt = records(result.Columns.Get("TxtHeader"))
                        Dim InputStream1 As InputStream
                        InputStream1.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
                        Dim Bitmap1 As Bitmap
                        Bitmap1.Initialize2(InputStream1)
                        InputStream1.Close
                        ImageView1.SetBackgroundImage(Bitmap1)
                        Label1.Text = HeaderTxt
                    Next
                End If

I need to incorporate the above code into the following original code of the ImageDownloader2 JobDone sub:
B4X:
    If Job.Success = True Then
        If Job.JobName = "PageJob" Then
            Dim m As Matcher = Regex.Matcher("class=\""darkbox\""><img src=\""([^""]+)""", Job.GetString)
            Do While m.Find
                links.Add(m.Group(1))
            Loop
            BuildItems
        End If
    Else
        Log(Job.ErrorMessage)
    End If
 

Jorgelcr

Active Member
Licensed User
Longtime User
Hello,

I had already seen this code, my problem is that I try to download the image inside another loop that is shown the registers. I explain:

I have a table-> Companies with three fields (Name, Location, Logo) In the field I soon save the ftp path of the file I uploaded.

I create a loop to browse the companies and show in a listview their Name and Location. I look if the field logo is empty and in case it is not empty I want to download the image and display it. So easy and so complicated.


B4X:
Sub Activity_Create(FirstTime As Boolean)
 
    Activity.LoadLayout("logos")

 
    ExecuteRemoteQuery("Select * From Empresas " , "EMPRESAS")
 
  
End Sub
Sub ExecuteRemoteQuery(Query As String, JobName As String)
    job1.Initialize("Job1", Me)
    job1.PostString("http://www.miweb.com/empresas.php", Query)
    
End Sub
Sub JobDone(job As HttpJob)

Select job.JobName
        Case "Job1"
            If job.Success Then
                Dim res As String
                res = job.GetString
                Log("Response from server: " & res)
                Dim parser As JSONParser
                parser.Initialize(res)
                COUNTRIES = parser.NextArray 'returns a list with maps
                For i = 0 To COUNTRIES.Size - 1 'bucle para recorrer los registros de la tabla
                    m = COUNTRIES.Get(i)
                    If m.Get("logo")=Null Then 'comprobar si tiene logo
                        ListView1.AddTwoLines(m.Get("Nombre"),m.Get("Localidad"))
                    Else
                       'Descargar logo
                        imageurl2 = "http://www.miweb.com/logo/" & m.Get("logo")
                        json.Initialize(job.GetString)
                        job2.Initialize("Image",Me)
                        job2.Download(imageurl2)
                 
                
                    End If
                Next
            End If
        Case "Image"
           'Mostrar logo en Listview ListView1.AddTwoLinesAndBitmap(m.Get("Nombre"),m.Get("Localidad"),job2.GetBitmap)
End Select
End Sub
 

DonManfred

Expert
Licensed User
Longtime User
I had already seen this code, my problem is that I try to download the image inside another loop that is shown the registers. I explain:
Please start a new thread in the questions forum for this.
Your concept does have multiple problems. One of it is that you are using a Listview where you should use a CustomListView (using Imageviews for the logos)

Create a new thread, create a small project (including your DB) showing your problem and upload it.
 

desof

Well-Known Member
Licensed User
Longtime User
Why change the URL by a URL of my domain where there are also jpg images and do not read them?


B4X:
''Private MainUrl As String = "http://www.flickr.com/explore/interesting/7days/"

Private MainUrl As String = "http://www.fmyURL.com/explore/interesting/7days/"
 

WebQuest

Active Member
Licensed User
Hello as I can give the link to download the image through an edittext I'm using this code but it gives me an error in loading the bitmap.

B4X:
Sub BTDownload_Click
    Dim links As Map

    links.Initialize
   
    If EditTextLink.Text<>"" Then
       
        links.Put(ImageViewResult,""&EditTextLink.Text&"")
        CallSubDelayed2 (ImageDownloader, "Download", collegamenti)
       
    Finisci se
   
End Sub [/ CODE]
 

DonManfred

Expert
Licensed User
Longtime User
Status
Not open for further replies.
Top