Spanish [SOLUCIONADO]B4A-Cargar imagen desde url

ferpahud

Active Member
Licensed User
Hola, buenos idas.

Estoy intentando cargar una imagen desde una url, pero no puedo lograrlo. Lo que hago en mi aplicación para que se entienda, es primero descargar una base de datos online, que contiene distintos atributos, entre ellos el nombre de la imagen.

Luego recorro esa base de datos y según la cantidad de registros que tenga voy creando de forma dinámica botones, y voy tomando de la BD la imagen del botón, el texto, etc.

El metodo que dibuja el boton es el siguiente:
B4X:
Sub DibujaBoton (boton As Button, Numero As Int, id As Int, texto As String, imagen As String)
    Dim x, y As Int
    boton.Initialize("btnV")
    boton.Tag = Numero 'se almacena el número de orden de cada botón

    Dim DestRect As Rect
    Dim icono As Bitmap ' mediante canvas inserto la imagen para despues redondear
    Dim iconoCanvas As Canvas

    x = separacion + (ancho_boton + separacion) * (Numero Mod columnas) 'calcula la coordenada X del botón
    y = separacion + (alto_boton + separacion) * Floor(Numero/columnas) 'calcula la coordenada Y del botón

    SV.Panel.AddView(boton, x, y, ancho_boton, alto_boton) 'añade el botón al SV

    icono.InitializeMutable(ancho_boton, alto_boton) ' inicializo el icono como bitmat modificable por el canvas
    DestRect.Initialize(0dip, 0dip, ancho_boton, alto_boton - 50dip)
    iconoCanvas.Initialize2(icono)

    'Dibuja la imagen de fondo del botón, previamente redondeada (IE.Roundcorner)
    iconoCanvas.DrawBitmap(IE.RoundCorner(LoadBitmapSample(File.DirAssets, imagen,ancho_boton, alto_boton),28), Null, DestRect)
   
    boton.SetBackgroundImage(icono) 'coloca en el fondo del botón
   
    boton.Gravity=Bit.Or(Gravity.BOTTOM, Gravity.CENTER_HORIZONTAL)
    boton.Text = texto
    boton.TextSize = 15
    boton.TextColor=Color_Boton
End Sub

Lo que sucede es que con este método solo puedo utilizar las imágenes que tengo guardadas en la aplicación, cuando yo en realidad quiero tomarla desde una url

Saludos
 

ferpahud

Active Member
Licensed User

dar2o3

Active Member
Licensed User
Longtime User
Lo que sucede es que con este método solo puedo utilizar las imágenes que tengo guardadas en la aplicación, cuando yo en realidad quiero tomarla desde una url

Saludos

El link que te he puesto hace exactamente lo que tu quieres, descargar imágenes desde una url, una vez descargadas ya puedes usarlas, igual no entiendo bien cual es tu duda.
 

Seneca

Active Member
Licensed User
Lo que sucede es que con este método solo puedo utilizar las imágenes que tengo guardadas en la aplicación, cuando yo en realidad quiero tomarla desde una url

LoadBitmapSample solo trabaja con imagenes locales? o puedo colocar la url?

Hola.

Cuando publiqué el código del mensaje #1 lo simplifiqué adjuntando las imágenes de los botones a la propia App. En realidad las imágenes no las guardo en la App, sino que las descargo desde un servidor al dispositivo. No te recomiendo cargar la imagen directamente desde una URL en el momento de dibujar el botón por varios motivos:
  • Puede que en ese instante no tengas conexión
  • Puede que la tengas pero sea muy lenta
  • Cada vez que tengas que mostrar un determinado menú descargarías las mismas imágenes de la URL una y otra vez
Lo que yo hago es que justo al inicial la App, mientras se muestra una pantalla splash, consulto la BD de menús para saber qué imágenes voy a necesitar a la hora de mostrar cualquiera de ellos y las guardo en una lista.

Luego recorro esa lista de imágenes y compruebo si cada una de las imágenes la tengo descargada en el dispositivo, y me preparo una segunda lista con aquellas que me falten (lógicamente, la primera vez que ejecute la App me faltarán todas). Una vez conozco qué imágenes me faltan lanzo un servicio que se encarga de descargar (o intentarlo) las imágenes desde mi servidor al dispositivo. El hacerlo mediante servicio es porque dependiendo del número de imágenes y del estado de conexión de la red se puede ir más o menos tiempo en descargarlas, y las ejecución de la app no puede esperar a que esto termine. Una vez el servicio intenta descargar todas las imágenes, lo finalizo.

Una vez pasado el tiempo del splah llega el momento de mostrar el primer menú. Lo que hago ahora es llamar Sub DibujaBoton, para dibujar cada botón. Pero justo antes compruebo si la imagen la tengo en el dispositivo (gracias a que el servicio ha podido descargarla del servidor). En caso contrario lo que hago es indicar Sub DibujaBoton que el botón ha de mostrar una imágen genérica (que sí tengo insertada en la App).

De esta manera me aseguro poder mostrar el menú incluso en los casos que un fallo de conexión no me deje descargar alguna o todas las imágenes de los botones. Aunque no quede muy elegante, al menos no paralizo la App.

La próxima vez que se ejecute la App, se intentarán descargar las imágenes de los botones que la vez anterior quedaron pendientes. Aunque otra solución mejor es que el propio servicio que se encarga de la descarga, lo siga intentando a intervalos regulares durante la App está ejecutándose, de manera que no haya que esperar a cerrar y volver a abrir la App para tenerlas todas en el dispositivo.

Para la descarga de las imágenes desde el servicio uso:

B4X:
job.Download("http://www.miservidor.com/img/" & archivo)

y su correspondiente:

B4X:
Sub JobDone(Job As HttpJob)
    If Job.Success Then
        Dim out As OutputStream
        out = File.OpenOutput(File.DirDefaultExternal,Job.JobName,False )
        File.Copy2(Job.GetInputStream, out)
        out.Close
        .....
        .....


Espero que te sirva la idea. Si es así, habrás de implementarla según tus necesidades.

Saludos.
 

ferpahud

Active Member
Licensed User
Hola.

Cuando publiqué el código del mensaje #1 lo simplifiqué adjuntando las imágenes de los botones a la propia App. En realidad las imágenes no las guardo en la App, sino que las descargo desde un servidor al dispositivo. No te recomiendo cargar la imagen directamente desde una URL en el momento de dibujar el botón por varios motivos:
  • Puede que en ese instante no tengas conexión
  • Puede que la tengas pero sea muy lenta
  • Cada vez que tengas que mostrar un determinado menú descargarías las mismas imágenes de la URL una y otra vez
Lo que yo hago es que justo al inicial la App, mientras se muestra una pantalla splash, consulto la BD de menús para saber qué imágenes voy a necesitar a la hora de mostrar cualquiera de ellos y las guardo en una lista.

Luego recorro esa lista de imágenes y compruebo si cada una de las imágenes la tengo descargada en el dispositivo, y me preparo una segunda lista con aquellas que me falten (lógicamente, la primera vez que ejecute la App me faltarán todas). Una vez conozco qué imágenes me faltan lanzo un servicio que se encarga de descargar (o intentarlo) las imágenes desde mi servidor al dispositivo. El hacerlo mediante servicio es porque dependiendo del número de imágenes y del estado de conexión de la red se puede ir más o menos tiempo en descargarlas, y las ejecución de la app no puede esperar a que esto termine. Una vez el servicio intenta descargar todas las imágenes, lo finalizo.

Una vez pasado el tiempo del splah llega el momento de mostrar el primer menú. Lo que hago ahora es llamar Sub DibujaBoton, para dibujar cada botón. Pero justo antes compruebo si la imagen la tengo en el dispositivo (gracias a que el servicio ha podido descargarla del servidor). En caso contrario lo que hago es indicar Sub DibujaBoton que el botón ha de mostrar una imágen genérica (que sí tengo insertada en la App).

De esta manera me aseguro poder mostrar el menú incluso en los casos que un fallo de conexión no me deje descargar alguna o todas las imágenes de los botones. Aunque no quede muy elegante, al menos no paralizo la App.

La próxima vez que se ejecute la App, se intentarán descargar las imágenes de los botones que la vez anterior quedaron pendientes. Aunque otra solución mejor es que el propio servicio que se encarga de la descarga, lo siga intentando a intervalos regulares durante la App está ejecutándose, de manera que no haya que esperar a cerrar y volver a abrir la App para tenerlas todas en el dispositivo.

Para la descarga de las imágenes desde el servicio uso:

B4X:
job.Download("http://www.miservidor.com/img/" & archivo)

y su correspondiente:

B4X:
Sub JobDone(Job As HttpJob)
    If Job.Success Then
        Dim out As OutputStream
        out = File.OpenOutput(File.DirDefaultExternal,Job.JobName,False )
        File.Copy2(Job.GetInputStream, out)
        out.Close
        .....
        .....


Espero que te sirva la idea. Si es así, habrás de implementarla según tus necesidades.

Saludos.
Muchas gracias por la respuesta, si efectivamente el codigo fue creado por ti.
Lo que no se es como recorrer las imagenes que tengo dentro de mi aplicacion, ¿como puedo hacer eso?
 

Seneca

Active Member
Licensed User
Muchas gracias por la respuesta, si efectivamente el codigo fue creado por ti.

Pude desarrollarlo gracias a las ideas y ayudas que me brindaron otros compañeros de foro, por eso no me importó compartirlo.

Lo que no se es como recorrer las imagenes que tengo dentro de mi aplicacion, ¿como puedo hacer eso?

¿Puedes detallar un poco más tu duda? No sé con exactitud a qué te refieres.
B4X:
Dim lstImagenesIconos as List 'Todas las imágenes
Dim lstImagenesPendientes as List 'Imágenes que faltan por descargar al dispositivo
.....

'Con lo siguiente consultas la BD y guardas en la lista lstImagenesIconos el nombre de todas las imagenes de los botones de los menus
lstImagenesIconos = DBUtils.ExecuteMemoryTable(Starter.sql, "SELECT imagen FROM menus", Null,0)
'Cada elemento de la lista es una matriz. Cada matriz contiene un único elemento, que es el nombre de una imagen de icono

....

Dim UnaImagen () As String
'Con el siguiente For-next recorres la lista de imágenes y compruebas cuáles de ellas las tienes ya descargadas y creas una nueva lista con las que te falten
For Numero = 0 To lstImagenesIconos.size - 1
     UnaImagen = lista.Get(Numero) 'Recupera de la Lista de imágenes el nombre de cada una
     'Comprueba si existe la imagen del botón y en caso contrario manda la guarda en la lista de imágenes faltantes

    'Comprueba si el archivo existe
     If Not( File.Exists(File.DirDefaultExternal,UnaImagen(0))) Then
         Log(UnaImagen(0) & " - No existe")
         lstImagenesPendientes.Put(UnaImagen(0))
     End If
Next

El siguiente paso sería recorrer la lista lstImagenesPendientes y descargar cada una de ellas con:

B4X:
job.Download("http://www.miservidor.com/img/" & archivo)

No sé si va por aquí tu duda.

Saludos.
 
Last edited:

ferpahud

Active Member
Licensed User
@Seneca A lo que me referia era como saber que imagenes tengo ya guardadas, viendo el codigo entiendo que se realiza con la siguiente linea:
B4X:
File.Exists(File.DirDefaultExternal,UnaImagen(0)

y dentro del for, donde dice "lista.Get(Numero)", deberia ser "lstImagenesIconos.Get(Numero)" , según entiendo

Lo que me marca error es en la linea de:
B4X:
lstImagenesPendientes.Put(UnaImagen(0))
marca como "desconocido el miembro put"

Sera que me falta alguna libreria? Gracias
 

Seneca

Active Member
Licensed User
y dentro del for, donde dice "lista.Get(Numero)", deberia ser "lstImagenesIconos.Get(Numero)" , según entiendo

Cierto. Escribí el código de memoria, sin probarlo, y no me di cuenta de ese error.

Lo que me marca error es en la linea de:
B4X:
lstImagenesPendientes.Put(UnaImagen(0))
marca como "desconocido el miembro put"

Sera que me falta alguna libreria? Gracias

No es necesaria ninguna libreria. ¿Has dimensionado lstImagenesPendientes como List?

B4X:
Dim lstImagenesPendientes as List

Saludos.
 

ferpahud

Active Member
Licensed User
Cierto. Escribí el código de memoria, sin probarlo, y no me di cuenta de ese error.



No es necesaria ninguna libreria. ¿Has dimensionado lstImagenesPendientes como List?

B4X:
Dim lstImagenesPendientes as List

Saludos.
Si, la eh dimensionado. Ni siquiera aparece un metodo que comience con "p" que se le pueda asignar a un objeto lista
646f7fb5e190428488b77e4868aa30ae.png
 

Seneca

Active Member
Licensed User
Si, la eh dimensionado. Ni siquiera aparece un metodo que comience con "p" que se le pueda asignar a un objeto lista

Hola.

Volví a caer en el error por no probar el código. El método .put es para los mapas. Lo correcto en las listas es:

B4X:
lstImagenesPendientes.Add(UnaImagen(0))

Saludos.
 

ferpahud

Active Member
Licensed User
Hola.

Volví a caer en el error por no probar el código. El método .put es para los mapas. Lo correcto en las listas es:

B4X:
lstImagenesPendientes.Add(UnaImagen(0))

Saludos.
Bien, ahora si. Una consulta, pera recorrer la lista con las imágenes pendientes y descargarlas, intengo hacerlo de la siguiente manera pero no funciona:
B4X:
For Each imagenItem In lstImagenesPendientes
        hilo.Download("http://www.miservidor.com/img/" & imagenItem)
    Next imagenItem

Tambien tengo otro problema, en la siguiente linea:
B4X:
For Numero = 0 To lstImagenesIconos.size - 1
     UnaImagen = lstImagenesIconos.Get(Numero)

No se almacena el nombre de la imagen, sino que se guarda lo siguiente:"[Ljava.lang.String;@7250aaa"
 
Last edited:

Seneca

Active Member
Licensed User
Bien, ahora si. Una consulta, pera recorrer la lista con las imágenes pendientes y descargarlas, intengo hacerlo de la siguiente manera pero no funciona:
B4X:
For Each imagenItem In lstImagenesPendientes
        hilo.Download("http://www.miservidor.com/img/" & imagenItem)
    Next imagenItem

No indicas qué significa ese "no funciona".

¿Te salta algún error?

¿Has comprobado que "imagenItem" tiene el nombre de un archivo?

¿Has usado el JobDone correspondiente a tu hilo.Download?

Algo así como:

B4X:
Sub JobDone(Job As HttpJob)
    ....
        ....

    If Job.Success Then
        Dim out As OutputStream
        out = File.OpenOutput(File.DirDefaultExternal,Job.JobName,False )
        File.Copy2(Job.GetInputStream, out)
        out.Close
        Log ("*** Cargado " & Job.JobName)
                ....
                ....
                ....

Tambien tengo otro problema, en la siguiente linea:
B4X:
For Numero = 0 To lstImagenesIconos.size - 1
     UnaImagen = lstImagenesIconos.Get(Numero)

No se almacena el nombre de la imagen, sino que se guarda lo siguiente:"[Ljava.lang.String;@7250aaa"

¿Puedes poner el código que rellena el lstImagenesIConos?

Saludos.
 

ferpahud

Active Member
Licensed User
No indicas qué significa ese "no funciona".

¿Te salta algún error?

¿Has comprobado que "imagenItem" tiene el nombre de un archivo?

¿Has usado el JobDone correspondiente a tu hilo.Download?

Algo así como:

B4X:
Sub JobDone(Job As HttpJob)
    ....
        ....

    If Job.Success Then
        Dim out As OutputStream
        out = File.OpenOutput(File.DirDefaultExternal,Job.JobName,False )
        File.Copy2(Job.GetInputStream, out)
        out.Close
        Log ("*** Cargado " & Job.JobName)
                ....
                ....
                ....



¿Puedes poner el código que rellena el lstImagenesIConos?

Saludos.

Marca el siguiente error:
fc27c071f53b435c83d015571df927db.png


no eh utilizado JobDone para hilo.download

Y el codigo que utilizo para cargar lstImagenesIconos fue el propuesto por usted:
B4X:
Sub imagenesCargadas
'Con lo siguiente consultas la BD y guardas en la lista lstImagenesIconos el nombre de todas las imagenes de los botones de los menus
lstImagenesIconos.Initialize
lstImagenesIconos = DBUtils.ExecuteMemoryTable(s, "SELECT imagen FROM rubros", Null,0)
End Sub

Saludos!
 

Seneca

Active Member
Licensed User
Marca el siguiente error:
fc27c071f53b435c83d015571df927db.png

Next imagenItem es incorrecto. Debes elimincar imagenItem

no eh utilizado JobDone para hilo.download

Es necesario el JobDone. Deberías repasar el uso de la librería OKHttp. En el ejemplo que se publica en el mensaje #1 de esta librería tienes una muestra del funcionamiento completo del procedimiento Download y su correspondiente y necesario JobDone.

Y el codigo que utilizo para cargar lstImagenesIconos fue el propuesto por usted:
B4X:
Sub imagenesCargadas
'Con lo siguiente consultas la BD y guardas en la lista lstImagenesIconos el nombre de todas las imagenes de los botones de los menus
lstImagenesIconos.Initialize
lstImagenesIconos = DBUtils.ExecuteMemoryTable(s, "SELECT imagen FROM rubros", Null,0)
End Sub

No sé a qué puede deberse que no se almacene el nombre de la imagen. En el código que te indiqué más arriba, yo Dimensionaba la lista lstImagenesIconos aunque no la Inicializaba. Tú lo haces al contrario. Mira a ver si puede ir por ahí.

Saludos.
 

ferpahud

Active Member
Licensed User
@Seneca lo de la lista finalmente lo resolví de la siguiente manera, ahora si guarda de forma correcta el nombre de la imagen con el metodo imagenesCargadas, luego comparo las imágenes que se encuentran en DirAssets para saber cuales están pendientes de descargar, con el método imagenesPendientes:
B4X:
Sub imagenesCargadas
'Con lo siguiente consultas la BD y guardas en la lista lstImagenesIconos el nombre de todas las imagenes de los comercios
lstImagenesIconos.Initialize
Dim UnaImagen As String
c=s.ExecQuery("SELECT imagen FROM comercios")
If c.RowCount>0 Then
    For i=0 To c.RowCount-1
        c.Position=i
        UnaImagen=c.GetString("imagen")
        lstImagenesIconos.Add(UnaImagen)
    Next
    End If
End Sub

Sub imagenesPendientes
    Dim UnaImagen As String
    lstImagenesPendientes.Initialize
'Con el siguiente For-next recorres la lista de imágenes y compruebas cuáles de ellas las tienes ya descargadas y creas una nueva lista con las que te falten
For Numero = 0 To lstImagenesIconos.size - 1
     UnaImagen = lstImagenesIconos.Get(Numero) 'Recupera de la Lista de imágenes el nombre de cada una
     Log(UnaImagen&" que muestra?")
     'Comprueba si existe la imagen del botón y en caso contrario manda la guarda en la lista de imágenes faltantes

    'Comprueba si el archivo existe
     If Not( File.Exists(File.DirAssets,UnaImagen)) Then
         Log(UnaImagen & " - No existe")
         lstImagenesPendientes.Add(UnaImagen)
     End If
Next
End Sub

Mi ultima duda es sobre descargar las imagenes que tengo en la lista de imagenes pendientes, donde uso el siguiente codigo:
B4X:
Sub descargarImagenes
    hilo.Initialize("hilo",Me)
    For Each imagenItem In lstImagenesPendientes
        hilo.Download("http://centrocomercialva.com.ar/imagenes/" & imagenItem)
        Log(imagenItem & " - Descargada")
    Next
End Sub

Lo que no entiendo si download descarga el archivo de la imagen, y en caso de hacerlo, en que parte lo guarda? Yo necesito que lo guarde en donde estan los archivos de DirAssets, es eso posible? Como lo hago?

EDICION: Cierro el tema, ya que creo que empece a consultar cosas que desviaron el tema. Muchas gracias a todos, saludos!
 
Last edited:

Seneca

Active Member
Licensed User
Lo que no entiendo si download descarga el archivo de la imagen, y en caso de hacerlo, en que parte lo guarda? Yo necesito que lo guarde en donde estan los archivos de DirAssets, es eso posible? Como lo hago?

Vuelvo a insistirte. Repasa la librería que te he indicado en el mensaje #17. Si no implementas un JobDone el .download no descargará nada de nada.

Saludos.
 

ferpahud

Active Member
Licensed User
Vuelvo a insistirte. Repasa la librería que te he indicado en el mensaje #17. Si no implementas un JobDone el .download no descargará nada de nada.

Saludos.
Implemente el JobDOne, pero el problema es que no se donde se descarga la imagen, yo necesito que se descargue en donde se encuentras los archivos de mi aplicación, para cuando compruebe que imágenes que ya fueron descargadas, pueda detectar efectivamente, las que ya se descargaron.... pero si recorro dirAssets y se encuentran en otro lugar no puedo detectarlas....

Saludos y muchas gracias
 
Top