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: 
mkdir1995
Level 7

Conditionally displaying a different scene

Using the Simple_Grid_With_Details_and_Video example, I want to conditionally display a screen on the click of an item in the home grid. If an item matches my criteria for a detail screen, the conditional for displaying a detail screen works!  But now I need to figure out the other part - if an item matches the criteria for a playlist, I want to be able to click on the item and show a different screen with a grid of items INSTEAD of a details screen. I am doing all of this inside of the OnRowItemSelected() function in HomeScene.brs.  


Function OnRowItemSelected()
  m.currentItem = m.gridScreen.focusedContent.item

  if m.currentItem.type_name = "video" 
    m.gridScreen.visible = "false"
    m.detailsScreen.content = m.gridScreen.focusedContent
    m.detailsScreen.setFocus(true)
    m.detailsScreen.visible = "true"    
  else
    getCategoryContent()
    m.gridScreen.visible = "false"
  end if 


getCategoryContent() :

function getCategoryContent()
  print "I am inside of getCategoryContent()"

  m.categoryItem = queryCategoryItems( m.currentItem )
  print "getting the items within this category item....." 

end function


...however, when calling this queryCategoryItems function, I keep getting an error that says "BRIGHTSCRIPT: ERROR: roUrlTransfer: creating MAIN|TASK-only component failed on RENDER thread". I don’t know why this works fine in the Main.brs but not within the HomeScene.brs, even though i am including all the necessary request/response files in a script tag in the homescreen.brs file. The error is in an outside file that handles the requests (line 40 below).


039:  function getRequestMessagePort() as Object
040:*   return m.transport.getMessagePort()
041:  end function
Interface not a member of BrightScript Component (runtime error &hf3) in pkg:/source/request.brs


If there's a better way to do this, I'd love to know. I wanted to keep this in the main.brs file, but then I came across more issues when tying it to a scene and it was proving to be far more difficult than just having it done upon the press of an item. Thanks!!
0 Kudos
9 Replies
destruk
Level 10

Re: Conditionally displaying a different scene

Main.brs is executed before Scenegraph starts.  If you are requiring rourltransfer while Scenegraph is active then it must be done within a task thread.
0 Kudos
mkdir1995
Level 7

Re: Conditionally displaying a different scene

"destruk" wrote:
Main.brs is executed before Scenegraph starts.  If you are requiring rourltransfer while Scenegraph is active then it must be done within a task thread.

And how does the task thread connect to the conditional? Is it a separate scene? Separate .brs file? Does the task have to be on the same scene of the playlist, or at the main scene? I have read the documentation on Tasks but it's extremely confusing to me; the tutorials are much easier to follow, but I don't see Tasks anywhere in the simple grid example. 
Thank you  Smiley Very Happy
0 Kudos
destruk
Level 10

Re: Conditionally displaying a different scene

Proper flow charting would help with your coding design.
A) You can download all the xml you like in the Main thread, before Scenegraph executes
or
B) You can download the xml in the main thread before scenegraph executes, do your branch in the main thread, execute scenegraph, when the user exits that it goes back to the main threead and downloads again and starts scenegraph the other way you want
or
C) You can simply start up scenegraph immediately in the main thread without downloading anything, when your first screen is visible in scenegraph download in a task node and parse the xml and create the display in scenegraph as required for the branch

A simple task node configuration -
<?xml version="1.0" encoding="utf-8" ?>
<!--********** Copyright 2015 Roku Corp.  All Rights Reserved. **********-->

<component name="taskdownloaddata" extends="Task">
<interface>
<field id="uri" type="uri" />
<field id="content" type="node" />
</interface>
<script type="text/brightscript" uri="pkg:/components/screens/TaskDownloadData/taskdownloaddata.brs"/>
</component>



And the brs
Sub init()
m.top.FunctionName="getNewData"
End Sub

Sub getNewData()
readInternet=createObject("roUrlTransfer")
readInternet.setUrl(m.top.uri)
source=readInternet.GetToString()
If Len(Source)>10 'Something is here to parse
content=createObject("roSGNode","ContentNode")
contentxml=createObject("roXMLElement")
contentxml=parseJSON(source)

row=CreateObject("RoSGNode","ContentNode")
row.title=contentxml["category name"]
If contentxml.entry.count()>0
cd=contentxml.entry[0]
y=cd.count()-1
For z=0 To y
item=CreateObject("RoSGNode","ContentNode")
item.SetFields(cd[z])
row.AppendChild(item)
Next
End If
content.AppendChild(row)
m.top.content=content
End If
End Sub



Basically you are just creating a task node, moving the code you would have used in main to download the xml into the task node, and setting up a way to stick in a URL and grab out the retrieved data back into the render thread where you display it.
0 Kudos
destruk
Level 10

Re: Conditionally displaying a different scene

btw although I state xml, notice I used parseJSON.  If you are grabbing xml it should be parseXML.  JSON I've found to be slightly faster so I use that for the extra minimal speed I see on my devices here over the lan.  And if your tag names do not exactly match the names of metadata in a content node then you'll need to add custom fields to the content node so they will match, or read your alternate names and copy the data into the valid fields of a content node.  It is a lot faster during execution to simply change the source tag names to match what roku requires and use setfields.
0 Kudos
mkdir1995
Level 7

Re: Conditionally displaying a different scene

@destruk, thank you so much for the thorough examples and explanations! 

I'm also using JSON Smiley Happy and I'm able to retrieve all of the info I need within the main thread - I just had some trouble with applying it to a new scene conditionally,  because of how things were scoped. I might be mistaken, but I assumed that if I can retrieve the content I need in the main thread, I could store it and set up the new scene without needing a Task? 
0 Kudos
destruk
Level 10

Re: Conditionally displaying a different scene

Yes,
If the problem is the scope of the data you can either pass it into scenegraph (which I think you do already) or you could put it into the global namespace.
0 Kudos
mkdir1995
Level 7

Re: Conditionally displaying a different scene

"destruk" wrote:
Yes,
If the problem is the scope of the data you can either pass it into scenegraph (which I think you do already) or you could put it into the global namespace.

Oooh - thats good to hear. I'm going to try doing it without a Task node one more time, then if all else fails, I'll attempt the examples you provided. THANK YOU! Smiley Happy I really appreciate it 
0 Kudos
mkdir1995
Level 7

Re: Conditionally displaying a different scene

So I've stuck with the idea of leaving all of my JSON retrieval in the main thread. It's much easier than having to separate them all into tasks. I've actually successfully entered a separate screen conditionally! Wooooo. Except... the RowList doesn't show. When I log DetailsScreen.content I get a roSGNode, but when I log the content of a categoryScreen, I get roInvalid. Any idea why this is happening? I can assume I'm somehow not setting the content correctly, but I'm not really sure where I went wrong. 

When creating a NEW RowList for the content of CategoryScreen, as well as appending all my rowItems, I'm doing it in a separate function in the main thread (under the main function that sets the home grid content). SO I'm wondering if this is the correct way or not; maybe it needs to be put into a separate .brs file connected to the CategoryScreen XML? This is what I'll try next.

As always, any help is verrry appreciated!!
0 Kudos

Re: Conditionally displaying a different scene

"mkdir1995" wrote:
So I've stuck with the idea of leaving all of my JSON retrieval in the main thread. It's much easier than having to separate them all into tasks. I've actually successfully entered a separate screen conditionally! Wooooo. Except... the RowList doesn't show. When I log DetailsScreen.content I get a roSGNode, but when I log the content of a categoryScreen, I get roInvalid. Any idea why this is happening? I can assume I'm somehow not setting the content correctly, but I'm not really sure where I went wrong. 

When creating a NEW RowList for the content of CategoryScreen, as well as appending all my rowItems, I'm doing it in a separate function in the main thread (under the main function that sets the home grid content). SO I'm wondering if this is the correct way or not; maybe it needs to be put into a separate .brs file connected to the CategoryScreen XML? This is what I'll try next.

As always, any help is verrry appreciated!!


What did you end up doing? I'm trying to accomplish something similar. Using the Hero-Grid-Screen example. I'm trying to set up on selecting an item on RowList when it has Focus, upon button press ok, instead of loading DetailsScreen I want to be able to show another GridScreen. Basically selecting a series poster from the RowList and then the GridScreen showing all the episodes. I think I'm going to need a separate .brs and .xml along with parsing another xml.rss feed to populate the new screen. Hope you got yours to work!
If were easy, everyone would do it. Problems are opportunities to learn, but there is a lot of banging your head against the wall to get there.
0 Kudos