The most obvious solution here is a cross between all of those you mentioned; basically paging. Load a set number and then allow the user to page backward and forward using a numbered page sequence above or below the ListView control.
To speed up further don't use an active RecordSet; instead, load the data into an array and directly drop the information into the control. Use an alternative form if you want to edit the information rather than editing in the ListView control.
Alternatively you could just create your own ListView equivalent and write the objects directly onto the form yourself using your own format.
I think that if you have to use something like LockWindowUpdate then you're going down the wrong path. You should just be able to use the appropriate property of the control to prevent user interference.
-- EDIT --
The idea is to read the data into an array in memory and then loop through it and populate your ListView in a similar way to this:
Private Function TestInsertListView() As Long
Dim i As Long
Dim j As Long
Dim lT As Long
Dim itmX As ListItem
lT = timeGetTime
' Add first row
With lvwTest
i = 1
Set itmX = .ListItems.Add(, , "Row" & i & ";Col 1")
For j = 2 To mcCOLS
itmX.SubItems(j - 1) = "Row" & i & ";Col" & j - 1
Next
For i = 2 To m_iRows
Set itmX = .ListItems.Add(i, , "Row" & i & ";Col 1")
For j = 2 To mcCOLS
itmX.SubItems(j - 1) = "Row" & i & ";Col" & j - 1
Next
Next
End With
TestInsertListView = timeGetTime - lT
End Function
(I found the above example here.)
Obviously you'd need to modify the above to include the reading of the data but that should be pretty straightforward. This link gives a demo of the ADO GetRows method which allows you to read the data.
LockWindowUpdate()for this issue. It's global and will unlock anything that's using it for the real purpose.