All Projects â†’ Ahmed-Adel-Ismail â†’ Binder

Ahmed-Adel-Ismail / Binder

Licence: Apache-2.0 License
An Annotation processor that allows binding two classes with each other, where the first class can listen to the updates of the second class ... ideal for MVVM and similar patterns

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Binder

Rxkprefs
🛠 A small Kotlin library to make shared preferences easy + RxJava and Coroutines support
Stars: ✭ 264 (+1157.14%)
Mutual labels:  reactive, rxjava, rx
Rxgps
Finding current location cannot be easier on Android !
Stars: ✭ 307 (+1361.9%)
Mutual labels:  reactive, rxjava, rx
Android Okgraphql
Reactive GraphQl client for Android
Stars: ✭ 64 (+204.76%)
Mutual labels:  reactive, rxjava, rx
fpEs
Functional Programming for EcmaScript(Javascript)
Stars: ✭ 40 (+90.48%)
Mutual labels:  reactive, rx
Rx.Http
A reactive way to make HTTP Request in .NET Core 🚀
Stars: ✭ 62 (+195.24%)
Mutual labels:  reactive, rx
reactify
The first and only true Functional Reactive Programming framework for Scala.
Stars: ✭ 77 (+266.67%)
Mutual labels:  reactive, rx
redrock
Typesafe, reactive redux
Stars: ✭ 14 (-33.33%)
Mutual labels:  reactive, rx
mono-reactive
open source Reactive Extensions (Rx) implementation for Mono
Stars: ✭ 65 (+209.52%)
Mutual labels:  reactive, rx
rxjava2-http
Transmit RxJava2 Flowable over http with non-blocking backpressure
Stars: ✭ 19 (-9.52%)
Mutual labels:  reactive, rxjava
Eyepetizer
An unofficial Eyepetizer(开眼视频) App built using Ijkplayer, RxJava2, Retrofit2, Dagger2, Room , DataBinding and Clean-MVVM Architecture.
Stars: ✭ 22 (+4.76%)
Mutual labels:  rxjava, mvvm
rxkotlin-jdbc
Fluent RxJava JDBC extension functions for Kotlin
Stars: ✭ 27 (+28.57%)
Mutual labels:  rxjava, rx
InterReact
Interactive Brokers reactive C# API.
Stars: ✭ 28 (+33.33%)
Mutual labels:  reactive, rx
purescript-outwatch
A functional and reactive UI framework based on Rx and VirtualDom
Stars: ✭ 33 (+57.14%)
Mutual labels:  reactive, rx
RxAnimator
An RxJava2 binding for android Animator
Stars: ✭ 80 (+280.95%)
Mutual labels:  rxjava, rx
callbag-subscribe
A callbag sink (listener) that connects an Observer a-la RxJS. 👜
Stars: ✭ 17 (-19.05%)
Mutual labels:  reactive, rx
Reactive.XAF
DevExpress XAF extension framework. 𝗹𝗶𝗻𝗸𝗲𝗱𝗶𝗻.𝗲𝘅𝗽𝗮𝗻𝗱𝗳𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸.𝗰𝗼𝗺, 𝘆𝗼𝘂𝘁𝘂𝗯𝗲.𝗲𝘅𝗽𝗮𝗻𝗱𝗳𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸.𝗰𝗼𝗺 and 𝘁𝘄𝗶𝘁𝘁𝗲𝗿 @𝗲𝘅𝗽𝗮𝗻𝗱𝗳𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸 and or simply 𝗦𝘁𝗮𝗿/𝘄𝗮𝘁𝗰𝗵 this repository and get notified from 𝗚𝗶𝘁𝗛𝘂𝗯
Stars: ✭ 60 (+185.71%)
Mutual labels:  reactive, rx
Mp3ID3Tagger
🎶🎵A macOS application to edit the ID3 tag of your mp3 files. Developed with RxSwift and RxCocoa. 🎸🎼
Stars: ✭ 17 (-19.05%)
Mutual labels:  reactive, mvvm
RxJava-Codelab
Codelab project for demonstration of RxJava features
Stars: ✭ 44 (+109.52%)
Mutual labels:  reactive, rxjava
mvcvm-swift-file-templates
Swift file templates for boosting mobile app development.
Stars: ✭ 16 (-23.81%)
Mutual labels:  reactive, mvvm
Rxjava Spring Boot Starter
RxJava Spring MVC integration
Stars: ✭ 180 (+757.14%)
Mutual labels:  reactive, rxjava

Binder

An Annotation processor that allows binding two classes with each other, where the first class can listen to the updates of the second class, like in MVVM, when we need our View to subscribe on the View-Model, so when it's variables update, we want our views to be updated as well ... although this library is not limited to MVVM, and also it allows this behavior between any two Objects, but it will be explained on an MVVM example for Android

Declaring the View-Model (Subscriptions source)

public class ViewModel extends android.arch.lifecycle.ViewModel {

	@SubscriptionName("stringLiveData")
	final MutableLiveData<String> stringLiveData = new MutableLiveData<>();

	private final Subject<Integer> intSubject = BehaviorSubject.createDefault(0);

	@SubscriptionName("intSubject")
	Subject<Integer> getIntSubject(){
	    return intSubject;
	}

	@Override
	public void onCleared(){
	    intSubject.complete();
	}

}

We need to put @SubscriptionName above the source that we need to receive it's updates, weather on the non-private variable, or on the non-private getter, as shown above ... the value passed to the annotation should be unique per class, as shown in the example, the stringLiveData variable is annotated with @SubscriptionName("stringLiveData"), and the intSubject getter is annotated with @SubscriptionName("intSubject"), the values "stringSubject" and "intSubject" are unique, if one is repeated, an error will occur during compilation

Declaring our View (Subscribers)

@SubscriptionsFactory(ViewModel.class)
public class MainActivity extends AppCompatActivity {

    private Binder<ViewModel> binder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        ViewModel viewModel = ViewModelProviders.of(this).get(ViewModel.class);
        binder = Binder.bind(this).to(viewModel);
    }


    @SubscribeTo("stringLiveData")
    void stringLiveDataSubscriber(MutableLiveData<String> liveData) {
        liveData.observe(this, text -> Log.e("MainActivity", "liveData : " + text));
    }

    @SubscribeTo("intSubject")
    Disposable intSubscriber(Subject<Integer> subject) {
        return subject.subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(v -> Log.e("MainActivity", "intSubject : " + v));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        binder.unbind();
    }
}

The first step is to tell the Annotation Processor where it can find the Subscriptions sources (our View-Model), through the annotation @SubscriptionsFactory

Then we declare our methods that will be invoked in the subscription process, like the following method :

@SubscribeTo("stringLiveData")
void stringLiveDataSubscriber(MutableLiveData<String> liveData) {
    liveData.observe(this, text -> Log.e("MainActivity", "liveData : " + text));
}

@SubscribeTo("intSubject")
Disposable intSubscriber(Subject<Integer> subject) {
    return subject.subscribeOn(Schedulers.computation())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(v -> Log.e("MainActivity", "intSubject : " + v));
}

in our annotation @SubscribeTo, we pass the key that we declared in our View-Model's @SubscriptionName annotation, in this example we subscribe to the Subject intSubject that was declared in our View-Model

after the annotation step, our method should be :

- not private
- it can return an RxJava 2 Disposable to be able to dispose it in Binder.unbind()
- it can return any other type (or void), but in this case it's return value will be ignored and will not be affected by the call to Binder.unbind() (which is exactly what we want with LiveData in Android)
- it should expect a parameter of the same type of the declared variable in the View-Model

at the end we do the subscription process through calling the below lines :

binder = Binder.bind(this).to(viewModel);

the above code will do the binding process and return a Binder which will hold all the Disposables created by our methods, and we then can clear it in our onDestroy() by calling :

binder.unbind();

we can access the View-Model (our Subscriptions Factory) through this getter method :

binder.getSubscriptionsFactory();

Another way to initialize the binding process is to invoke the below lines :

binder = Binder.bind(this).toNewSubscriptionsFactory();

this way, the Binder will create a new instance of the Class mentioned in the @SubscriptionsFactory, but this class should have a default no-args constructor

Summing up things

Although the example is on an MVVM pattern for Android, this can be applied to any two classes, so in our example, we can then Bind our View-Model to our Inter-actor or Repositories, and so on

Gradle Dependency

Step 1. Add the JitPack repository to your build file

Add it in your root build.gradle at the end of repositories:

allprojects {
    repositories {
	    ...
	    maven { url 'https://jitpack.io' }
    }
}

Step 2. Add the dependency

dependencies {
    compile 'com.github.Ahmed-Adel-Ismail.Binder:binding:1.1.0'
    annotationProcessor 'com.github.Ahmed-Adel-Ismail.Binder:processor:1.1.0'
}

Android Support

starting from version 0.1.0, there is Support for Android as follows :

Gradle Dependency for Android

dependencies {
    compile 'com.github.Ahmed-Adel-Ismail.Binder:android:1.1.0'
    annotationProcessor 'com.github.Ahmed-Adel-Ismail.Binder:processor:1.1.0'
}

Update your Application class

@Override
public void onCreate() {
    super.onCreate();
    Binding.integrate(this);
}

Implement MVVM with Binding processor on Activities and Fragments

You do not need to handle the Binding operations any more, just declare the annotations in your Activity or android.support.v4.app.Fragment as follows :

@SubscriptionsFactory(MainViewModel.class)
public class MainActivity extends AppCompatActivity {

	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	@SubscribeTo("stringSubject")
	Disposable stringSubscriber(Subject<String> subject) {
		return subject.share()
				.subscribeOn(Schedulers.computation())
				.observeOn(AndroidSchedulers.mainThread())
				.subscribe(v -> Log.e("MainActivity", "stringSubject : " + v));
	}
}


@SubscriptionsFactory(MainViewModel.class)
public class MainFragment extends Fragment {

	@Nullable
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		super.onCreateView(inflater, container, savedInstanceState);
		return inflater.inflate(R.layout.fragment_main,container);
	}

	@SubscribeTo("stringSubject")
	Disposable stringSubscriber(Subject<String> subject) {
		return subject.share()
				.subscribeOn(Schedulers.computation())
				.observeOn(AndroidSchedulers.mainThread())
				.subscribe(v -> Log.e("MainFragment", "stringSubject : " + v));
	}
}

And declare the annotations in your ViewModel as follows :

public class MainViewModel extends android.arch.lifecycle.ViewModel {

	@SubscriptionName("stringSubject")
	final Subject<String> stringSubject = PublishSubject.create();
	
	@Override
	public void onCleared(){
		stringSubject.onComplete();
	}	
}

Since the MainViewModel extends the new Architecture components ViewModel, it will be shared accross all the Fragments and there Activity, if it does not extend the android.arch.lifecycle.ViewModel, a new instance will be created for each, which means that an instance will be created for The MainActivity, and another will be created to MainFragment

If you want the MainViewModel to not extend the android.arch.lifecycle.ViewModel, and be shared between the Activity and it's Fragments, you can annotate the class with @SharedSubscriptionFactory, as follows :

@SharedSubscriptionFactory
public class MainViewModel {

	@SubscriptionName("stringSubject")
	final Subject<String> stringSubject = PublishSubject.create();
	
	void clear(){
		stringSubject.onComplete();
	}
}

if you have a method that will clear / destroy your ViewModel, like the clear() method in the MainViewModel, you can annotate it with @OnSubscriptionsClosed, this will cause the Binder to call it when the Activity / Fragment is totally destroyed (not rotating), and if this ViewModel is shared between Activity and it's Fragments, this method will be invoked when the Activity is totally destroyed (not rotating), so our ViewModel will look like this :

public class MainViewModel {

	@SubscriptionName("stringSubject")
	final Subject<String> stringSubject = PublishSubject.create();
	
	@OnSubscriptionsClosed
	void clear(){
		stringSubject.onComplete();
	}
}

Notice that @OnSubscriptionsClosed will cause the clear() method to be invoked on any type of ViewModel, but for classes that extend android.arch.lifecycle.ViewModel, it is better to override the onCleared() method instead of using @OnSubscriptionsClosed

Pro Guard Rules

For Pro Guard, you may need to add those lines in the proguard-rules file :

# Keep default constructors inside classes
-keepclassmembers class * {
   public protected <init>(...);
   <init>(...);
}

# Keep generated classes names
-keep class **$$Subscribers { *; }

# keep classes with annotated members
-keepclasseswithmembers class * {
    @com.binding.annotations.* <methods>;
    @com.android.binding.* <methods>;
}
  • Starting from version 1.0.0, package names were changed, so if you were using older version, just remove the import statements, and import the same classes from the new packages
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].