java - InvalidationListener only executed in debug mode with breakpoint -


i have problem invalidationlistener. set listener on simplestringproperty. called first change of simplestringproperty. entered debug-mode , made break-point on line calls simplestringproperty::set , started working until removed break-point again.

i made short executable example program simulates modification of simplestringproperty timer. may run program 1 time without break points , 1 time having breakpoint @ line: property.set(value);

import javafx.animation.keyframe; import javafx.animation.timeline; import javafx.application.application; import javafx.beans.property.simplestringproperty; import javafx.scene.scene; import javafx.scene.layout.borderpane; import javafx.stage.stage; import javafx.util.duration;   public class main extends application {      private simplestringproperty property;     private int counter;      @override     public void start(stage stage) {         // open window avoid termination         stage.setwidth(800);         stage.setheight(600);         borderpane pane = new borderpane();         stage.setscene(new scene(pane));         stage.show();          // create simpleobjectproperty         property = new simplestringproperty();         property.addlistener(observable ->             system.out.println("new value is: " + counter)         );         counter = 0;          // create timer change 'property' every second         timeline timeline = new timeline();         keyframe keyframe = new keyframe(duration.seconds(2), event ->{             string value = "" + ++counter;             system.out.println("set property to: " + value);             property.set(value);         });         timeline.getkeyframes().add(keyframe);         timeline.setcyclecount(timeline.indefinite);         timeline.playfromstart();     }      public static void main(string[] args) {         launch(args);     } } 

output on machine (linux mint 16.04 64bit, oracle-java 1.8.0_111):

set property to: 1 new value is: 1 set property to: 2 set property to: 3 set property to: 4 ... 

please explain me:

  1. why listener not called on every change?
  2. why listener called, when set break-point?
  3. what should make working without break-points?

an observable value has 2 different states changes can trigger listeners. there value, , there state of whether or not valid.

in general, value of observable value may computed, rather stored in field. once value has been "realized" (my terminology), being computed if computed, or being retrieved if stored in field, observable value in "valid" state. if value changes (or may have changed), observable value becomes "invalid", indicating may need recomputed or looked again.

the invalidation listener triggered when observable value transitions valid state invalid one. in code, first time call

property.set(value); 

the property transitions invalid state (because retrieved value, if any, not current value).

since don't ever call property.get() (or property.getvalue()), property never gets validated. consequently, next time call property.set(value), property not transition invalid state (it in state), , listener not fired.

if replace listener code with

property.addlistener(observable ->     system.out.println("new value is: " + property.get()) ); 

this listener cause property become valid again, , listener fired each time.

the real issue using wrong kind of listener here. if want perform action every time value changes, use changelistener, not invalidationlistener:

property.addlistener((observable, oldvalue, newvalue) ->      system.out.println("new value is: " + newvalue) ); 

the observation running in debug mode breakpoint causes invalidation listener invoked every time interesting one. i'm guessing bit, suspect happening when hit breakpoint, debugger showing current values of variables. inevitably involves calling getvalue() on property (as part of tostring() implementation, perhaps), , property becomes validated.

you unlikely explicitly use invalidationlistener often. main use in bindings. consider following example:

doubleproperty x = new simpledoubleproperty(3); doubleproperty y = new simpledoubleproperty(4);  doublebinding hyp = new doublebinding() {     {         bind(x);         bind(y);     }      @override     protected double computevalue() {         system.out.println("computing distance");         return math.sqrt(x.get()*x.get() + y.get()*y.get());     } };  label hyplabel = new label(); hyplabel.textproperty().bind(hyp.asstring("hypotenuse: %f")); 

the call bind(x) in binding implementation means: when x becomes invalid, consider binding invalid. y. of course, implementation of bind uses invalidationlisteners under hood.

the point here computation of hyp's value pretty expensive. if make multiple changes x or y, hyp becomes invalid , needs recomputed when need again. since text property of label bound hyp, means label's text becomes invalid. however, need new value when label repainted in rendering pulse; overkill compute value every change of x , y.


Comments

  1. Thanks for the post, I am techno savvy. I believe you hit the nail right on the head. I am highly impressed with your blog.
    It is very nicely explained. Your article adds best knowledge to our Java Online Training from India.
    or learn thru Java Online Training from India Students.

    ReplyDelete

Post a Comment

Popular posts from this blog

java - SSE Emitter : Manage timeouts and complete() -

jquery - uncaught exception: DataTables Editor - remote hosting of code not allowed -

java - How to resolve error - package com.squareup.okhttp3 doesn't exist? -