Android Question Activity freeze when service is working

xcl

Member
Licensed User
Activity freeze when service is working

Hi all...
(sorry for my English)

I have a some problem with user UI and service for sync.

My project contains three module.
- main activity module
- starter service module
- servece module (named "background") for sync with server via httpjob

When activity is start i called (CallSubDelayed) sync procedure from Background.
In sync procedure i call HttpJob.PostString
JobDone rised in Background module and i work with data from server.
Processing server data may take long time (5 - 100 seconds) and in this time my activity is freezed...

The main reason for the long processing of data in my case - searching contact by phone number in user phonebook for name and photo.

I assumed that the work of the service should not be reflected in the work of the activity
But I can not do it work

It is possible make it that service working do not freeze user UI?


Simple variant of my code:

Main:
B4X:
#Region  Project Attributes
    #ApplicationLabel: syncTest
    #VersionCode: 1
    #VersionName: 1
    '#BridgeLogger: True
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

Sub Activity_Create(FirstTime As Boolean)
   
    Activity.LoadLayout("main")
    Log("Started")
   
    CallSubDelayed(BackGround,"Sync")
End Sub

Starter
B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
End Sub

Sub Service_Create
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Sub Service_TaskRemoved
    'This event will be raised when the user removes the app from the recent apps list.
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy

End Sub


Background:
B4X:
#Region  Service Attributes
    #StartAtBoot: False
    '#StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Service_Create

End Sub

Sub Service_Start (StartingIntent As Intent)
    Log("Background service start...")
   
   
'    Dim n As Notification
'    n.Initialize
'    n.Icon = "icon"
'    n.SetInfo2("qwertyu", "gthjkl","for", Me)
'    n.AutoCancel = True
'    Service.StartForeground(1,n)
'    Service.StopForeground(1)
   
End Sub



Sub Sync
    Dim job As HttpJob
    Dim jobPS As String
   
    job.Initialize("GetPhoneList",Me)
    jobPS = job.PostString ("mytestserver.com/GetPhoneList, "user=user1")
End Sub

Sub Service_Destroy
    Log("Background destroy")
End Sub

Public Sub OnlyDigits(St As String) As String
    St=St.Replace("-","")
    St=St.Replace(".","")
    St=St.Replace("(","")
    St=St.Replace(")","")
    St=St.Replace("+","")
    St=St.Replace(" ","")
    Return St
End Sub

Public Sub GetContactsMap()
   
    Dim cu As ContactsUtils
    cu.Initialize
    Dim ac As List = cu.FindAllContacts(True)
   
    Dim Res As Map
    Res.Initialize
   
    Starter.ContactsMap.Initialize
   
    Dim Phones As List
    Dim dPh As String
    For Each Contact As cuContact In ac
        Phones = cu.GetPhones(Contact.Id)
        For Each Ph As cuPhone In Phones
            dPh = OnlyDigits(Ph.Number)
           
            Res.Put("Name", Contact.DisplayName)
            Private Photo As Bitmap = cu.GetPhoto(Contact.id)
            If Photo.IsInitialized Then
                Res.Put("Photo", Photo)
            Else
                Res.Put("Photo", Null)
            End If
           
            Starter.ContactsMap.Put(dPh, Res)          
        Next
    Next                      
End Sub

Public Sub GetContactByPhone(Phone As String) As Map
    Phone = OnlyDigits(Phone)
    Dim Res As Map
    Res.Initialize
   

    Dim cu As ContactsUtils
    cu.Initialize
    Dim ac As List = cu.FindAllContacts(True)
   
   
    Dim Phones As List
    Dim dPh As String
    For Each Contact As cuContact In ac
        Phones = cu.GetPhones(Contact.Id)
        For Each Ph As cuPhone In Phones
            dPh = OnlyDigits(Ph.Number)
            If dPh=Phone Then
               
                Res.Put("Name", Contact.DisplayName)
               
                Private Photo As Bitmap = cu.GetPhoto(Contact.id)
                If Photo.IsInitialized Then
                    Res.Put("Photo", SaveImage(Photo))
                End If
            End If
        Next
    Next
    Return Res
                       
End Sub

Sub JobDone (Job As HttpJob)
    Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
    If Job.Success = True Then
        Job.GetString2("utf-8")
        Log("Info:"&Job.GetString)
        Dim Answ As Map = GetMapFromString(Job.GetString,"#")
   
        For each PhoneNumber as String in Answ
            Contact = GetContactByPhone(PhoneNumber)
                                   
            If Contact.ContainsKey("Name") Then
                Log(Contact.Get("Name"))
            End If
            If Contact.ContainsKey("Photo") Then
                Log("Photo present...")
            End If
        Next  

    End if  
   
End Sub


The most time-consuming line: Phones = cu.GetPhones(Contact.Id)
My phonebook contains more then 1200 contacts...
But that's not the question.

The question is: can the service and interface work in parallel?
Or am I doing something wrong?


Thanks...
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
So for each number you are requestion a list of all contacts and then search the results for the number.
With the next number you again requests a list of all contacts to do a search here. Does not sound efficient.

Load the List of contacts once and then only iterate trough all of them in the search.

Something like

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private allcontacts As List
End Sub
Sub Service_Create
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.
End Sub
Sub Service_Start (StartingIntent As Intent)
    allcontacts.Initialize
    InitContactslist
End Sub

Sub Service_Destroy

End Sub
Public Sub InitContactslist
    Log($"InitContactslist()"$)
    Dim cu As ContactsUtils
    cu.Initialize
    allcontacts = cu.FindAllContacts(True)
    Log($"Found Contacts: ${allcontacts.Size}"$)   
End Sub

And then, in your
GetContactByPhone you do not read a new list. Just use the available list.
also in your GetContactsMap you should use the list already available.
 
Upvote 0

xcl

Member
Licensed User
Thanks!

Service code runs on the main thread.
That answer for my question...


Your code is extremely inefficient.
You should use FindContactsByPhone. If you do need to get all contacts then do it once. Getting the information from the contacts store is a heavy operation
Yes, i known it, that made for example.
In my real code i get contact map one time. But it still long operation...
FindContactsByPhone - don't work with different phone format (+0(123)123-456, +123123456...),

And then, in your
GetContactByPhone you do not read a new list. Just use the available list.
also in your GetContactsMap you should use the list already available.
Thanks, but It's still long as my example, but is not a question :)

I known how to optimize that code.

But i want to make that background service will work in another thread and do not freeze UI.
As I understand it - it's not possible in this way
 
Upvote 0
Top