Code Monkey home page Code Monkey logo

kratos's Introduction

Kratos

Logo

Provide basic Double Binding(Data Binding) feature on Android.

  • Using annotation to generate boilerplate code.
  • Bind view and data to help you clean your code.

Example

Data Binding

The following code demostrate that two views(EditText and TextView) bound to one single data(which in the code boundData holds the data. you can later access or change the data by using boundData.get() and boundData.set("some string"))

public class SimpleActivity extends Activity {

    @BindText({R.id.test_doublebinding_input, R.id.test_doublebinding_presenter})
    KString boundData = new KString();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);
        Kratos.bind(this);
    }
}

The presenter(TextView) will behave exactly the same as input(EditText) since they were bound to the same data:

Example

What if you want yourself a custom update behavior than the default update method when data changes? You can add custom update function to update view:

@BindText(R.id.some_edittext_id)
KString boundData = new KString(new KString.Update() {
    @Override
    public void update(@NotNull View view, @NotNull String s) {
        EditText et = (EditText)view;          //Add custom update function here.
        int start = et.getSelectionStart();    // This code is the same as: public KString boundData1 = new KString(),
        et.setText(s);                         // since this custom function is the same as the default function.
        et.setSelection(start);
    }
});

If you are using Kotlin, the code is more simple:

@KBindText("some_edittext_id")
public var boundData = KString {
    it, new ->
    it as EditText
    val position = this.selectionStart
    this.setText(new)
    this.setSelection(position)
}

Card

The concept of Card is very important in Kratos.

Basically, every view is a card, each activity is generated by one single json file, a little bit like html.

The goal is to implement each view as a card, and then easily reuse them by manipulating json file.

For example, the following activity is generated from sample.json file.

Card

You can easily handle click event by override onEventMainThread method.

Notice that

  • Kratos uses toolbar by default, so you need a NoActionBar theme in your style file, or you can just use KratosTheme.
  • When you run into non-final id problem in your library project, just use annotation start with "L", for example LBindText. But remember that you should never use both kind of annotation in the same file!

What's the benefit

  • No more fear of the changing requirements. Since activities are generated from json file, you can manipulate the layout on the fly(imagine put the json file on a server, like html on website).
  • No more redundant code. Since each view is a card, you can reuse views easily by manipulate the json file.
  • Easily create and compose custom views. All you need to do is to extend KCard, create you own KData and bind the data to the card(must write full package name, so that kratos can find your card). You can implement rather complex card using kratos depending on your skills. For example, all the view in the following activity are card:

ComplexCard

For more code see kratos-sample.

How To

Create custom card

To Create a card consists of two TextView that can also handle click even2

  1. Create a class that extends KData, for example:

    public class KText extends KData {
        public KString text1;
        public KString text2;
    }
  2. Create a class that extends KCard, use KData as its Generic, for example:

    @BindLayout(R.layout.kcard_text)  //@LBindLayout("kcard_text")
    @Binds({@Bind(id = R.id.kcard_text_text1, data = "text1"),
            @Bind(id = R.id.kcard_text_text2, data = "text2")})
    public class TextCard extends KCard<KText> {
        public TextCard(@NotNull Context context) {
           super(context);
       }
    
       @Override
       public void init() {
           setOnLinkListener();
       }
    }

    You should initailize your stuff inside init function, not constructor;

    Notice that it uses BindLayout to specify its layout:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:padding="16dp">
    
        <TextView
            android:id="@+id/kcard_text_text1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="#888888"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/kcard_text_text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="#888888"
            android:textSize="14sp" />
    </LinearLayout>
  3. Create a Activity that extends KCardActivity:

    public class CardSampleActivity extends KCardActivity {
    
        private void showToast(String text) {
            Toast.makeText(CardSampleActivity.this, text, Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onEventMainThread(@NotNull KOnClickEvent<KData> event) {
            super.onEventMainThread(event);
            switch (event.id) {
                case "textCard1":
                    showToast("Handle click on textCard1!");
                    break;
            }
        }
    }

    Notice that it handles click event by overriding onEventMainThread method.

  4. Pass your json layout to your activity:

    {
      "header": {
        "title": "Card Sample"
      },
      "body": [
        {
          "data": {
            "text": "this is text1",
            "text": "this is text2"
          },
          "type": "me.ele.kratos_sample.TextCard",
          "id": "textCard1",
          "style": {
            "margin_top": 20,
            "margin_left": 20,
            "margin_right": 20
          }
        }
      ]
    }  

    Notice that it uses full package name in type property.

    You can use kratos' util function to pass json file to your next activity:

    ActivityUtils.jump(SimpleActivity.this, CardSampleActivity.class, CODE_CARD_SAMPLE, R.raw.sample);
  5. Create a package-info.java file in your source folder like this:

    @PackageName package me.ele.kratos_sample;
    
    import kratos.PackageName;

You will get something like this:

Deme

Add Custom updater:

If you want a custom update behavior when data been changed, add a function annotated with OnKStringChanged to your card, like this:

@OnKStringChanged("text1")
public void updateText1(@NotNull TextView v, @NotNull String s) {
    v.setText(s);
    Log.d("TextCard", "custom updater!");
}

Wait

You may say:"That's no big deal. what's the point?"

But

This is where the magic happens!

Assume you have this data object which implements Parcelable:

public class Customer implements Parcelable {

    public KString name = new KString();

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeParcelable(this.name, flags);
    }

    public Customer() {
    }

    protected Customer(Parcel in) {
        this.name = in.readParcelable(KString.class.getClassLoader());
    }

    public static final Creator<Customer> CREATOR = new Creator<Customer>() {
        public Customer createFromParcel(Parcel source) {
            return new Customer(source);
        }

        public Customer[] newArray(int size) {
            return new Customer[size];
        }
    };
}

This Customer has a property -- name, and this is what you do.

  1. Change the text1 element in the json file above to this:
"text1": "{Customer.name}",
  1. Add this code to your activity:
Customer customer;
@Override
public void onFinishRender() {
    bind(this, customer);
}

Tada!!From now on, if you want to change the view that has Customer's name in it, all you need to do is change the value of customer.name, say you do this:

customer.name.set("Merlin");

This is what you get:

Customer

Dude, Holy ****, This is Magic..

Download

Kratos is still under development and a lot of features haven't been added to it yet. But the basic idea is here. If you are interested in this project, feel free to fork.

Kratos is available from maven central:

apply plugin: 'com.neenbedankt.android-apt'
buildscript {
    ext.kratos_version = '0.2.4'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

dependencies {
    compile "com.github.acemerlin:kratos:$kratos_version"
    apt "com.github.acemerlin:kratos-compiler:$kratos_version"
}

How It Works

  • Use Kotlin's Observable Delegate to listen to changes made to certain property.
  • Use Kotlin's Extension feature to add functions to View.
  • Use Annotation Processor to generate code which binds the data and the view(or views).

Lisence

GNU GENERAL PUBLIC LICENSE Version 3

kratos's People

Contributors

acemerlin avatar skyacer avatar sanvibyfish avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.