Android Tutorial Classes tutorial

Basic4android v2.00 adds support for classes modules.

Classes definition from Wikipedia:

Example:
B4X:
'Class Person module
Sub Class_Globals
   Private FirstName, LastName As String
   Private BirthDate As Long
End Sub

Sub Initialize (aFirstName As String, aLastName As String, aBirthDate As Long)
   FirstName = aFirstName
   LastName = aLastName
   BirthDate = aBirthDate
End Sub

Public Sub GetName As String
   Return FirstName & " " & LastName
End Sub

Public Sub GetCurrentAge As Int
   Return GetAgeAt(DateTime.Now)
End Sub

Public Sub GetAgeAt(Date As Long) As Int
   Dim diff As Long
   diff = Date - BirthDate
   Return Floor(diff / DateTime.TicksPerDay / 365)
End Sub

'Main module
...
Dim p As Person
p.Initialize("John", "Doe", DateTime.DateParse("05/12/1970"))
Log(p.GetCurrentAge)

I will start by explaining the differences between classes, code modules and types.

Similar to types, classes are templates. From this template you can instantiate any number of objects.
The type fields are similar to the classes global variables. However unlike types which only define the data structure, classes also define the behavior. The behavior is defined in the classes subs.

Unlike classes which are a template for objects, code modules are collections of subs. Another important difference between code modules and classes is that code modules always run in the context of the calling sub (the activity or service that called the sub). The code module doesn't hold a reference to any context. For that reason it is impossible to handle events or use CallSub with code modules.
Classes store a reference to the context of the activity or service module that called the Initialize sub. This means that classes objects share the same life cycle as the service or activity that initialized them.

Code modules are somewhat similar to singleton or static classes.

Adding a class module
Adding a new or existing class module is done by choosing Project -> Add New Module -> Class module or Add Existing module.
Like other modules, classes are saved as files with bas extension.

Classes structure
Classes must have the following two subs:

Class_Globals - This sub is similar to the activity Globals sub. These variables will be the class global variables (sometimes referred to instance variables or instance members).

Initialize - A class object should be initialized before you can call any other sub. Initializing an object is done by calling the Initialize sub. When you call Initialize you set the object's context (the parent activity or service).
Note that you can modify this sub signature and add arguments as needed.

In the above code we created a class named Person and later instantiate an object of this type:
B4X:
Dim p As Person
p.Initialize("John", "Doe", DateTime.DateParse("05/12/1970"))
Log(p.GetCurrentAge)

Calling initialize is not required if the object itself was already initialized:
B4X:
Dim p2 As Person
p2 = p 'both variables now point to the same Person object.
Log(p2.GetCurrentAge)

Polymorphism
Polymorphism allows you to treat different types of objects that adhere to the same interface in the same way.
Basic4android polymorphism is similar to the Duck typing concept.

As an example we will create two classes named: Square and Circle.
Each class has a sub named Draw that draws the object to a canvas:
B4X:
'Class Square module
Sub Class_Globals
   Private mx, my, mLength As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Sub Initialize (x As Int, y As Int, length As Int)
   mx = x
   my = y
   mLength = length
End Sub

Sub Draw(c As Canvas)
   Dim r As Rect
   r.Initialize(mx, my, mx + mLength, my + mLength)
   c.DrawRect(r, Colors.White, False, 1dip)
End Sub
B4X:
'Class Circle module
Sub Class_Globals
   Private mx, my, mRadius As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Sub Initialize (x As Int, y As Int, radius As Int)
   mx = x
   my = y
   mRadius = radius
End Sub

Sub Draw(cvs As Canvas)
   cvs.DrawCircle(mx, my, mRadius, Colors.Yellow, False, 1dip)
End Sub

In the main module we create a list with Squares and Circles. We then go over the list and draw all the objects:
B4X:
Sub Process_Globals
   Dim shapes As List
End Sub

Sub Globals
   Dim cvs As Canvas  
End Sub

Sub Activity_Create(FirstTime As Boolean)
   cvs.Initialize(Activity)
   Dim sq1, sq2 As Square
   Dim circle1 As Circle
   sq1.Initialize(100dip, 100dip, 50dip)
   sq2.Initialize(2dip, 2dip, 100dip)
   circle1.Initialize(50%x, 50%y, 100dip)
   shapes.Initialize
   shapes.Add(sq1)
   shapes.Add(sq2)
   shapes.Add(circle1)
   DrawAllShapes
End Sub

Sub DrawAllShapes
   For i = 0 To shapes.Size - 1
      CallSub2(shapes.Get(i), "Draw", cvs) 'Call Draw of each object
   Next
   Activity.Invalidate
End Sub
(the example code is attached)

As you can see, we do not know the specific type of each object in the list. We just assume that it has a Draw method that expects a single Canvas argument. Later we can easily add more types of shapes.
You can use the SubExists keyword to check whether an object includes a specific sub.

You can also use the Is keyword to check if an object is of a specific type.

Self reference
The Me keyword returns a reference to the current object. 'Me' keyword can only be used inside a class module.
Consider the above example. We could have passed the shapes list to the Initialize sub and then add each object to the list from the Initialize sub:
B4X:
Sub Initialize (Shapes As List, x As Int, y As Int, radius As Int)
   mx = x
   my = y
   mRadius = radius
   Shapes.Add(Me) 'Me is used to add this object to the list
End Sub

Activity object
This point is related to the activities special life cycle. Make sure to first read the activities and processes life-cycle tutorial.

Android UI elements hold a reference to the parent activity. As the OS is allowed to kill background activities in order to free memory, UI elements cannot be declared as process global variables (these variables live as long as the process lives). Such elements are named Activity objects. The same is true for custom classes. If one or more of the class global variables is of a UI type (or any activity object type) then the class will be treated as an "activity object". The meaning is that instances of this class cannot be declared as process global variables.

Properties
Starting from B4A v2.70, classes support properties. Properties syntax can be considered a syntactic sugar.
Properties combine two methods into a single "field" like member.
For example the two following methods:
B4X:
'Gets or sets the text
Sub getText As String
   Return btn.Text
End Sub

Sub setText(t As String)
   btn.Text = t
End Sub
Are merged automatically into a single property:



The property can be treated like any other field:
B4X:
Dim c1 As SomeClass
c1.Text = "abc"
Log(c1.Text)

The rules for properties:
- Only relevant for classes.
- One or two subs with the format get<prop> / set<prop>. Note that get / set must be lower case.
- A property can be read-only (only get), write-only (only set) or both.
- The two subs types (parameter in the set sub and return type in the get sub) must be the same.
- Within the class you should call the methods directly. The property will not appear.
- The property cannot have the same name as a global variable.

Related links:
Built-in documentation
Variables & Objects
Variables & Subs visibility
 

Attachments

  • Draw.zip
    7.1 KB · Views: 2,460
Last edited:

nad

Active Member
Licensed User
Longtime User
This is incredible. What an awesome tool is basic4android. Thanks a lot
 

BarrySumpter

Active Member
Licensed User
Longtime User
Thanks Erel!

I'm getting the Invalid Email address with executing v2.
Have already sent email to support.
Waiting patiently and having a read about classes and how to implement via b4a v2.
I didn't install over the top of v1.92 so can continue developing until then.


I've attempted classes about 12 times in my 35 years in IT.
The first was with C++.
Far too complex for me at that stage and was the reason I moved to VB 2.0
Experience was not much better thru out the following years.
Either the project didn't require it or my interest failed as no progress from complexity.
.net was so intricate and complex I moved to REALbasic, etc.

This is the first time I'm really looking forward to having another go at classes
knowing that b4a motto will be "keeping it simple".

I've read thru the first post but it didn't explain how I could dim p as Person.
More specific how do we define Person as a class.
Since I can't execute v2 yet, I'm thinking its something like:
Project | Add New Module | Class Module | Name: Person

Would that be correct?


Also, if it turns out that classes in b4a are to complex for me,
will I be left out regarding future development and support?

Really look forward to sinking me teeth into this.
 
Last edited:

netchicken

Active Member
Licensed User
Longtime User
Barry here is a lesson i am writing about classes at the moment. I hope this helps. There seems to be numerous ways to write them looking at other peoples code here.

edit: fixed typos
 

Attachments

  • Visual basic for Android class.zip
    302 KB · Views: 904
Last edited:

BarrySumpter

Active Member
Licensed User
Longtime User
Hi netchicken,
Many thanks for the excellent contribution!

What does the suffic _c designate?

Centigrade?
 

netchicken

Active Member
Licensed User
Longtime User
Yep, Centigrade weatherunderground.com call their fields with _f or _c to differentiate the two types.
 
Last edited:

claudio

Member
Licensed User
Longtime User
Very nice Erel!
It's what i waiting for to upgrade from my 1.6 version.

But what about inheritance?
Simple inheritance is enough but is useful.
example:

B4X:
'Class Shape module
Sub Class_Globals
    Private mx, m As Int
End Sub

Sub Initialize (x As Int, y As Int, length As Int)
    mx = x
    my = y
End Sub

Sub AddList(Shapes As List)
    Shapes.Add(Me)
End Sub

B4X:
'Class Square module
Sub Class_Globals from Shape
    Private mLength As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Sub Initialize (x As Int, y As Int, length As Int)
    Shape.Initialize(x,y)
    mLength = length
End Sub

Sub Draw(c As Canvas)
    Dim r As Rect
    r.Initialize(mx, my, mx + mLength, my + mLength)
    c.DrawRect(r, Colors.White, False, 1dip)
End Sub

In this way each class derived from shape can use the AddList method.

otherwise i can do something like:

B4X:
'Class Square module
Sub Class_Globals
    Public s As Shape
    Private mLength As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Sub Initialize (x As Int, y As Int, length As Int)
    s.Initialize(x,y)
    mLength = length
End Sub

Sub Draw(c As Canvas)
    Dim r As Rect
    r.Initialize(s.mx, s.my, s.mx + mLength, s.my + mLength)
    c.DrawRect(r, Colors.White, False, 1dip)
End Sub

but inheritance is better.

Claudio
 

keirS

Well-Known Member
Licensed User
Longtime User
Erel would it be possible to have Access and Assign methods implemented in a future release? I find these very useful in other OOP languages
 

keirS

Well-Known Member
Licensed User
Longtime User
Do you mean properties? Like Button.Left ?

No to give you an idea:

B4X:
'Class module
Sub Class_Globals
   
    Public FirstName, LastName As String
    Public BirthDate As Long
End Sub

Sub Initialize (aFirstName As String, aLastName As String, aBirthDate As Long)
    FirstName = aFirstName
    LastName = aLastName
    BirthDate = aBirthDate
End Sub



Public Sub GetCurrentAge As Int
    Return GetAgeAt(DateTime.Now)
End Sub


Private Sub FirstName_Assgin(aFirstName As String)
    'Do assign code here

End Sub

I changed the class so FirstName and LastName are public members. Sub FirstName_Assgin would be called each time the value of FitstName is changed. The Access method would be called each time the value of FirstName is retrieved.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Are you talking Get and Set methods or events/triggers that execute when the variables are changed? Get and Set are just methods and usually the variables are private and you have access to them through the methods...this can be done right now. Autocreation of them are just IDE perks in other languages. If you are talking event/trigger that fires each time the variables are changed it sounds like you really just need Get/Set methods with the code since they are executed every time the variables are changed then the variables always/only change in the Get/Set so the code can be in there.
 

Jost aus Soest

Active Member
Licensed User
Longtime User
It would be nice to define for a private variable a getter and a setter, but accessing them like a usual attribut.
I.e.: obj.x = 5 would call the setter setX(...), while n = obj.x would call the getter getX().

In this way you can write pretty code and have in the same time full control over the attribut.
 

stevel05

Expert
Licensed User
Longtime User
Have a look here

The fastscroll class creates a scroll view on a panel or activity that is passed to it.
 
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…