Android Question calling a method a Class which uses asynchronous data retrieval

moster67

Expert
Licensed User
Longtime User
Well, I must admit I have never used classes that much. However, now I am rewriting a lot of code transforming them into classes (and perhaps later into B4A-libraries) so the code may be easily (re)used in other similar apps without much ado.

I have gone through most examples and most things seem rather clear. However, I have problems with classes that fetch data using the httputils2-library (or the class). I don't know how to return the data retrieved in the class to the method called in Main. In the class, I think the problem is that the return value is generated in the JobDone-sub (due to the nature of asynchronous data retrieval) and there is no way to pass it back to my method which is called in Main.

Here is some pseudo-code:

let us say I have this method-call in Main:
B4X:
dim mydata as mygetdatacall

mydata.initialize
log(mydata.getXMLreply)

here is the class mygetdatacall:
B4X:
Sub Class_Globals
    Dim mysaxparser As SaxParser
    Private Myreturndata As String
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
End Sub

Sub getXMLreply As String  
        Dim JOBgetmydata As HttpJob
        Dim myURL As String= "http://192.168.1.80/web/about"
      
        JOBgetmydata.Initialize("JOBgetmydata", Me)
        JOBgetmydata.Username="myusername"
        JOBgetmydata.Password="mypassword"
        JOBgetmydata.Download(myURL)

        'return    Myreturndata 'does not work - sub is not being used again
End Sub

Sub JobDone (Job As HttpJob)
    Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
    If Job.Success = True Then
        Select Job.JobName          
            Case "JOBgetmydata"  
                Try
                    mysaxparser.Initialize
                    Dim result_data As InputStream
                    result_data = Job.GetInputStream
                    mysaxparser.Parse(result_data, "mysaxparser")  
                Catch
                    'do something different
                End Try              
                Return Myreturndata '??? how to return data to the method(sub) getXMLreply
        End Select
    Else
        Log("Error: " & Job.ErrorMessage)      
    End If
    Job.Release
    Log("job was released")
End Sub

Sub mysaxparser_EndElement (Uri As String, Name As String, Text As StringBuilder)
    If mysaxparser.Parents.IndexOf("about") > - 1 Then
        If Name = "service" Then
            Myreturndata = Text.ToString
                If Myreturndata.Length = 0 Then
                    Myreturndata = "No data"
                End If
        End If
    End If
End Sub


How can I get this to work?

B4X:
Return Myreturndata

to be returned as a result from the class when calling it from Main:

B4X:
log(mydata.getXMLreply)

???

I can use callsub or using Process global variables for sharing data within the app but it seems not right when classes are available in B4A and I could retrieve data using a simple method-call. Probably I might be missing something very obvious.

Anyone who can help me to shed some lights? Thanks!
 

moster67

Expert
Licensed User
Longtime User
@tds: Yes, I know I can do that and that is the way I started writing my classes and how to make my code more flexible. But then I thought there might be another way of doing it (I mean, more properly) but I guess at this point, due to the the asynchronous process, there is no better (flexible) way. No worries, even by using CallSub2 and having different jobs outlined in a class, I will end up with much more manageable code compared to now

Thx
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
One option is to use CallSub to call a sub in the activity.
The second option which is a bit less elegant is to handle JobDone in the activity and delegate this call to the class. If you check Remote Database Connector B4A code you will see that I chose to handle JobDone in the activity (or service). This is done by setting the target object in Job.Initialize to the target object passed to the class (see the code there it will be more clear).

The advantage of handling JobDone in the activity or service is related to the behavior of CallSubDelayed. If the application is in the background then it will store the message in a special message queue (note that its length is limited) and then run the message when the activity is resumed. You will not get this behavior if the target is a class.
 
Upvote 0
Top