Android Tutorial 💡 Part 2 Examples - Creating long lists using xCustomListView with Lazy Loading - Newer developers

kps

Member
@Peter Simpson
Thank you for the example under #1.
I have always felt comfortable and very educative to take an existing example, modify it, play with it and understand how it works.

Out of curiosity, I wanted to check if the search feature works for non-English languages also.
I modified the names in chinook.db and tried it out.
It works!
I am so excited !

Thanks a lot.

Best regards,
KPS
 

Daniel44

Active Member
Licensed User
Here is the Lazy Loading example for loading airport information from the SQLite database that has 7698 rows of airport data.

In my example video from last week, I was loading all 7698 rows of data directly into the xCLV and it populating extremely quickly. I strongly suggest that you DO NOT replicate what I did and load all the data at once. I have changed the sql query to limit the results to 2000 rows of data. I have a few fast devices that allowed me to accomplish populating all the data relatively quickly, slower devices would definitely struggled to accomplish the same feat.

>>> CLICK HERE <<< to download the Airports example code.

View attachment 88728

Enjoy...
Hey Sir wonderful job it is very useful. Can you answer a question? I have a database with Countries and their cities and I'm using your Airport Example but I don't know how group the countries with their cities, in the airport example the header shows the airport name and below its city. I'm looking for something like than but below the header all Country's cities Can you post an example ? Thank you Sir
 

Peter Simpson

Expert
Licensed User
Hey Sir wonderful job it is very useful. Can you answer a question? I have a database with Countries and their cities and I'm using your Airport Example but I don't know how group the countries with their cities, in the airport example the header shows the airport name and below its city. I'm looking for something like than but below the header all Country's cities Can you post an example ? Thank you Sir
Hello @Daniel44,
Working from memory (or should I say what I think is a logical design), I think that the following should work. I've not tested it, I'm answering your question directly on my phone, I have not computers or laptops currently switched on.
B4X:
SELECT * FROM airports ORDER BY Country, City ASC;
Or something like that.

Enjoy...
 

Daniel44

Active Member
Licensed User
Hello @Daniel44,
Working from memory (or should I say what I think is a logical design), I think that the following should work. I've not tested it, I'm answering your question directly on my phone, I have not computers or laptops currently switched on.
B4X:
SELECT * FROM airports ORDER BY Country, City ASC;
Or something like that.

Enjoy...
Thank you for asking Sir. Maybe I didn't explain myself well. I've changed this:

B4X:
If New.Length = 0  Then
        AirportsCount = Starter.SQL.ExecQuerySingleResult("SELECT COUNT(*) FROM `airports`;") 'The amuont of airports listed in the database
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` ORDER BY `Name` ASC LIMIT ${Limit};"$, Null) 'I NO NOT RECOMMEND that you load the whole database
    Else
        AirportsCount = 0
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` WHERE `Name` Like '%${New}%' ORDER BY `Name` ASC LIMIT 500;"$, Null) 'Limited for slower devices
    End If

    Wait For (SenderFilter) SQL_QueryComplete (Success As Boolean, rs As ResultSet)
    If Success Then
        Dim StartTime As Long = DateTime.Now
        Do While rs.NextRow
            Dim AD As AirportData
                AD.Initialize
                AD.Name    = rs.GetString("Name")
                AD.AirportID = rs.GetString("Airport ID")
                AD.IATA    = rs.GetString("IATA")
                AD.ICAO    = rs.GetString("ICAO")
                AD.City    = rs.GetString("City")
                AD.Latitude    = rs.GetString("Latitude")
                AD.Longitude = rs.GetString("Longitude")
                AD.Altitude    = $"${rs.GetString("Altitude in feet")} ft"$
                
            Dim Pnl As B4XView = XUI.CreatePanel("")
            Pnl.SetLayoutAnimated(0, 0, 0, CLVAirports.AsView.Width, 130dip) 'Panel height + 4 for drop shadow
            CLVAirports.Add(Pnl, AD)
        Loop
        rs.Close


To this:
B4X:
Dim SenderFilter As Object
    If New.Length = 0  Then
        AirportsCount = Starter.SQL.ExecQuerySingleResult("SELECT COUNT(*) FROM `airports`;") 'The amuont of airports listed in the database
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT  * FROM airports order by `Country`,`City` ASC LIMIT ${Limit};"$, Null) 'I NO NOT RECOMMEND that you load the whole database
    Else
        AirportsCount = 0
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` WHERE `Country` Like '%${New}%' ORDER BY `Country` ASC LIMIT 500;"$, Null) 'Limited for slower devices
    End If

    Wait For (SenderFilter) SQL_QueryComplete (Success As Boolean, rs As ResultSet)
    If Success Then
        Dim StartTime As Long = DateTime.Now
        Do While rs.NextRow
            Dim AD As AirportData
                AD.Initialize
                AD.Name    = rs.GetString("Country")
                AD.AirportID = rs.GetString("Airport ID")
                AD.IATA    = rs.GetString("IATA")
                AD.ICAO    = rs.GetString("ICAO")
                AD.City    = rs.GetString("City")
                AD.Latitude    = rs.GetString("Latitude")
                AD.Longitude = rs.GetString("Longitude")
                AD.Altitude    = $"${rs.GetString("Altitude in feet")} ft"$
                
            Dim Pnl As B4XView = XUI.CreatePanel("")
            Pnl.SetLayoutAnimated(0, 0, 0, CLVAirports.AsView.Width, 130dip) 'Panel height + 4 for drop shadow
            CLVAirports.Add(Pnl, AD)
        Loop
        rs.Close
these changes show me this:
Screenshot_20200927-185958.png


and I would like this:

WISH.png


I mean i.e. each country with all its respective cities without the country repeating itself

Would that be possible? If so, what should I change?. Thank you Sir.
 

Unobtainius

Member
Licensed User
@Peter Simpson
ive just finished watching the b4a to b4j video and am simply mind blown. I know we are aiming to write b4x cross platform stuff and in a way your video demonstrates just why we can. I couldn't believe how easily you did it. Bravo sir and I especially loved the what the ?? bit. I'm in a hospital waiting room just now (for my old mum) so will have to wait to have a look at the lazy loading examples but I'm sure they will provide me lots of insight. Thanks Peter, keep the exceptional work
 

QinLiwei

New Member
Hi, Peter Simpson, I can't download these examples because I can't access www.dropbox.com, but I really need them. Could you upload them to the B4X forum or send me an email?My email address is :88251404@qq.com. I am looking forward to your reply. Thank you very much!
 

anOparator

Active Member
Licensed User
This is another good post on CustomListView but I get this error compiling the Invoices example, in Debug and Release mode using B4A 10.2
B4X:
Copying updated assets files (6)
*** Service (starter) Create ***
java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/core/content/ContextCompat;
    at anywheresoftware.b4a.objects.RuntimePermissions.GetSafeDirDefaultExternal(RuntimePermissions.java:120)
    at com.simplysoftware.chinookinvoices.starter$ResumableSub_Service_Create.resume(starter.java:188)
    at com.simplysoftware.chinookinvoices.starter._service_create(starter.java:165)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
    at com.simplysoftware.chinookinvoices.starter.onCreate(starter.java:56)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:3342)
    at android.app.ActivityThread.-wrap4(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1680)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6518)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.ContextCompat" on path: DexPathList[[zip file "/data/app/com.simplysoftware.chinookinvoices-n5cNwPjejJXmRQHC4CW1GA==/base.apk"],nativeLibraryDirectories=[/data/app/com.simplysoftware.chinookinvoices-n5cNwPjejJXmRQHC4CW1GA==/lib/arm, /system/lib, /vendor/lib]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    ... 20 more
java.lang.RuntimeException: Unable to create service com.simplysoftware.chinookinvoices.starter: java.lang.RuntimeException: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/core/content/ContextCompat;
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:3352)
    at android.app.ActivityThread.-wrap4(Unknown Source:0)
It was uploaded to https://www.dropbox.com/s/6c669byshlonjrn/xCLV LL Invoices.zip?dl=0
What to do, what to do?
 

DonManfred

Expert
Licensed User
This is another good post on CustomListView but I get this error compiling the Invoices example, in Debug and Release mode using B4A 10.2
1. You should create a new thread for any issue you have
2. You are not using AndroidX. You still use android-support which is deprecated and not longer available.
Follow the Installation instructions carefully: https://www.b4x.com/b4a.html
 

Unobtainius

Member
Licensed User
Thank you for asking Sir. Maybe I didn't explain myself well. I've changed this:

B4X:
If New.Length = 0  Then
        AirportsCount = Starter.SQL.ExecQuerySingleResult("SELECT COUNT(*) FROM `airports`;") 'The amuont of airports listed in the database
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` ORDER BY `Name` ASC LIMIT ${Limit};"$, Null) 'I NO NOT RECOMMEND that you load the whole database
    Else
        AirportsCount = 0
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` WHERE `Name` Like '%${New}%' ORDER BY `Name` ASC LIMIT 500;"$, Null) 'Limited for slower devices
    End If

    Wait For (SenderFilter) SQL_QueryComplete (Success As Boolean, rs As ResultSet)
    If Success Then
        Dim StartTime As Long = DateTime.Now
        Do While rs.NextRow
            Dim AD As AirportData
                AD.Initialize
                AD.Name    = rs.GetString("Name")
                AD.AirportID = rs.GetString("Airport ID")
                AD.IATA    = rs.GetString("IATA")
                AD.ICAO    = rs.GetString("ICAO")
                AD.City    = rs.GetString("City")
                AD.Latitude    = rs.GetString("Latitude")
                AD.Longitude = rs.GetString("Longitude")
                AD.Altitude    = $"${rs.GetString("Altitude in feet")} ft"$
               
            Dim Pnl As B4XView = XUI.CreatePanel("")
            Pnl.SetLayoutAnimated(0, 0, 0, CLVAirports.AsView.Width, 130dip) 'Panel height + 4 for drop shadow
            CLVAirports.Add(Pnl, AD)
        Loop
        rs.Close


To this:
B4X:
Dim SenderFilter As Object
    If New.Length = 0  Then
        AirportsCount = Starter.SQL.ExecQuerySingleResult("SELECT COUNT(*) FROM `airports`;") 'The amuont of airports listed in the database
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT  * FROM airports order by `Country`,`City` ASC LIMIT ${Limit};"$, Null) 'I NO NOT RECOMMEND that you load the whole database
    Else
        AirportsCount = 0
        SenderFilter = Starter.sql.ExecQueryAsync("SQL", $"SELECT * FROM `airports` WHERE `Country` Like '%${New}%' ORDER BY `Country` ASC LIMIT 500;"$, Null) 'Limited for slower devices
    End If

    Wait For (SenderFilter) SQL_QueryComplete (Success As Boolean, rs As ResultSet)
    If Success Then
        Dim StartTime As Long = DateTime.Now
        Do While rs.NextRow
            Dim AD As AirportData
                AD.Initialize
                AD.Name    = rs.GetString("Country")
                AD.AirportID = rs.GetString("Airport ID")
                AD.IATA    = rs.GetString("IATA")
                AD.ICAO    = rs.GetString("ICAO")
                AD.City    = rs.GetString("City")
                AD.Latitude    = rs.GetString("Latitude")
                AD.Longitude = rs.GetString("Longitude")
                AD.Altitude    = $"${rs.GetString("Altitude in feet")} ft"$
               
            Dim Pnl As B4XView = XUI.CreatePanel("")
            Pnl.SetLayoutAnimated(0, 0, 0, CLVAirports.AsView.Width, 130dip) 'Panel height + 4 for drop shadow
            CLVAirports.Add(Pnl, AD)
        Loop
        rs.Close
these changes show me this:
View attachment 100635

and I would like this:

View attachment 100636

I mean i.e. each country with all its respective cities without the country repeating itself

Would that be possible? If so, what should I change?. Thank you Sir.
If you think about the custom list control simply as a list that can accept any layout you want to place into each item, it opens your mind to many possibilities. In general people use it to show the same type of item layout over and over, but you don't have to.

For what you are looking to achieve I would have a layout for the header (country) and a layout for the airport. Then have a variable to hold the country name and if the country you are about to insert is different from that, insert the header as a new item, then the airport as a new item. If the country has not changed then just add the airport as an item. Just remember to update your variable to the country being inserted after your decision.

Just one possible solution
 

Daniel44

Active Member
Licensed User
If you think about the custom list control simply as a list that can accept any layout you want to place into each item, it opens your mind to many possibilities. In general people use it to show the same type of item layout over and over, but you don't have to.

For what you are looking to achieve I would have a layout for the header (country) and a layout for the airport. Then have a variable to hold the country name and if the country you are about to insert is different from that, insert the header as a new item, then the airport as a new item. If the country has not changed then just add the airport as an item. Just remember to update your variable to the country being inserted after your decision.

Just one possible solution
Thank you @Unobtainius
 
Top