Overiew of how (back) navigation works in CN1

140 views
Skip to first unread message

sidiabale

unread,
Feb 21, 2015, 5:43:37 PM2/21/15
to codenameone...@googlegroups.com
Hi,

I'm new to CN1 and trying to understand how (back) navigation works in CN1. So far, I've seen several navigation-related posts but I still miss an overview. I also see a bunch of methods like back(), showBack(), setBackDestination(), showForm() that all relate to navigation but the API documentation isn't crystal clear as to which should be used when.

I would like detailed answers to at least the following questions. How can one properly implement navigation for:
  1. A GUI builder-based app with complex navigation? So something like A --> B --> C ---> D --->(back) ---> B.
  2. A GUI builder-based app that uses forms as 'templates'? See the concrete question below for what I mean by 'templates'.
  3. An app that includes both GUI Builder forms and hand-coded forms? As far as I can see from the forum, there are some nuances related to this.
  4. An app that has a splash screen? In one of the threads, I think I saw something about splash screens being a bit of a special case.
  5. An app with GUI builder and/or handcoded forms that has a custom navigation management component? So I want to have my own class that manually decides what back does on every form without any help from the CN1 framework.
PS: It would be great if the Developer Guide can be extended with a section dedicated to a sufficiently detailed explanation of navigation in CN1. Going by the number of threads I've seen here on this topic, I think it will also save the CN1 team useful time currently spent on answering nearly duplicate questions.

======= Concrete Example =======
If you are experiencing an issue please mention the full platform your issue applies to:
IDE: NetBeans
Simulator + Android device

I have a simple application consisting of two forms, say "Main" and "Question". The "Main" form contains a "Start" button that triggers a series of questions. The "Question" form is basically a re-usable template with a content section and a "Previous" and "Next" button. Navigation using the previous and next buttons works fine. However, when I use the Back button, I get strange behavior. 

More concretely, given the following navigation stack

[{}, {$title=Test, $focus=start, $name=Main}, {$title=Test, $focus=next, $name=Question}, {$title=Test, $focus=next, $name=Question}, {$title=Test, $focus=next, $name=Question} (so Main --> Question --> Question --> Question)
  • The previous button takes me to the desired state of [{}, {$title=Test, $focus=start, $name=Main}, {$title=Test, $focus=next, $name=Question}, {$title=Test, $focus=next, $name=Question}] (i.e., Main --> Question --> Question)
  • However, the Back button takes me directly to Main without updating the navigation stack. I don't seem to find the correct way to make the Back button behavior match that of the Previous button in the Question form. What am I doing wrong?
The relevant code from the previous and next button action handlers in the StateMachine is as follows:

@Override
protected void onQuestion_PreviousAction(Component c, ActionEvent event) {
   
if (currentQuestion == null || model.getPreviousQuestion(currentQuestion) == null) {
        showForm
("Main", null);
   
} else {
        currentQuestion
= model.getPreviousQuestion(currentQuestion);
        setBackDestination
("Question");
        back
();
   
}
}

@Override
protected void onQuestion_NextAction(Component c, ActionEvent event) {
   
if (model.getNextQuestion(currentQuestion) == null) {
        showForm
("Main", null);
   
} else {
        currentQuestion
= model.getNextQuestion(currentQuestion);
        showForm
("Question", null);
   
}
}

Shai Almog

unread,
Feb 21, 2015, 11:49:02 PM2/21/15
to codenameone...@googlegroups.com
Hi,
back() just pops the navigation stack returning you to the previous form in the GUI builder.
showBack() is a method of form, its unrelated to navigation since its unaware of the existence of the stack and just shows the given form with back transition.
setBackDestination() pops the stack to the given name without actually navigating to that form. This allows back() to skip some forms.
showForm just navigates to the given form, if the command given in the second argument is a back command it will do that as a back animation (e.g. slide will run in the opposite direction).

As to your example I'm not sure why you needed the setBackDestination call there?

Chidiebere Okwudire

unread,
Feb 22, 2015, 5:24:11 AM2/22/15
to codenameone...@googlegroups.com
Hi Shai,

Thanks for your prompt response although you didn't quite answer my questions.

I added the setBackDestination() call in a bid to solve the problem that the Back button 'ignores' the navigation stack and takes me back to the Main form. However, that doesn't work.

Given the example I sketched, how can I get the desired behavior?

Please don't forget the other questions as well. I'd rather understand how things work than have to ask yet another question for each problem I encounter with navigation.

Thanks
--
You received this message because you are subscribed to a topic in the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/codenameone-discussions/kY9jUfEo8k0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to codenameone-discu...@googlegroups.com.
Visit this group at http://groups.google.com/group/codenameone-discussions.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/5609450c-a169-4820-be55-36073dd3593c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Shai Almog

unread,
Feb 22, 2015, 9:56:05 AM2/22/15
to codenameone...@googlegroups.com
Hi,
I see the problem. Since both are the same form the logic for navigation assumes you want to go back to the actual "previous" form which is common. Just override:
protected boolean isSameBackDestination(Container source, Container destination)

And define it to return false for the case of that form.
Message has been deleted
Message has been deleted

sidiabale

unread,
Feb 24, 2015, 1:27:44 PM2/24/15
to codenameone...@googlegroups.com
Hi Shai,

Your suggestion helped but hasn't completely solved the problem.

After overriding the method, I see that the navigation stack gets updated and navigation seems to occur. The problem now is that I keep on getting the same data. So say I have Main --> Q1 --> Q2 --> Q3 where all Q's are instances of the same Question form. On navigating back, I get Q3 --> Q3 --> Q3 --> Main. What I'm missing is an event to signal back navigation so that I can update my internal state and load the right content. Does such a callback exist in CN1? If not, how can I solve this new problem?

Here's the implementation of isSameBackDestination()

@Override
protected boolean isSameBackDestination(Container source, Container destination) {
    final Form current = Display.getInstance().getCurrent(); 
    if (current != null && "Question".equals(current.getName())) {
        return false;
    }
    return super.isSameBackDestination(source, destination);
}

Shai Almog

unread,
Feb 25, 2015, 1:42:38 AM2/25/15
to codenameone...@googlegroups.com
Hi,
before*Show for the given form should be invoked with every back/forward navigation. Isn't it happening?

sidiabale

unread,
Feb 25, 2015, 4:55:50 AM2/25/15
to codenameone...@googlegroups.com
Hi Shai,

That's true but how does that help with the problem of distinguishing back and forward navigation? I need to do different things for each case to load the right data. Any other ideas or is this kind of navigation behavior not feasible in codename one?
Message has been deleted

sidiabale

unread,
Feb 25, 2015, 5:35:58 AM2/25/15
to codenameone...@googlegroups.com
Btw,

I also thought of using the f.putClientProperty() method to store the question id but when I try retrieving it in the beforeQuestion() method, f.getClientProperty() always returns null so that does not help. Is this a bug? The same behavior was also reported over a year ago in this post.

Shai Almog

unread,
Feb 25, 2015, 11:43:25 AM2/25/15
to codenameone...@googlegroups.com
If you have state beyond this just store it in the state machine class variables and use that state in the before*show method.

sidiabale

unread,
Feb 26, 2015, 2:01:41 AM2/26/15
to codenameone...@googlegroups.com
Hi Shai,

Could it be that my question is unclear or that you're skimming over the details? I'm not storing state in the form because I want to (my state is already stored in the state machine). It's basically a workaround I proposed because of the problem I'm facing with back navigation on multiple instance of a GUI builder form.

You had suggested that I override the isSameDestination() method which I did but now I observe the situation stated below. My question has basically been: How do I solve this? My proposal to store the question ID in the form was just an idea of a possible solution but like I said the putClientProperty() and getClientProperty() seems to be broken so that doesn't help me.

Please look again at the problem mentioned below (and more of the thread above if you miss the context) and kindly let me know if there's a way to solve this problem in CodenameOne. Thanks


On Tuesday, 24 February 2015 19:27:44 UTC+1, sidiabale wrote:
Hi Shai,

Your suggestion helped but hasn't completely solved the problem.

After overriding the method, I see that the navigation stack gets updated and navigation seems to occur. The problem now is that I keep on getting the same data. So say I have Main --> Q1 --> Q2 --> Q3 where all Q's are instances of the same Question form. On navigating back, I get Q3 --> Q3 --> Q3 --> Main. How can I solve this new problem?

Shai Almog

unread,
Feb 26, 2015, 11:44:42 AM2/26/15
to codenameone...@googlegroups.com
Hi,
storing in the form won't work since the form is transient. You need to store the state in the class.
The reason I can't solve your problem for you is that I don't have your business logic.

sidiabale

unread,
Feb 28, 2015, 7:45:06 PM2/28/15
to codenameone...@googlegroups.com
Hi,

I found the callback I was looking for:

onBackNavigation()

There I can update the question form as desired. Thanks for your assistance all the same.

sidiabale

unread,
Feb 28, 2015, 8:06:55 PM2/28/15
to codenameone...@googlegroups.com
As per the status of my other questions, can you please provide answers to the ones that have not been covered in this thread so far (see below)?

I would like detailed answers to at least the following questions. How can one properly implement navigation for:
  1. A GUI builder-based app with complex navigation? So something like A --> B --> C ---> D ---> (back) ---> B.
  1. Possible: Use setBackDestination("B") before back navigation in form D
  1. A GUI builder-based app that uses forms as 'templates'? See the concrete question below for what I mean by 'templates'.
  1. Possible: You'll need to override isSameBackDestination() and possibly onBackNavigation() to update state.
  1. An app that includes both GUI Builder forms and hand-coded forms? As far as I can see from the forum, there are some nuances related to this.
  1. Not sure; haven't tried out yet
  1. An app that has a splash screen? In one of the threads, I think I saw something about splash screens being a bit of a special case.
  1. Not sure; haven't tried out yet
  1. An app with GUI builder and/or handcoded forms that has a custom navigation management component? So I want to have my own class that manually decides what back does on every form without any help from the CN1 framework.
  1. Not sure; haven't tried out yet

Shai Almog

unread,
Feb 28, 2015, 11:55:15 PM2/28/15
to codenameone...@googlegroups.com
3. Navigation is a GUI builder feature and implemented there. If you invoke "show()" you will be leaving the navigation stack behind which will have no idea you moved to another form.
In handcoded apps you usually keep a reference to the previous form and use showBack() to go back there.

4. http://www.codenameone.com/blog/the-7-screenshots-of-ios
Splash screens can be implemented using the next form property in the GUI builder. So you set it in the splash and it implicitly moves to the next form.

5. Just disable navigation and do whatever you want. This is the only option for handcoded apps.

Chidiebere Okwudire

unread,
Mar 1, 2015, 4:25:43 AM3/1/15
to codenameone...@googlegroups.com
Thanks for the clarification! 

Cheers
--
You received this message because you are subscribed to a topic in the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/codenameone-discussions/kY9jUfEo8k0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to codenameone-discu...@googlegroups.com.
Visit this group at http://groups.google.com/group/codenameone-discussions.
Reply all
Reply to author
Forward
0 new messages