Android Question How to make a big Loops

Douglas Farias

Expert
Licensed User
Longtime User
Hi all

how can i make a big loops and my app dont stop work?
i have try many ways, inclusive add doevents but my app stop work =

what the best way to make big loops, image loops, text loops etc and the app dont stop work?
for exemple
i made this app
https://play.google.com/store/apps/details?id=filmes.hd.df

this take a response from webservice on json with movie image, movie description, movie name etc
many movies have 500 characters, now i make a simple calc 10 movies *-*

the app stop work sometimes, and i dont know to fix, with doevents dont fix.

what can i make to make big loops and my app dont stop work?
 

RandomCoder

Well-Known Member
Licensed User
Longtime User
There is typically three approaches...
  1. Move the code onto it's own thread and try to adapt it so that it fires an event when all the work is done.
  2. Remove the loop altogether and call a sub to do part of the work. Wait for that work to complete (jobdone event in your case) then call the same sub to do the next part of the work etc until all work is done, after which you can then proceed with the next function.
  3. Similar to option 2. but if an event is not easily available then use a timer to poll a global variable whose state reflects the current state of the program.
As an example, the UPNP browser I am currently writing, browses a device on my network for films. The response might say that 1000 films are available. If I then want to list ALL the films, I simply send a browse request for films with an index of 1 to 100 and await the jobdone event. My code then parses the data and checks if the last film index exceeded the max number of films. If not I then use callsub3 to call the browse sub again but this time giving it a value of 101 so as to get the next list of films and so on until all 1000 films have been browsed. The code is not locked in a loop and it works really well. I could if I wanted choose to load the information in batches of 50 or 200 films at once, it just affects how long the app is sat waiting for the jobdone event to fire and the amount it has to parse afterwards.

Regards,
RandomCoder
 
Upvote 0

Douglas Farias

Expert
Licensed User
Longtime User
@RandomCoder
thx man
i dont understand so much the english *-*

for example on the movie app, when u open the app this make a query to get 100 movies with description, image etc etc.
ok
i put a progressdialogshow on the activity create and the user need wait the query result and listview add itens.
on some devices this times make the app stop work

on new devices dont have problem.

look what i make

B4X:
Sub verifica1
ExecuteRemoteQuery("Select * FROM top20 ORDER BY id DESC LIMIT 100", verificaupdates)
End Sub

B4X:
'HERE IS THE PROBLEM, ON SOME DEVICES THE APP STOP WORK HERE
'THE RESULT IS VERY BIG AND APP STOP WORK
'HAVE A WAY TO RUN THIS ON BACKGROUND OR MAKE APP DONT STOP?
  Case "verificaupdates"
        simcategoria = False
        links.Clear
        painelseries.visible = False
        painelsobre.Visible = False
        listacategorias.Visible = False
        Dim parser As JSONParser
            parser.Initialize(Job.GetString)
            Dim root As List = parser.NextArray
            Dim contador As Int
            kv.DeleteAll
            For Each colroot As Map In root
             contador = contador + 1
             Dim capa_img As String = colroot.Get("capa_img")
             Dim id As String = colroot.Get("id")
             Dim titulo As String = colroot.Get("titulo")
             Dim descricaocurta As String = colroot.Get("descricaocurta")
            kv.PutSimple("capa_img"&contador,capa_img)
            kv.PutSimple("id"&contador,id)
            kv.PutSimple("titulo"&contador,titulo)
            kv.PutSimple("descricaocurta"&contador,descricaocurta)
            links.Add(capa_img)
            Next
        BuildItems


what can i make in this case to app dont stop work?

can u show me one sample pls?
i dont understand so much your english *-*
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
It's very difficult to provide advice with the small sample of code you have listed. I'm certain that the problem will be within the For... Next loop as this is writing data to the device which takes time. You also haven't shown the content of sub "BuildItems", is this another block of code that locks the main thread in a loop?
B4X:
' THE PROBLEM IS ALMOST CERTAINLY HERE IN THIS LOOP
            For Each colroot As Map In root
             contador = contador + 1
             Dim capa_img As String = colroot.Get("capa_img")
             Dim id As String = colroot.Get("id")
             Dim titulo As String = colroot.Get("titulo")
             Dim descricaocurta As String = colroot.Get("descricaocurta")
            kv.PutSimple("capa_img"&contador,capa_img)
            kv.PutSimple("id"&contador,id)
            kv.PutSimple("titulo"&contador,titulo)
            kv.PutSimple("descricaocurta"&contador,descricaocurta)
            links.Add(capa_img)
            Next
  ' WHAT DOES THIS NEXT FUNCTION DO?
        BuildItems

Anyway, I've tried to provide a solution (its untested) which will extract 10 results from the list, update the progressbar and then get the next 10 and so on until all items have been saved. It will then hide the progressbar and call "BuildItems".
NOTE:- Variable root is now a Process_Global variable, I've chosen to extract 10 results at a time but this can easily be changed. It will also affect how often the progressbar is updated!
B4X:
' CHANGE YOUR CODE TO MATCH THIS...
  Case "verificaupdates"
        simcategoria = False
        links.Clear
        painelseries.visible = False
        painelsobre.Visible = False
        listacategorias.Visible = False
        Dim parser As JSONParser
            parser.Initialize(job.GetString)
            root = parser.NextArray
            ExtractResults(0, 10)    ' Extract and save the first 10 results
         ......
         ......

' AND ADD THESE SUBS...
Public Sub ExtractResults(start_index, quantity)
    Dim contador As Int
    If start_index = 0 Then kv.DeleteAll    ' Only delete keyvalue store if starting a new list
    For contador = start_index To Min(start_index + quantity, root.Size - 1)
        Dim colroot As Map = root.Get(contador)
        Dim capa_img As String = colroot.Get("capa_img")
        Dim id As String = colroot.Get("id")
        Dim titulo As String = colroot.Get("titulo")
        Dim descricaocurta As String = colroot.Get("descricaocurta")
        kv.PutSimple("capa_img"&contador,capa_img)
        kv.PutSimple("id"&contador,id)
        kv.PutSimple("titulo"&contador,titulo)
        kv.PutSimple("descricaocurta"&contador,descricaocurta)
        links.Add(capa_img)
    Next
    ' Update progress bar
    CallSubDelayed2("" , "progress_update", contador)
End Sub

Public Sub progress_Update(extracted As Int)
    If extracted < root.Size - 1 Then
        Dim percent As Int
        percent = (extracted / (root.Size - 1) ) * 100
        progress.progress = percent
        progress.Visible = True
        ExtractResults(extracted + 1, 10)    ' Extract the next 10 results
    Else
        progress.progress = 0
        progress.Visible = False
        root.Clear    ' Finished using root list and so clear contents to free memory
        BuildItems
    End If
End Sub

' YOU WILL ALSO NEED TO DECLARE, INITIALISE AND ADD A ProgressBar NAMED progess TO YOUR ACTIVITY

An alternative method would be to change your SQL query and only request the first 10 movies, once this has been returned then modify your query to get the next 10 and so on. This is the approach that I would have possibly taken dependent on how long the data takes to download.

If you can provide a working sample of the problem then I/we might be able to help you better.

Kind Regards,
RandomCoder
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
@Douglas Farias
Did the sample code work? The CallSub delayed should have allowed the message queue to be processed and prevent the app from locking up?

Regards,
RandomCoder
 
Upvote 0

Douglas Farias

Expert
Licensed User
Longtime User
nop i think my problem is on
kv.PutSimple

when i dont use kv the app dont stop, and i get fast result
but i need the kv to save the values *-*
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
On both of the calls to ExtractResults( ) replace the value 10 with 1 instead and see if that works?
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
is the kv (keystore?) stuff you're using nog sqlite based?

which means you do 4x100 queries in that loop aswell.

grabbing that content when needed straight from the parser might solve your issue,
there's no need to store data again somewhere else when it is already available
(you just waste resources (memory, cpu ...))
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
He's not running the query another 4 times, just extracting items from the list. But Douglas is calling the keyvaluestore 4 times for each movie. It might be better to create a type that holds all the info for a movie and just store this instead which would only require one write per movie. But like you say, maybe there is no need to persistently store this data in the first place?

Regards,
RandomCoder
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
that's what I was saying, 4 keystore put is 4(*100) insert or update queries, not?
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
Sorry, yes I see what you meant. I misunderstood your reference to a query as being that of original query to obtain the JSON results :oops:
 
Upvote 0
Top