Groovy 1.8.2 和 1.9 beta3 发布,基于JVM的短平快动态

作者:ca88

ca88 1

Custom Setters

Some attributes need custom binding logic. For example, there is no associated setter for the android:paddingLeft attribute. Instead, setPadding(left, top, right, bottom) exists. A static binding adapter method with the BindingAdapter annotation allows the developer to customize how a setter for an attribute is called.

The android attributes have already had BindingAdapters created. For example, here is the one for paddingLeft:

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
   view.setPadding(padding,
                   view.getPaddingTop(),
                   view.getPaddingRight(),
                   view.getPaddingBottom());
}

Binding adapters are useful for other types of customization. For example, a custom loader can be called off-thread to load an image.

Developer-created binding adapters will override the data binding default adapters when there is a conflict.

You can also have adapters that receive multiple parameters.

@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
   Picasso.with(view.getContext()).load(url).error(error).into(view);
}

<ImageView app:imageUrl="@{venue.imageUrl}"
app:error="@{@drawable/venueError}"/>

This adapter will be called if both imageUrl and error are used for an ImageView and imageUrl is a string and error is a drawable.

  • Custom namespaces are ignored during matching.
  • You can also write adapters for android namespace.
    Binding adapter methods may optionally take the old values in their handlers. A method taking old and new values should have all old values for the attributes come first, followed by the new values:
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
   if (oldPadding != newPadding) {
       view.setPadding(newPadding,
                       vie     w.getPaddingTop(),
                       view.getPaddingRight(),
                       view.getPaddingBottom());
   }
}

Event handlers may only be used with interfaces or abstract classes with one abstract method. For example:

@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
       View.OnLayoutChangeListener newValue) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        if (oldValue != null) {
            view.removeOnLayoutChangeListener(oldValue);
        }
        if (newValue != null) {
            view.addOnLayoutChangeListener(newValue);
        }
    }
}

When a listener has multiple methods, it must be split into multiple listeners. For example, View.OnAttachStateChangeListener has two methods:onViewAttachedToWindow() and onViewDetachedFromWindow(). We must then create two interfaces to differentiate the attributes and handlers for them.

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
    void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
    void onViewAttachedToWindow(View v);
}
Because changing one listener will also affect the other, we must have three different binding adapters, one for each attribute and one for both, should they both be set.

@BindingAdapter("android:onViewAttachedToWindow")
public static void setListener(View view, OnViewAttachedToWindow attached) {
    setListener(view, null, attached);
}

@BindingAdapter("android:onViewDetachedFromWindow")
public static void setListener(View view, OnViewDetachedFromWindow detached) {
    setListener(view, detached, null);
}

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
public static void setListener(View view, final OnViewDetachedFromWindow detach,
        final OnViewAttachedToWindow attach) {
    if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
        final OnAttachStateChangeListener newListener;
        if (detach == null && attach == null) {
            newListener = null;
        } else {
            newListener = new OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    if (attach != null) {
                        attach.onViewAttachedToWindow(v);
                    }
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    if (detach != null) {
                        detach.onViewDetachedFromWindow(v);
                    }
                }
            };
        }
        final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
                newListener, R.id.onAttachStateChangeListener);
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener);
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener);
        }
    }
}

The above example is slightly more complicated than normal because View uses add and remove for the listener instead of a set method for View.OnAttachStateChangeListener. The android.databinding.adapters.ListenerUtil class helps keep track of the previous listeners so that they may be removed in the Binding Adaper.

ca88,By annotating the interfaces OnViewDetachedFromWindow and OnViewAttachedToWindow with @TargetApi(VERSION_CODES.HONEYCOMB_MR1), the data binding code generator knows that the listener should only be generated when running on Honeycomb MR1 and new devices, the same version supported by addOnAttachStateChangeListener(View.OnAttachStateChangeListener).

Groovy 1.8.6 正式公告了,那是洋气的 Groovy 稳定版本。Groovy是三个基于 Java虚构机的长足动态语言,它创设在强硬的Java语言之上,同期引进闭包和元编制程序等美好的新效能,并增多了Python、Ruby和Smalltalk等语言中的繁多特点。Groovy扶助DSL和任何简洁的语法,让您的代码变得轻易阅读和保险。Groovy无缝集成具备曾经存在的 Java对象和类库,能够直接编写翻译成Java字节码,那样能够在任何利用Java的地点使用Groovy。该版本的新成效富含:新增byte[].encodeHex方法。新增GDK方法Object[].contains(卡塔尔国。为原始数组提供了回顾D欧霉素在内的点子。该版本的效应更改富含:调整和缩短了groovyc命令行长度。GroovyTestCase中的shouldFail{...}语句应该回到分外音信,而不是密封式的消息。Groovy的POM中增多了多个license/块。GroovyScriptEngineImpl以后能够运用ConcurrentHashMaps。GroovyEngine无法为ant文件成立友好的台本名称。绑定hasVariable。改过了报表中的TableSorter输出。TimeDuration应该达成Comparable作用。List中加多了叁个collate方法。其余,该版本还修复了有的bug,详细音讯参阅:ReleaseNote下载地址:

此版本主借使指向1.7中bug的修补和性质的升高,1.8.0最终版将要当年岁末公布。

Groovy开拓团队发表Groovy 1.8.2和1.9 beta3揭破了。此次是因为beta 2发出了二个竟然的小本事故障,以至Maven Central方面包车型客车题目,1.9拨出的beta版直接跳至beta 3。Groovy是一个基于 Java虚构机的不慢动态语言,它营造在强大的Java语言之上,同有的时候候引进闭包和元编制程序等能够的新作用,并增加了Python、Ruby和Smalltalk等语言中的繁多特色。Groovy帮助DSL和其余简洁的语法,让你的代码变得轻易阅读和维护。Groovy无缝集成富有曾经存在的 Java对象和类库,能够间接编写翻译成Java字节码,那样能够在别的利用Java的地点使用Groovy。你也足以将Groovy想像成 Java 语言的后生可畏种越发简约、表明本领更加强的变体。Groovy 和 Java 语言的要害不一致是:达成同样的职责所需的 Groovy 代码比 Java 代码越来越少。 本次版本的最大优点在于原始类型的演算质量优化。除此而外,其余的更改都是关于BUG修复的。Groovy 1.8.2改进:[GROOVY-4949] - Groovy should provide CharSequence variants for most its DGM String methods[GROOVY-4962] - SwingBuilder binding updates should happen inside the EDT if the target is an UI component详细消息参阅:Groovy 1.8.2 Release NotesGroovy 1.9 beta3改进:[GROOVY-4949] - Groovy should provide CharSequence variants for most its DGM String methods[GROOVY-4960] - SwingBuilder.doOutside should use a ThreadPool[GROOVY-4961] - SwingBuilder should set the node's name property with the value of the id property if no name is set[GROOVY-4962] - SwingBuilder binding updates should happen inside the EDT if the target is an UI component详细消息参阅:Groovy 1.9 beta3 Release Notes此外,Groovy已经成功了到Git的动员搬迁职业。能够访谈下边包车型客车地方询问实际情况:。之后,Groovy还有大概会提供叁个GitHub的镜像。Groovy官方网站:下载地址:

Background Thread

You can change your data model in a background thread as long as it is not a collection. Data binding will localize each variable / field while evaluating to avoid any concurrency issues.

ca88 2

Groovy 1.8.0-beta-1

Listener Bindings

Listener Bindings are binding expressions that run when an event happens. They are similar to method references, but they let you run arbitrary data binding expressions. This feature is available with Android Gradle Plugin for Gradle version 2.0 and later.

In method references, the parameters of the method must match the parameters of the event listener. In Listener Bindings, only your return value must match the expected return value of the listener (unless it is expecting void). For example, you can have a presenter class that has the following method:

public class Presenter {
    public void onSaveClick(Task task){}
}

Then you can bind the click event to your class as follows:

  <?xml version="1.0" encoding="utf-8"?>
  <layout xmlns:android="http://schemas.android.com/apk/res/android">
      <data>
          <variable name="task" type="com.android.example.Task" />
          <variable name="presenter" type="com.android.example.Presenter" />
      </data>
      <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
          <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onClick="@{() -> presenter.onSaveClick(task)}" />
      </LinearLayout>
  </layout>

Listeners are represented by lambda expressions that are allowed only as root elements of your expressions. When a callback is used in an expression, Data Binding automatically creates the necessary listener and registers for the event. When the view fires the event, Data Binding evaluates the given expression. As in regular binding expressions, you still get the null and thread safety of Data Binding while these listener expressions are being evaluated.

Note that in the example above, we haven't defined the view parameter that is passed into onClick(android.view.View). Listener bindings provide two choices for listener parameters: you can either ignore all parameters to the method or name all of them. If you prefer to name the parameters, you can use them in your expression. For example, the expression above could be written as:

  android:onClick="@{(view) -> presenter.onSaveClick(task)}"

Or if you wanted to use the parameter in the expression, it could work as follows:

public class Presenter {
    public void onSaveClick(View view, Task task){}
}

  android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"

You can use a lambda expression with more than one parameter:

public class Presenter {
    public void onCompletedChanged(Task task, boolean completed){}
}

  <CheckBox android:layout_width="wrap_content"       android:layout_height="wrap_content"
        android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />

If the event you are listening to returns a value whose type is not void, your expressions must return the same type of value as well. For example, if you want to listen for the long click event, your expression should return boolean.

public class Presenter {
    public boolean onLongClick(View view, Task task){}
}

  android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"

If the expression cannot be evaluated due to null objects, Data Binding returns the default Java value for that type. For example, null for reference types, 0 for int, false for boolean, etc.

If you need to use an expression with a predicate (e.g. ternary), you can use void as a symbol.

  android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"

此版本重若是对bug的修补,还加多了新的GDK方法,如:File.renameTo(String path卡塔尔(英语:State of Qatar)等。查看1.7.4发布公文档案:

Missing Operations

A few operations are missing from the expression syntax that you can use in Java.

  • this
  • super
  • new
  • Explicit generic invocation

Groovy 1.7.4 和1.8.0-beta-1版本同临时常间发布。

ViewStubs

ViewStubs are a little different from normal Views. They start off invisible and when they either are made visible or are explicitly told to inflate, they replace themselves in the layout by inflating another layout.

Because the ViewStub essentially disappears from the View hierarchy, the View in the binding object must also disappear to allow collection. Because the Views are final, a ViewStubProxy object takes the place of the ViewStub, giving the developer access to the ViewStub when it exists and also access to the inflated View hierarchy when the ViewStub has been inflated.

When inflating another layout, a binding must be established for the new layout. Therefore, the ViewStubProxy must listen to the ViewStub'sViewStub.OnInflateListener and establish the binding at that time. Since only one can exist, the ViewStubProxy allows the developer to set anOnInflateListener on it that it will call after establishing the binding.

Groovy 1.7.4

Writing your first set of data binding expressions

Data-binding layout files are slightly different and start with a root tag of layout followed by a data element and a view root element. This view element is what your root would be in a non-binding layout file. A sample file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

The user variable within data describes a property that may be used within this layout.

<variable name="user" type="com.example.User"/>

Expressions within the layout are written in the attribute properties using the "@{}" syntax. Here, the TextView's text is set to the firstName property of user:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}"/>

改进:

Observable zctions

Some applications use more dynamic structures to hold data. Observable collections allow keyed access to these data objects. ObservableArrayMap is useful when the key is a reference type, such as String.

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

In the layout, the map may be accessed through the String keys:

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap<String, Object>"/>
</data>
<TextView
   android:text='@{user["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1   (Integer)user["age"])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

ObservableArrayList is useful when the key is an integer:

ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);

In the layout, the list may be accessed through the indices:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
   android:text='@{user[Fields.LAST_NAME]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1   (Integer)user[Fields.AGE])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

翻看详细揭露文书档案:

Build Environment

To get started with Data Binding, download the library from the Support repository in the Android SDK manager.

To configure your app to use data binding, add the dataBinding element to your build.gradle file in the app module.

Use the following code snippet to configure data binding:

android {
    ....
    dataBinding {
        enabled = true
    }
}

If you have an app module that depends on a library which uses data binding, your app module must configure data binding in its build.gradle file as well.

Also, make sure you are using a compatible version of Android Studio. Android Studio 1.3 and later provides support for data binding as described in Android Studio Support for Data Binding.

closures are now "callable" (inheriting from java.util.concurrent.Callable)new AST transformations like@Log to inject a logger in your classes@ScriptField for creating a field in a script (should be renamed to @Field in the next beta)@PackageScope now working also on methods and classes (not just fields as before)@Synchronized for providing safer synchronization semantics@InheritConstructors to inherit constructors, like often the case when extending exception classes@IndexedProperties to add JavaBeans indexed property support@AutoClone providing automatic cloning support to your beans@AutoExternalize providing automatic externalization of your POGOs@Canonical adding proper equals(), hashCode(), toString() methods@EqualsAndHashCode adding an equals() and hashCode() method@ToString for creating a default readable toString() method@TupleConstructor for adding a tuple constructoran additional syntax for strings, with $/.../$, to circumvent various escaping corner cases, like for example $/a/bc$$ $//$new GDK methods like Map.countBy{}, Map.collectEntries{}, Date.putAt() (subscript operator), Date.updated() obviously all other incremental improvements and new features from the Groovy 1.7 branch likethe new String methods like tr(), stripMargin(), stripIndent(), (un)expand(), Map's withDefault{} method, Closure's ncury() and rcury()Sql's withBatch{} and withTransaction{}

Immediate Binding

When a variable or observable changes, the binding will be scheduled to change before the next frame. There are times, however, when binding must be executed immediately. To force execution, use the executePendingBindings() method.

Avoid Complex Listeners

Listener expressions are very powerful and can make your code very easy to read. On the other hand, listeners containing complex expressions make your layouts hard to read and unmaintainable. These expressions should be as simple as passing available data from your UI to your callback method. You should implement any business logic inside the callback method that you invoked from the listener expression.
Some specialized click event handlers exist and they need an attribute other than android:onClick to avoid a conflict. The following attributes have been created to avoid such conflicts:

ca88 3

截图

Dynamic Variables

At times, the specific binding class won't be known. For example, a RecyclerView.Adapter operating against arbitrary layouts won't know the specific binding class. It still must assign the binding value during the onBindViewHolder(VH, int).

In this example, all layouts that the RecyclerView binds to have an "item" variable. The BindingHolder has a getBinding method returning theViewDataBinding base.

public void onBindViewHolder(BindingHolder holder, int position) {
   final T item = mItems.get(position);
   holder.getBinding().setVariable(BR.item, item);
   holder.getBinding().executePendingBindings();
}

Data Objects

Any plain old Java object (POJO) may be used for data binding, but modifying a POJO will not cause the UI to update. The real power of data binding can be used by giving your data objects the ability to notify when data changes. There are three different data change notification mechanisms,Observable objects, observable fields, and observable collections.

When one of these observable data object is bound to the UI and a property of the data object changes, the UI will be updated automatically.

本文由ca88发布,转载请注明来源

关键词: DataBinding 语言 版本 代码 详细信息