Android Question Widget questions

Alvsky

Member
Licensed User
Longtime User
Hi all,
I made a widget that shows the name of the saints for each day and I have two questions:

1. After installation, it takes around 20 seconds for widget to be populated. It takes data from database file. Question is why it takes so much time to fetch data from DB and is it maybe normal?

2. I need to update my widget once a day, at midnight, or minute after. For my widget I took a widget example from forum and adjusted it to my needs (at least I think so :) ).
For testing purposes I put a counter (x) to increase by 1 when widget is updated. for update I try to use TimeToNextMinute. What happens is that when I install the widget, counter increases by two immediately (it should not increase until first "controlled" update) and exactly 1 minute after specified time counter starts to tick veeery fast.

So my big question is: What am I doing wrong?

Below is the widget code

B4X:
Sub Service_Create
    x=0

    rv = ConfigureHomeWidget("wdgKatKal", "rv", 0, "Katolicki kalendar")
    rv_RequestUpdate
End Sub

Sub Service_Start (StartingIntent As Intent)

    If StartingIntent.Action = "android.appwidget.action.APPWIDGET_DELETED" Then Return

    If rv.HandleWidgetEvents(StartingIntent) = False Then

        rv_RequestUpdate
    End If

    If StartingIntent.Action <> "android.appwidget.action.APPWIDGET_DISABLED" Then
        StartServiceAt("", TimeToNextMinute, False)
    End If
End Sub

Sub rv_RequestUpdate
   x=x+1
    mnt = DateTime.GetMonth(DateTime.Now) 'find the current month
    yr = DateTime.GetYear(DateTime.Now) 'find the current year
   
    Database
    DateTime.DateFormat = "d.M.yyyy" ' bila je tu točka na kraju
    DateTime.TimeFormat = "HH:mm"

    'saint of the day'
    dbC = dbS.ExecQuery2 ("SELECT sveci,d,m,blagdan,pomicni_blag_"&yr&" FROM 'KatKalendar' WHERE m = ? AND d = ?", Array As String(mnt,DateTime.GetDayOfMonth(DateTime.Now)))
    dbC.Position=0       
...   
   
    dt = dbC.GetString("d")+x

    datum = dt&"."&mnt&"."&yr&"." 
    dan = Days_hr(DateTime.GetDayOfWeek(DateTime.Now))

   

    rv.SetText("lblSveci",sveci)
    rv.SetText("lblDat",datum)
    rv.SetText("lblDan",dan)
    rv.SetText("lblFeast",feast)
    rv.UpdateWidget
End Sub
Sub rv_Disabled
    StopService("")
End Sub

Sub Service_Destroy

End Sub

Sub Database
    Dim ruta As String
   
    If File.ExternalWritable Then
            ruta = File.DirDefaultExternal
        Else
            ruta = File.DirInternal
    End If

'# Always copy new DB file
    File.Copy(File.DirAssets, "kalendar.db", ruta, "kalendar.db")
    dbS.Initialize(ruta, "kalendar.db", True)

End Sub


Sub TimeToNextMinute As Long
    Dim ret As Long
ret=DateTime.TimeParse("10:28")
ret = ret + DateTime.TicksPerMinute
    ret = ret - (ret Mod DateTime.TicksPerMinute)   
    Return ret
End Sub
 

mangojack

Expert
Licensed User
Longtime User
On the Database issue .. every time the widget is updated ,you copy the db from assets then read data.
On service start check for file existence and only copy if not present. It should be present after 1st install and run.

Also remove rv_RequestUpdate form Service Create to avoid error
B4X:
If File.Exists(ruta,"kalendar.db") = False Then
   File.Copy(File.DirAssets, "kalendar.db", ruta, "kalendar.db")
End If
 
Last edited:
Upvote 0

mangojack

Expert
Licensed User
Longtime User
If you want to update your widget only once a day then maybe do something like ..
Make sure the service restarts and reschedules itself after shutdown.
B4X:
#Region  Service Attributes
   #StartAtBoot: True
#End Region

Sub Service_Start (StartingIntent As Intent)
   If StartingIntent.Action <> "android.intent.action.BOOT_COMPLETED" Then
      'do your stuff
    End If

    ScheduleNextServiceStart(0,01)
    StopService("")
End Sub

Sub ScheduleNextServiceStart(Hours As Int, Minutes As Int)

   Dim CurrentTime, Today, NextRunTime, HourMinTicks As Long

   DateTime.DateFormat = "dd-MM-yyyy"

   'calculate ticks for hours and minutes schedule
   HourMinTicks = Hours * DateTime.TicksPerHour + Minutes * DateTime.TicksPerMinute

   'calc ticks up to start of today ... 00:00am
   Today = DateTime.DateParse(DateTime.Date(DateTime.Now))
   'calc ticks up to current/present time
   CurrentTime = DateTime.Now - Today

   If HourMinTicks > CurrentTime Then
       'Time has Not passed, schedule For Today
       NextRunTime = Today + HourMinTicks
   Else 'Schedule for tomorrow
       NextRunTime = Today + DateTime.TicksPerDay + HourMinTicks
   End If

   StartServiceAt("",NextRunTime,True)

   'Log($"NextRunTime: ${NextRunTime} Date: ${DateTime.Date(NextRunTime)} Time: ${DateTime.Time(NextRunTime)}"$)

End Sub

the above works well .. although I think it would be suggested to use DateUtils for above time calcs ..
 
Last edited:
Upvote 0

Alvsky

Member
Licensed User
Longtime User
@mangojack
I tried your solution and it works good first time.
For testing purposes I changed the code to do update every minute and after the first time update happens, i get infinite loop of start and stop service. Here's the log:

B4X:
RexUp-x:0
x:1 Next Run Time: Date:07-03-2016 Time:15:44
** Service (katkal_widget) Destroy **
** Service (katkal_widget) Create **
** Service (katkal_widget) Start **
RexUp-x:0
x:1 Next Run Time: Date:07-03-2016 Time:15:44
** Service (katkal_widget) Start **
RexUp-x:1
x:2 Next Run Time: Date:07-03-2016 Time:15:44
** Service (katkal_widget) Destroy **
** Service (katkal_widget) Create **
** Service (katkal_widget) Start **
RexUp-x:0
x:1 Next Run Time: Date:07-03-2016 Time:15:44
** Service (katkal_widget) Destroy **
** Service (katkal_widget) Create **
** Service (katkal_widget) Start **
RexUp-x:0
x:1 Next Run Time: Date:07-03-2016 Time:15:44
** Service (katkal_widget) Destroy **
** Service (katkal_widget) Create **
** Service (katkal_widget) Start **

These are the changes to the code:

B4X:
Sub ScheduleNextServiceStart(Hours As Int, Minutes As Int)
...

   If HourMinTicks > CurrentTime Then
       'Time has Not passed, schedule For Today
       NextRunTime = Today + HourMinTicks
   Else 'Schedule for tomorrow
       NextRunTime = Today + DateTime.TicksPerDay/1440 + HourMinTicks     <-------- divided with 1440 to get 1 minute
   End If

   StartServiceAt("",NextRunTime,True)
'test = "NextRunTime:" & NextRunTime & " Date:" & DateTime.Date(NextRunTime) &  "Time:" & DateTime.Time(NextRunTime)
   Log("x:" & x & " Next Run Time: Date:" & DateTime.Date(NextRunTime) &  " Time:" & DateTime.Time(NextRunTime))

End Sub
 
Upvote 0

mangojack

Expert
Licensed User
Longtime User
The code I supplied was to start your service at 1 minute past midnight. There was no need to divide by 1440.
B4X:
'Schedule the service to restart @ 0Hrs 1 minute
   ScheduleNextServiceStart(0,01)


If you want to restart every 1 minute I would return to your original method which works as expected ..
B4X:
StartServiceAt("", TimeToNextMinute, False)

Sub TimeToNextMinute As Long
   Dim ret As Long
   ret = DateTime.Now + DateTime.TicksPerMinute
   ret = ret - (ret Mod DateTime.TicksPerMinute) 
   Log($"NextRunTime: ${ret}  Date: ${DateTime.Date(ret)}  Time: ${DateTime.Time(ret)}"$)
   Return ret
End Sub
 
Last edited:
Upvote 0

mangojack

Expert
Licensed User
Longtime User
Note that the only correct way to do date/time calculations that include days is with DateUtils.

as suggested above ..
the above works well .. although I think it would be suggested to use DateUtils for above time calcs ..
 
Upvote 0

Alvsky

Member
Licensed User
Longtime User
regarding one minute update, I was just concerned that widget will enter the loop after 1 day also but it works fine, as you said it will :)

I have another problem though, I need my widget to be clickable, i.e. to open the main app when it is clicked.
B4X:
Sub wIkona_Click
    StartActivity(Main)
End Sub

It worked fine, but now it just starts the service and ends it immediately (probably because StopService("")).
Here is the Log
B4X:
** Service (katkal_widget) Create **
** Service (katkal_widget) Start **
Next Run Time: Date:09-03-2016 Time:00:01
** Service (katkal_widget) Destroy **

Any suggestions how can I solve this.
 
Upvote 0

mangojack

Expert
Licensed User
Longtime User
You can remove the StopService call .. but I dont think thats the problem

Your Click event should start the activity .. One thing I did notice , The widget view_Click event would not work occasionally after changes during debugging.
I found Uninstalling app/widget from device , then running debug in release mode resolved issue.

Have you read Home Screen Widgtes part II

It might be wise to start new thread for any problems you have after a good search and read.
 
Last edited:
Upvote 0

Alvsky

Member
Licensed User
Longtime User
Solved the last issue. This was commented :
B4X:
    If rv.HandleWidgetEvents(StartingIntent) = False Then
        rv_RequestUpdate
    End If

After activating this, all works fine.


I did read the Tutorial and after reading it I started to make my own widget but some things I just don't seem to get so easily :)

So I am grateful for help and time you guys provide to guys like me

Thanks once more
 
Upvote 0
Top