Android Question How to communicate with a CustomView

achapman

Member
Licensed User
Longtime User
Hi everyone, I'm playing with creating a CustomView for the first time and I can't figure out how to communicate with it reliably.

The key thing I want to do at the moment is, at any time I want, pass a timestamp to my view and then have the view update the date field within it.

I tried creating a public "SetDate" method in the customview, which crashes out when I run it.

Here's the relevant parts of what I did:

CDDatePicker
(My custom view)

B4X:
Sub Class_Globals
    Private EventName As String 'ignore
    Private CallBack As Object 'ignore
    Private Canvas As Panel
    Private LblDate As Label
    Private IVDownArrow As ImageView
    Private DateFormatStr As String
  
    Private LblMonth As Label
    Private IVLeftArrowMonth As ImageView
    Private IVRightArrowMonth As ImageView
  
    Private LblDay As Label
    Private IVLeftArrowDay As ImageView
    Private IVRightArrowDay As ImageView  
  
    Private CurrentStamp As Long
    Private Unfolded As Boolean = False
    Private InitialHeight As Int
    Private UnfoldedHeight As Int
    Public CurrentHeight As Int
  
    Dim ControlHeight As Int = 30dip
    Dim ControlGapV As Int = 10dip  
    Dim MyTimer As Timer
End Sub

Public Sub DesignerCreateView (Base As Panel, Lbl As Label, Props As Map)
    Canvas = Base
    Canvas.Color = Props.Get("BackgroundColor")
  
    Dim CurrentY As Int = 0
    DateFormatStr = CDDatePickerStorage.DateFormat
    DateTime.DateFormat = DateFormatStr
  
    CurrentStamp = DateTime.Now

    ' Add Label to Show Current Date
    LblDate.Initialize("LblDate")
    LblDate.TextSize = CDDatePickerStorage.FontSize
    LblDate.TextColor = Props.Get("ControlFontColor")
    LblDate.Text = DateTime.Date(CurrentStamp)
    LblDate.Gravity = Gravity.CENTER
  
    Canvas.AddView(LblDate, 0, 0, Canvas.Width - 35dip, ControlHeight)
  
    InitialHeight = ControlHeight
    Canvas.Height = InitialHeight
  
    IVDownArrow.Initialize("IVImageView")
    Canvas.AddView(IVDownArrow, Canvas.Width - 30dip, 0, ControlHeight, ControlHeight)
    RenderSVG(IVDownArrow, "i-down-arrow.svg", 1)
  
    CurrentY = CurrentY + ControlHeight + ControlGapV
      
    ' DAY
    ' Add Label to Show Current Date
    LblDay.Initialize("LblDay")
    LblDay.Text = GetDayString(CurrentStamp)
    LblDay.TextSize = CDDatePickerStorage.FontSize
    LblDay.Gravity = Gravity.CENTER
    LblDay.TextColor = Props.Get("ControlFontColor")
  
    Canvas.AddView(LblDay, 35dip, CurrentY, Canvas.Width - 70dip, ControlHeight)  
  
    IVLeftArrowDay.Initialize("IVLeftArrowDay")
    Canvas.AddView(IVLeftArrowDay, 0, CurrentY, ControlHeight, ControlHeight)
    RenderSVG(IVLeftArrowDay, "i-left-arrow.svg", 1)
      
    IVRightArrowDay.Initialize("IVRightArrowDay")
    Canvas.AddView(IVRightArrowDay, Canvas.Width - 30dip, CurrentY, ControlHeight, ControlHeight)
    RenderSVG(IVRightArrowDay, "i-right-arrow.svg", 1)  
  
    CurrentY = CurrentY + ControlHeight + ControlGapV
  
    ' MONTH
    ' Add Label to Show Current Date
    LblMonth.Initialize("LblMonth")
    LblMonth.Text = GetMonthName(DateTime.GetMonth(CurrentStamp))
    LblMonth.TextSize = CDDatePickerStorage.FontSize
    LblMonth.TextColor = Props.Get("ControlFontColor")
  
    LblMonth.Gravity = Gravity.CENTER
  
    Canvas.AddView(LblMonth, 35dip, CurrentY, Canvas.Width - 70dip, ControlHeight)  
  
    IVLeftArrowMonth.Initialize("IVLeftArrowMonth")
    Canvas.AddView(IVLeftArrowMonth, 0, CurrentY, ControlHeight, ControlHeight)
    RenderSVG(IVLeftArrowMonth, "i-left-arrow.svg", 1)
      
    IVRightArrowMonth.Initialize("IVRightArrowMonth")
    Canvas.AddView(IVRightArrowMonth, Canvas.Width - 30dip, CurrentY, ControlHeight, ControlHeight)
    RenderSVG(IVRightArrowMonth, "i-right-arrow.svg", 1)
  
    CurrentY = CurrentY + ControlHeight + ControlGapV  
  
    UnfoldedHeight = CurrentY  
    CDDatePickerStorage.PickerHeight = UnfoldedHeight  
  
    If((Props.ContainsKey("ControlFont")) And (Props.Get("ControlFont") <> "")) Then
        Try
            Dim Const StandardFont As Typeface = Typeface.CreateNew(Typeface.LoadFromAssets(Props.Get("ControlFont")), Typeface.STYLE_BOLD)              
          
            LblDate.Typeface = StandardFont
            LblMonth.Typeface = StandardFont
            LblDay.Typeface = StandardFont          
        Catch
            Log(LastException)
        End Try
    End If  
  
    MyTimer.Initialize("MyTimer", 500)  
    MyTimer.Enabled = True
End Sub

Public Sub UpdateDisplay
    LblMonth.Text = GetMonthName(DateTime.GetMonth(CurrentStamp))
    LblDay.Text = GetDayString(CurrentStamp)
    Log("Setting to stamp: " & DateTime.Date(CurrentStamp))
  
    DateTime.DateFormat = DateFormatStr
    LblDate.Text = DateTime.Date(CurrentStamp)
  
    If(SubExists(CallBack, EventName & "_DateChanged")) Then
        CallSub2(CallBack, EventName & "_DateChanged", CurrentStamp)
    End If
End Sub

Public Sub SetDate(Ticks As Long)
    CurrentStamp = Ticks
    UpdateDisplay  
End Sub


Then in my main activity, I have a button that when clicked, calls:

B4X:
Sub BtnNow_Click
    DatePicker.SetDate(DateTime.Now)
End Sub

The SetDate function is invoked, however when the UpdateDisplay function within the CustomView is called, LblMonth is null, and pretty much everything in there is null.

Why is LblMonth null? And what is the correct way of working with custom views?

The error in full is:

** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Error occurred on line: 168 (CDDatePicker)
java.lang.NullPointerException: expected receiver of type anywheresoftware.b4a.objects.TextViewWrapper, but got null
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:703)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:337)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:247)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:134)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:157)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:78)
at android.view.View.performClick(View.java:4240)
at android.view.View$PerformClick.run(View.java:17721)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)

Any ideas?
 
Last edited:

achapman

Member
Licensed User
Longtime User
Thanks Erel, I've added the code tags in. The question really is, if you have say a label in a custom view, and you want to update that label outside the custom view (i.e. from a button click in the main activity), how do you do it? If you look at the SetDate function above you'll see how I was trying to do it, but that's when the null pointer exception occurred. Thoughts?
 
Upvote 0

achapman

Member
Licensed User
Longtime User
Here you go - thanks Erel. Try clicking the left "Now" button. You'll see the exception happen.
 

Attachments

  • CDDatePicker.zip
    206.7 KB · Views: 219
Upvote 0
Top