Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
debdattabasu committed Sep 13, 2014
0 parents commit 0251720
Show file tree
Hide file tree
Showing 116 changed files with 6,520 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#built application files
*.apk
*.ap_

# files for the dex VM
*.dex

# Java class files
*.class

# generated files
bin/
gen/

# Local configuration file (sdk path, etc)
local.properties

# Windows thumbnail db
Thumbs.db

# OSX files
.DS_Store


# Android Studio
.idea
.gradle
*.iml
gradlew
gradlew.bat
gradle.properties
build/
28 changes: 28 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Project RoboMVVM(https://github.com/debdattabasu/RoboMVVM)
Copyright (c) 2014, Debdatta Basu
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
196 changes: 196 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
RoboMVVM - MVVM Framework For Android
=====================================

RoboMVVM is an open source library that facilitates the use of the [MVVM](http:https://en.wikipedia.org/wiki/Model_View_ViewModel) pattern in Android apps. Those familiar with the .NET world can appreciate the ability of the MVVM pattern to simplify building, testing and refactoring UI heavy applications. The MVVM pattern heavily utilizes [Data Binding](http:https://en.wikipedia.org/wiki/Data_binding), the ability to make property changes in one component reflect in its observers. This requires a mechanism to notify observers of property changes in a component. The MVVM pattern also allows Action Binding, which is the binding of events in a component to actions in its observers.


RoboMVVM will save countless hours of your time by providing you with the tools you need to quickly setup bindings between your views and your data models. At the core of the RoboMVVM library is the Component class, which is a container for events, properties, and actions. The Binding class is used to bind properties to properties and events to actions between a source component and a target component. Bindings can be one way or two way as specified by a BindMode, and a ValueConverter is used to convert between source and target properties

Because Android does not have a standard property change and event notification system, an MVVM library must wrap Android classes in its own adapters to allow for Data and Action binding. RoboMVVM provides the ComponentAdapter base class for this purpose. It also provides many ComponentAdapter subclasses that act as adapters for most commonly used Android classes.

Please refer to the [Javadoc](http:https://debdattabasu.github.io/RoboMVVM/javadoc/) for more information.


TextSync - An Enlightening Use Case
===================================

Android code is notoriously ugly to write and maintain. For example, consider the code we need to write to keep the text property of two [EditText](http:https://developer.android.com/reference/android/widget/EditText.html)s in sync. You can also find this sample in the repository[here]().

```java
public class MainActivity extends Activity {

EditText text0, text1;

private final TextWatcher watcher0 = new TextWatcher() {

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

text1.removeTextChangedListener(watcher1);
text1.setText(text0.getText().toString());
text1.addTextChangedListener(watcher1);
}

@Override
public void afterTextChanged(Editable s) {

}
};

private final TextWatcher watcher1 = new TextWatcher() {

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
text0.removeTextChangedListener(watcher0);
text0.setText(text1.getText().toString());
text0.addTextChangedListener(watcher0);
}

@Override
public void afterTextChanged(Editable s) {

}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text0 = (EditText) findViewById(R.id.edit_text_0);
text1 = (EditText) findViewById(R.id.edit_text_1);

text0.addTextChangedListener(watcher0);
text1.addTextChangedListener(watcher1);
}
}
```

That's an awful lot of code for such a simple task. You will notice that the actual business logic is only a handful of lines. The rest of the code is just boilerplate to conform to how android works. This is repetitive code that must be written a countess number times in every android project, and in many cases, this obfuscates the real intent of the code.

Now consider the same example with data binding in RoboMVVM. You can also find this sample in the repository[here]().

```java
public class MainActivity extends Activity {

@SetLayout(R.layout.activity_main)
public static class MainActivityViewModel extends ViewModel {

public MainActivityViewModel(Context context) {
super(context);
}

private String text = "Hello World!";

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
raisePropertyChangeEvent("text");
}

@Override
protected void bind() {
bindProperty("text", R.id.edit_text_0, "text", BindMode.BIDIRECTIONAL);
bindProperty("text", R.id.edit_text_1, "text", BindMode.BIDIRECTIONAL);
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MainActivityViewModel(this).getView());
}
}
```

It is immediately evident that the code is a lot shorter. What is more important, however, is that the code is now almost entirely business logic. The goal of RoboMVVM is to make your code about your actual data models and business logic, and less about managing Android's idiosyncrasies.


Property Binding Mechanism
===========================

When a one-way binding is set up from a source property to a target property, an EventListener is added to the source component that listens for changes to the specified property. When that property changes, The new value is retreived from the source object using the source component's getProperty function. The value is then passed through the ValueConverter, if any, and the final value is assigned to the target property using the target component's setProperty function.

The getProperty function calls a getter function with a corresponding name and return type. The setProperty function chooses a setter function in the target component based on the property name and the type of the supplied argument. For example, if the name of the property is foo, and the supplied argument is of type int, then the following function calls are attempted:

```java
void setFoo(int arg);
int getFoo();
```

The same mechanism is replicated in the other direction for two-way bindings.


Action Binding Mechanism
========================

When a binding is set up between an event in the source component to an action in the target component, an EventListener is added to the source component that listens for events of the specified type. When such an event is raised, an action is called using the target component's invokeAction function. This function calls all functions in the component whose names match the supplied action name, have a void return type, and have either a single argument of a type compatible with the supplied event arg, or no arguments.

For example, when an event of type ClickEventArg, which is derived from EventArg, is assigned to an action named doSomething, all of the following functions are called:

```java
void doSomething(ClickEventArg arg);

void doSomething(EventArg arg);

void doSomething();
```


Binding ViewModel Lists to Adapter Views
=========================================

RoboMVVM lets you create lists of arbitrary View Models and bind them to [AdapterViews](http:https://developer.android.com/reference/android/widget/AdapterView.html). This means that you can add items of vastly different look and feel to the same AdapterView. This can be used to easily create rich dynamic item lists.


Item List Sample
================

This app lets you add, remove and modify string items in a ListView. It also has an options menu where you can view a description of this app. It demonstrates the binding of View Model Collections, as well as handling of menus.


License
=======

This library uses the [3-Clause BSD License](http:https://opensource.org/licenses/BSD-3-Clause).

Project RoboMVVM(https://github.com/debdattabasu/RoboMVVM)
Copyright (c) 2014, Debdatta Basu
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 changes: 16 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.2'
}
}

allprojects {
repositories {
jcenter()
}
}
6 changes: 6 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\:https://services.gradle.org/distributions/gradle-1.12-all.zip
1 change: 1 addition & 0 deletions library/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
30 changes: 30 additions & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 18
buildToolsVersion "20.0.0"

defaultConfig {

applicationId "org.dbasu.robomvvm"
minSdkVersion 15
targetSdkVersion 20
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}


}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "org.apache.commons:commons-lang3:3.3.2"
compile "com.google.guava:guava:17.0"

}
17 changes: 17 additions & 0 deletions library/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Program Files (x86)\Android\android-studio\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http:https://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
4 changes: 4 additions & 0 deletions library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<manifest xmlns:android="http:https://schemas.android.com/apk/res/android"
package="org.dbasu.robomvvm">

</manifest>
53 changes: 53 additions & 0 deletions library/src/main/java/org/dbasu/robomvvm/annotation/SetLayout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @project RoboMVVM
* @project RoboMVVM(https://github.com/debdattabasu/RoboMVVM)
* @author Debdatta Basu
*
* @license 3-clause BSD license(http:https://opensource.org/licenses/BSD-3-Clause).
* Copyright (c) 2014, Debdatta Basu. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

package org.dbasu.robomvvm.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Attribute to set the layout resource id on a {@link org.dbasu.robomvvm.viewmodel.ViewModel} or a menu resource id on a
* {@link org.dbasu.robomvvm.viewmodel.MenuViewModel}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SetLayout {

/**
* The resource id to be set.
* @return
* The resource id.
*/
int value();
}
Loading

0 comments on commit 0251720

Please sign in to comment.