/* This file is part of Reactive Cascade which is released under The MIT License. See license.md , https://github.com/futurice/cascade and http://reactivecascade.com for details. This is open source for the common good. Please contribute improvements by pull request or contact paulirotta@gmail.com */ package com.reactivecascade.i; import android.support.annotation.NonNull; /** * An object you can bind _from_ to receive updates each time this object decides to emit them. * <p> * A common implementation is {@link com.reactivecascade.reactive.ReactiveValue} which will concurrently emit * to all its down-chain bindings each time it changes. * <p> * See also {@link IReactiveTarget} * <p> * Unlike the single-use functional (as opposed to "reactive") objects, the chain created is * suitable for multiple firings. Chains of {@link IReactiveSource} * functions are usually held with a weak reference at their head. They will automatically collapse * and clean up the binding at the same time the leaf node is garbage collected. Any firing which started * before garbage collection may lead to a from which is discarded. The same is true even if you manually * {@link com.reactivecascade.reactive.ReactiveValue#unsubscribe(String, IReactiveTarget)} so the automatic cleanup is equivalent. * Still, some people are paranoid, and others just like changing diapers and doing dirty plumbing work. * Feel free to do it manually. If you want to be controversial, do so in the {@link Object#finalize()} * method of the leaf node. It could be argued that if <code>.finalize()</code> was not called for * a long time, you didn't have a problem or leak in the first place so why worry. * <p> * If your reactive chain branches, be sure to prune just the branch of interest. A reactive chain is * said to "branch" when there are multiple <code>.subscribe()</code> statements * from a single <code>IReactiveSource</code>). The end node of a reactive chain is called the * "leaf node". The leaf node is "live" if it is strongly referenced and not free for garbage * collection. If the reactive chain branches, only that section * of the reactive function free which is no longer needed by a live leaf node will * collapse and be garbage collected to prevent useless firing. Check the logs for notification when this occurs. * <p> * If your reactive chain is strongly referenced in some other way, automatic cleanup will be defeated. * A typical way to do this is use an anonymous inner class instead of a lambda expression. Anonymous * inner classes from within the leaf node or its non-persistent child objects are not a problem. * <p> * A second even more sneaky way to defeat the automatic memory cleanup of unused reactive chains is: include * a closure reference in your lambda expressions to some object that will not be garbage collected * when the leaf nod of the reactive function chain is garbage collected. So you can freely * incorporate closures into your lambda and not manually call {@link com.reactivecascade.reactive.ReactiveValue#unsubscribe(String, IReactiveTarget)} * <em>only</em> if the closures reference objects that will not hang around past the end of the * useful life of the reactive chain. * * @param <OUT> */ public interface IReactiveSource<OUT> extends INamed { //TODO Add .subscribe(mOnFireAction..) list versions for convenience /** * Remove a down-chain branch from the reactive function tree at this node * * @param reason * @param reactiveTarget * @return <code>true</code> if the branch was found and removed */ boolean unsubscribe(@NonNull String reason, @NonNull IReactiveTarget<OUT> reactiveTarget); /** * Remove all down-chain branches from this node of the reactive function tree */ void unsubscribeAll(@NonNull String reason); /** * Attach a downstream <code>.subscribe()</code> like {@link #split(IReactiveTarget)} * as a {@link java.lang.ref.WeakReference} * for automatic down-chain {@link #unsubscribe(String, IReactiveTarget)} on garbage collect of reactive chain leaf node. * * @param reactiveTarget * @return */ IReactiveSource<OUT> split(@NonNull IReactiveTarget<OUT> reactiveTarget); //TODO revisit the use cases for a merge function in async (Not the same as RX zip) // /** // * Inject the reactive data stream like {@link #merge(IReactiveSource)} as a {@link java.lang.ref.WeakReference} // * for automatic down-chain {@link #unsubscribe(String, IReactiveTarget)} on garbage collect of reactive chain leaf node. // * // * @param upchainReactiveSource // * @param <UPCHAIN_OUT> // * @return // */ // <UPCHAIN_OUT> IReactiveSource<OUT> merge(IReactiveSource<UPCHAIN_OUT> upchainReactiveSource); /** * Add an mOnFireAction as a new branch down-chain from this node. * <p> * It will run on the same {@link com.reactivecascade.i.IThreadType} as this node and may be called synchronously. * <p> * If this <code>mOnFireAction</code> is a lambda with closure references to a surrounding {@link java.lang.Object} * context, subscribe the mOnFireAction will automatically {@link #unsubscribe(String, IReactiveTarget)} when the surrounding * context is garbage collected <em>and</em> any down-chain {@link IReactiveTarget} * is garbage collected. * * @param action * @return */ @NonNull IReactiveSource<OUT> subscribe(@NonNull IAction<OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * <p> * It will run on the same {@link com.reactivecascade.i.IThreadType} as this node and may be called synchronously. * <p> * If this <code>mOnFireAction</code> is a lambda with closure references to a surrounding {@link java.lang.Object} * context, subscribe the mOnFireAction will automatically {@link #unsubscribe(String, IReactiveTarget)} when the surrounding * context is garbage collected <em>and</em> any down-chain {@link IReactiveTarget} * is garbage collected. * * @param action * @return */ @NonNull IReactiveSource<OUT> subscribe(@NonNull IActionOne<OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * <p> * It will run on the same {@link com.reactivecascade.i.IThreadType} as this node and may be called synchronously. * <p> * If this <code>mOnFireAction</code> is a lambda with closure references to a surrounding {@link java.lang.Object} * context, subscribe the mOnFireAction will automatically {@link #unsubscribe(String, IReactiveTarget)} when the surrounding * context is garbage collected <em>and</em> any down-chain {@link IReactiveTarget} * is garbage collected. * * @param action * @param <DOWNCHAIN_OUT> * @return */ @NonNull <DOWNCHAIN_OUT> IReactiveSource<DOWNCHAIN_OUT> subscribeMap(@NonNull IActionOneR<OUT, DOWNCHAIN_OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * * @param threadType The mOnFireAction will be called asynchronously unless the this is same {@link com.reactivecascade.i.IThreadType} as this (upchain) node in the reactive function tree. * @param action * @return */ @NonNull IReactiveSource<OUT> subscribe(@NonNull IThreadType threadType, @NonNull IAction<OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * * @param threadType The mOnFireAction will be called asynchronously unless the this is same {@link com.reactivecascade.i.IThreadType} as this (upchain) node in the reactive function tree. * @param action * @return */ @NonNull IReactiveSource<OUT> subscribe(@NonNull IThreadType threadType, @NonNull IActionOne<OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * * @param action * @param <DOWNCHAIN_OUT> * @return */ @NonNull <DOWNCHAIN_OUT> IReactiveSource<DOWNCHAIN_OUT> subscribe(@NonNull IActionR<DOWNCHAIN_OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * * @param threadType * @param action * @param <DOWNCHAIN_OUT> * @return */ @NonNull <DOWNCHAIN_OUT> IReactiveSource<DOWNCHAIN_OUT> subscribe(@NonNull IThreadType threadType, @NonNull IActionR<DOWNCHAIN_OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * * @param threadType The mOnFireAction will be called asynchronously unless the this is same {@link com.reactivecascade.i.IThreadType} as this (upchain) node in the reactive function tree. * @param action * @param <DOWNCHAIN_OUT> * @return */ @NonNull <DOWNCHAIN_OUT> IReactiveSource<DOWNCHAIN_OUT> subscribeMap(@NonNull IThreadType threadType, @NonNull IActionOneR<OUT, DOWNCHAIN_OUT> action); /** * Add an mOnFireAction as a new branch down-chain from this node. * <p> * It will run on the same {@link com.reactivecascade.i.IThreadType} as this node and may be called synchronously. * * @param reactiveTarget * @return */ @NonNull IReactiveSource<OUT> subscribe(@NonNull IReactiveTarget<OUT> reactiveTarget); }