Java fx 中的 property 探索

property的概念

一个property 通常是外部不可见的,在该类之外,我们只能通过get/set这些接口方法实现对其读与修改,我们对其实现细节(setter/getter)不关心也并不需要知道。但是通常我们(view)对它是否改变,从什么值改变成什么值十分关心(view)


the kinds of feature in property of java fx

  • 对于 fx 的property 都是可观察的(observable) 实现了observable 和observableValue接口
    observable接口
public interface observable {
    void addListener(InvalidationListener listener);
    void removeListener(InvalidationListener listener);
}

observalue接口

public abstract interface ObservableValue<T> extends Observable
{
    public abstract void addListener(ChangeListener<? super T> paramChangeListener);
    public abstract void removeListener(ChangeListener<? super T> paramChangeListener);  
    public abstract T getValue();
}

它们监听失效(invalid) 和 变化(change) 事件

  • Property 可以分为只读的以及可读写的。

        每个Property 类一般提供 : get()/set() and getValue()/setValue 针对primitive type(Read only property don't provide the set interface.)  getValue/SetValue 针对装箱类型
    

read-write property is easy to understand, you can read-write it in internal or outside.

  • 对于只读属性的认识. (read-only for outside and read-write internally)
    一个ReadOnlyXXXWrapper 类 包裹了两个类型,一个是只读的,一个是可读写的.
ReadOnlyIntegerWrapper idWrapper = new ReadOnlyIntegerWrapper(100);
ReadOnlyIntegerProperty id = idWrapper.getReadOnlyProperty();
System.out.println("idWrapper:" + idWrapper.get());
System.out.println("id:" + id.get());
// Change the value
idWrapper.set(101);
System.out.println("idWrapper:" + idWrapper.get());
System.out.println("id:" + id.get());

A Book Class 同时拥有只读属性和可读写属性的一个实体类

对于可读写属性抽象类型为XXXProperty, 实现类型通常SimpleXXXProperty.对于只读属性抽象类型通常是ReadOnlyXXXProeprty, 实现类型是ReadOnlyXXXWrapper.

public class Book {
    private final StringProperty title = new SimpleStringProperty(this,"title", "Unknown");
    private final DoubleProperty price = new SimpleDoubleProperty(this,"price", 0.0);
    private final ReadOnlyStringWrapper ISBN = new ReadOnlyStringWrapper(this,"ISBN", "Unknown");
    public Book() {}
    public Book(String title, double price, String ISBN) {
        this.title.set(title);
        this.price.set(price);
        this.ISBN.set(ISBN);
    }
    public final String getTitle() {
        return title.get();
    }
    public final void setTitle(String title) {
        this.title.set(title);
    }
    public final StringProperty titleProperty() {
        return title;
    }
    public final double getprice() {
        return price.get();
    }
    public final void setPrice(double price) {
        this.price.set(price);
    }
    public final DoubleProperty priceProperty() {
        return price;
    }
    public final String getISBN() {
        return ISBN.get();
    }
    public final ReadOnlyStringProperty ISBNProperty() {
        return ISBN.getReadOnlyProperty();
    }
} ```
***
## Lazily Instantiating Property Objects (充分优化内存,使用懒加载)
只有当需要item的weightProperty被需要的时候(weightProperty()被调用)初始化property.
``` java
public class Item {
    private DoubleProperty weight;
    private double _weight = 150;

    public double getWeight() {
        return (weight == null) ? _weight : weight.get();
    }

    public void setWeight(double newWeight) {
        if (weight == null) {
            _weight = newWeight;
        } else {
            weight.set(newWeight);
        }
    }

    public DoubleProperty weightProperty() {
        if (weight == null) {
            weight = new SimpleDoubleProperty(this, "weight", _weight);
        }
        return weight;
    }
}

Tips:
使用懒加载或者饥饿加载主要试情况而定, 一个拥有少量属性的类,并且基本你必定会用到属性,那么可以考虑饥饿加载,如果是封装的对象开销过大或者一个类里面封装了许多属性,只有少数会使用到时候可以考虑懒加载来优化内存。


Property Class Hierarchy

Paste_Image.png

最好将 property 的getter/setter 声明为final

public class Book2 {
    private final StringProperty title = new SimpleStringProperty(this,
            "title", "Unknown");
    public final StringProperty titleProperty() {
        return title;
    }
    public final String getTitle() {
        return title.get();
    }
    public final void setTitle(String title) {
        this.title.set(title);
    }
}

解析property 接口的方法

  1. bind(建立单向绑定)
    与一个来自于继承泛型T链的实现了observableValue接口的对象(一般为property)相绑定
void bind(ObservableValue<? extends T> observable);
  1. bindBidrectional(建立双向绑定)
    必须与同一类型建立双向绑定
void bindBidirectional(Property<T> other);

对property 对象添加Invalidation(失效)事件监听

main {
IntegerProperty counter = new SimpleIntegerProperty(100);
couter.set(100) // 会出发一个invalid事件
couter.set(101) // 不会触发,因为该属性已经失效
int value = couter.get() //使属性回复有效
couter.set(101) // 会再出发一个Invalid事件
// Add an invalidation listener to the counter property
counter.addListener(InvalidationTest::invalidated);
}
public static void invalidated(Observable prop) {
System.out.println("Counter is invalid.");
}

对property 对象添加change(值改变)事件监听

main {
IntegerProperty counter = new SimpleIntegerProperty(100);
// Add a change listener to the counter property
counter.set(101); // 产生changeEvent
counter.set(102); //产生changeEvent
counter.set(102); //不产生changeEvent
counter.addListener(ChangeTest::changed);
}
public static void changed(ObservableValue<? extends Number> prop,Number oldValue,Number newValue) {
System.out.print("Counter changed: ");
System.out.println("Old = " + oldValue + ", new = "+ newValue);
}

使用WeakListener来避免内存泄漏

应该在对某个property添加listener. 这样这些property中就有listener的强引用,这样这些listener就很难被回收。还有一种情况就是匿名的changlistener实现,会有外部的
对象的引用,如果外部对象包括比较占内存的view,就很容易出现这个问题。

ChangeListener<Number> cListener = create a change listener...
WeakChangeListener<Number> wListener = new WeakChangeListener(cListener);
// Add a weak change listener, assuming that counter is a property
counter.addListener(wListener);
......
cListener = null;//不需要改listener的时候

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容