Listener collection / class

pbmi

Member
Licensed User
Longtime User
I want to load a csv data file, line-by-line. For each line read (using textreader.readline), I then want to notify a collection of "listeners".

This collection in turn needs to notify each of its members.

(much like the .NET Observer pattern)

This is easy in VB using classes and the implement keyword, but how can I
implement this in B4A ?

At the moment, I have a Service module that loads the data line by line - but I am not sure where to go from there...
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can do something like this:
B4X:
'code module named NewLineListener
Sub Process_Globals
 Type ListenerFields (f1 As String, f2 As Int)
End Sub

Sub NewLine(obj As ListenerFields, Columns() As String)
 'work with obj and columns
End Sub

'Service module
Sub Process_Globals
 Dim Listeners As List
End Sub

'read CSV loop
Dim f As ListenerFields
For i = 0 To Listeners.Size - 1
 f = Listeners.Get(i)
 NewLineListener.NewLine(f, columns)
Next
 
Upvote 0

pbmi

Member
Licensed User
Longtime User
Thanks, Erel.

I setup the following based on your reply:

1. a Code module, with Listeners as a List variable and a Notify sub which contains the following loop:

Sub Notify(newline as String)
For i=0 To Listeners.Size-1
Log("Listeners.Notify(linestring) is working...")
'*** this is my question as below
next
End Sub

2. a Service module to open the CSV file, read each line using myCSVReader.ReadLine and then call Listeners.Notify(line as linestring):

Do While lineString<>Null
lineString=CSVReader.ReadLine
linesread=linesread+1
Listeners.Notify(lineString)
Loop


The above worked in terms of notifying the collection of Listeners, but I would like to be able "type" the collection so that each Listener in the collection also has a Notify method - much like implementing an interface.

This would allow me to notify each Listener (within my Listeners code module) as follows:

Listeners.Get(i).Notify(newline)

How can I implement this in Basic4Android?

Thanks.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I don't think that you implemented my proposed solution correctly.

In your service you should have a List with all the listeners.
When reading a line you should run this loop:
B4X:
Dim f As ListenerFields is equivalent to the listener instance fields.
For i = 0 To Listeners.Size - 1
 f = Listeners.Get(i)
 NewLineListener.NewLine(f, columns)
Next
NewLine is equivalent to Notify.
The Listener
 
Upvote 0

pbmi

Member
Licensed User
Longtime User
Sorry, but maybe I haven't yet switched from VB to B4A mode to understand your solution. Or I didn't properly explain my requirement.

But I think this will be an important topic to many VB developers who, like myself, really appreciate your product - so..

Let's say I have 2 different classes, each with a DIFFERENT implementation (eg calculation to be performed) within Notify:

Class1:
Sub Notify(newline as string)
' do something with newline
End sub

Class2:
Sub Notify(newline as string)
' do something DIFFERENT with newline
End sub

To implement this in VB, for example, I do the following:

1. Create an Interface class, called say IListener with 1 sub:
Sub Notify(newline as string)
End Sub

2. Create a collection class called say ListenerCollection with:

private myListeners() as IListener
...
Implements IListener
...
Sub IListener_Notify(newline as string)
For i=0 to myListeners.UpperBound
myListeners(i).Notify(newline)
next i
End Sub

3. Create the classes (Class1 and Class2), each with a different implementation of Notify:
...
Implements IListener
...
Sub IListener_Notify(newline as string)
' do something different with newline
End Sub

4. Now, in my application, I can do the following:

Dim Listeners as new ListenerCollection

Dim L1 as new Class1
Dim L2 as new Class2

Listeners.Add(L1)
Listeners.Add(L2)

Dim rdr as new CSVReader
rdr.Listeners=Listeners

...and in my CSVReader:

Do Until EOF

'read line
linestring=myrdr.ReadLine

'notify ALL listeners
Listeners.Notify(linestring)

Loop


As mentioned, I can see how to replicate the CSVReader and notify a collection of listeners - but not how to replicate the different class1 and class2 implementations to support myListeners(i).Notify(newline) as above.

Many thanks
 
Last edited:
Upvote 0

pbmi

Member
Licensed User
Longtime User
Yes, I understood there is no support for classes, hence my original post.

I also checked whether I could use a Type structure plus CallSub() to call a Code module that contained the implementation - but I noticed that CallSub does not support Code modules.


Anyway, I found a solution:

I. I created a calculation class type with the type of calculation as int:

Type calcclass(name as string, calctype as int, values as list)

2. I code each class implementation in a Code module within a Sub Notify():

Sub Notify(newline as linestring, calc as calcclass)
... implementation code
End Sub

3. In the listeners module, I use a Select/Case on calctype to call the correct implementation:

Dim listener As calcclass
Dim ub As Long
ub=listeners.Size-1

If listeners.IsInitialized=True Then

For i=0 To ub

' *** get calc object
listener = listeners.Get(i)

'*** select correct calc implementation
Select listener.indtype
Case 0
calc0.Notify(linestring,listener)
Case 1
calc1.Notify(linestring,listener)
...
End Select

Next

End If

Not the prettiest way, but it worked.

Going forward, I think it would be good if the CallSub() also supported Code modules - this would remove the need to use/maintain a Select/Case.

Thanks
 
Upvote 0

pbmi

Member
Licensed User
Longtime User
Just wondered whether anyone else has encountered/overcome this issue of classes / listeners ?

Is there a better way to resolve this out than the solution I posted?

Thanks

Sent from my GT-P7500 using Tapatalk 2
 
Upvote 0
Top