Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
kvanderwende
Level 7

roUrlTransfer on Item Select

I have downloaded samples and searched the forum and I am having trouble getting something to work.  My situation is this.  I have a database that returns JSON for a grid screen. I have functions to use roUrlTransfer to retrieve the data.  The grid is shows (podcasts).  Each show has 1 or more seasons with episodes.  I don't want to load anything until it is needed.  So the grid just displays the shows.  When one is selected I want to retrieve the seasons and episodes for that show.

My home scene works fine because I am getting the items for the grid during init.  I understand that I cannot use roUrlTranfer from a render node.  I tried following an example using Task but when the task is initialized I don't have a selected item so there is nothing to return.  I tried running the task when the item is selected but I still get an error that says "BRIGHTSCRIPT: ERROR: roUrlTransfer: creating MAIN|TASK-only component failed on RENDER thread".

XML
<component name="ShowTask" extends="Task" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
<interface>
    <field id="showIndex" type="int" value="0"/>
    <field id="showContentAA" type="assocarray"/>
</interface>
<script type="text/brightscript" uri="pkg:/components/Tasks/ShowTask.brs" />
</component>


BRS
sub init()
    m.top.functionName = "getContent"
end sub

function getContent() as void
    print "getContnent"
    if m.top.showIndex <> invalid
        m.top.showContentAA = getShowLeaves(m.top.showIndex)
    end if
end function


I am not sure how to get that to work.  I followed the Simple Task example and I only ever see it hit getContent one time.

m.showTask = CreateObject("roSGNode", "SimpleTask")
m.showTask.ObserveField("showIndex", "onIndexChanged")
m.showTask.control = "RUN"


If I set showIndex when the item is selected getContent never fires.  I think I am not fully grasping how Tasks work.
0 Kudos
4 Replies
gazer
Level 7

Re: roUrlTransfer on Item Select

The Task is a background process with a call back by the observe field.

You should be initiating the run command when the item is selected and then observe the field that has the content returned from the remote source.

Once the roUrlTransfer has returned the data set the interface field that should contain that data with the returned data and that should then trigger the observe field on the main thread from the calling script.

FYI, I have read that it is better to process the JSON on the main thread as tasks can be quite slow, though this could impact UI performance for large amounts of data.
0 Kudos
kvanderwende
Level 7

Re: roUrlTransfer on Item Select

"gazer" wrote:
The Task is a background process with a call back by the observe field.

You should be initiating the run command when the item is selected and then observe the field that has the content returned from the remote source.

Once the roUrlTransfer has returned the data set the interface field that should contain that data with the returned data and that should then trigger the observe field on the main thread from the calling script.

FYI, I have read that it is better to process the JSON on the main thread as tasks can be quite slow, though this could impact UI performance for large amounts of data.

Thank you for the feedback.  I think my problem was WHERE to run the task.  I have experimented with loading everything from main but was not sure how much data is too much.  I have 15 shows with 1-9 seasons with episodes in each season.  Currently around 900 episodes (podcasts)
I am going to attempt to get everything working with loading in main then revisit using a Task because at some point I will hit the point where loading everything up front will be a performance hit.
0 Kudos
coldrain
Level 7

Re: roUrlTransfer on Item Select

I think you should use the task like this:

Init the showTask:
m.showTask = CreateObject("roSGNode", "SimpleTask")
m.showTask.ObserveField("showContentAA", "receiveContentFromServer")


When you select an item from the grid, assign the showIndex value (don't observe this field) and call m.showTask.control = "RUN", then the task will be triggered and call your getContent function. Then the getContent function will retrieve the data from the server and assign to showContentAA which will fire the function receiveContentFromServer.

Btw, I don't load everything upfront but only category and don't see any performance hit.
0 Kudos
kvanderwende
Level 7

Re: roUrlTransfer on Item Select

"coldrain" wrote:
I think you should use the task like this:

Init the showTask:
m.showTask = CreateObject("roSGNode", "SimpleTask")
m.showTask.ObserveField("showContentAA", "receiveContentFromServer")


When you select an item from the grid, assign the showIndex value (don't observe this field) and call m.showTask.control = "RUN", then the task will be triggered and call your getContent function. Then the getContent function will retrieve the data from the server and assign to showContentAA which will fire the function receiveContentFromServer.

Btw, I don't load everything upfront but only category and don't see any performance hit.

Thank you so much.  I was observing the wrong field.  I am caching things and show loading indicator if we have to hit the server.  I had a working version of this a few years ago then things became deprecated.  That is why I have terminology like "showLeaves."
ShowTask.xml
<?xml version="1.0" encoding="UTF-8"?>
<component name="ShowTask" extends="Task" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
<interface>
    <field id="showID" type="string" alwaysNotify="true"/>
    <field id="showContentArray" type="array" alwaysNotify="true"/>
</interface>
<script type="text/brightscript" uri="pkg:/source/utils.brs" />
<script type="text/brightscript" uri="pkg:/components/Tasks/ShowTask.brs" />
</component>

ShowTask.brs
sub init()
    m.top.ShowID        = m.top.findNode("ShowID")
    m.top.showContentArray = m.top.findNode("showContentArray")
    m.top.functionName  = "executeTask"

end sub

function executeTask() as void
    if m.top.ShowID <> ""
       m.top.showContentArray = getShowLeaves(m.top.showID.ToStr())
    end if
end function

Set up task in init() of HomeScene.brs
    m.showTask = CreateObject("roSGNode", "ShowTask")
    m.showTask.ObserveField("showContentArray", "setContentFromServer")


OnRowItemSelected
Function OnRowItemSelected()
   m.gridScreen.visible = "false"
   selectedItem = m.GridScreen.focusedContent
   if m.seasonsEpisodesAA.DoesExist(selectedItem.id) then
        m.tlnShowScreen.showGridContent = m.seasonsEpisodesAA[selectedItem.id]
        ShowScreen(m.tlnShowScreen)
    else
        m.loadingIndicator.text = "Loading " + selectedItem.title + "..."
        m.loadingIndicator.control = "start"
        m.showTask.ShowID = selectedItem.id
        m.showTask.control = "RUN"
    end if

End Function


SetContentFromServer
Function setContentFromServer()
    selectedItem = m.GridScreen.focusedContent
    
    ShowRowItems = createObject("RoSGNode","ContentNode")
    for each itemAA in m.showTask.showContentArray
        row = createObject("RoSGNode","ContentNode")
        row.Title = itemAA.Title
        for each episodeAA in itemAA.Episodes
            item = createObject("RoSGNode","ContentNode")
            item.SetFields(episodeAA)
            row.appendChild(item)
        end for
        ShowRowItems.appendChild(row)
    end for
    m.seasonsEpisodesAA.AddReplace(selectedItem.id,ShowRowItems)
    
    m.seasonsEpisodesAA.AddReplace(selectedItem.id, ShowRowItems)
    m.tlnShowScreen.showGridContent = m.seasonsEpisodesAA[selectedItem.id]
    m.loadingIndicator.control = "stop"
    ShowScreen(m.tlnShowScreen)
End Function
0 Kudos