使用 DataBinding 库绑定事件

Using DataBinding library for binding events

我正在尝试使用 Android M 附带的 DataBinding Library 将事件与 xml 中的视图绑定。我正在关注 Android Developers 并逐步实施。对于视图的可见性、文本等属性,它工作正常,但如果我尝试与 onclick 绑定,它不会按预期工作。这是我到目前为止尝试过的示例代码:

 <data>
    <import type="android.view.View"/>
    <variable name="user" type="com.example.databinding.User"/>
    <variable name="handlers" type="com.example.databinding.MyHandlers"/>
</data>

 <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"
    android:visibility="@{user.isFriend ? View.VISIBLE : View.GONE}" />
 <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me"
    android:id="@+id/button"
    android:layout_gravity="left"
    android:onClick="@{handlers.onClickFriend}"/>

主要活动:

  public class MainActivity extends AppCompatActivity {

  User user;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = 
    DataBindingUtil.setContentView(this,R.layout.activity_main);
    user = new User("Pankaj","Kumar",true,true);
    binding.setUser(user);
   }
 }

我的处理程序:

public class MyHandlers {
public void onClickFriend(View view){
    Log.i(MyHandlers.class.getSimpleName(),"Now Friend");
}

public void onClickEnemy(View view){
    Log.i(MyHandlers.class.getSimpleName(),"Now Enemy");
  }
}

我只编写了提高可读性所需的代码。有人可以帮我解决这个问题吗?

我认为您还需要绑定 handlers,也许在 onCreate 中是这样的:

MyHandlers handlers = new MyHandlers();
binding.setHandlers(handlers);

不必创建单独的 class MyHandlers 并调用 setHandlers 来处理 android:onClick。您可以只使用方法:public void onClickFriend(View view)public void onClickEnemy(View view) in MainActivity。 activity 视图:

public class MainActivity extends AppCompatActivity {
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        user = new User("Pankaj", "Kumar", true, true);
        binding.setUser(user);
    }

    public void onClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(), "Now Friend");
    }

    public void onClickEnemy(View view) {
        Log.i(MyHandlers.class.getSimpleName(), "Now Enemy");
    }
}

布局:

<data>
    <import type="android.view.View"/>
    <variable name="user" type="com.example.databinding.User"/>
</data>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"
    android:visibility="@{user.isFriend ? View.VISIBLE : View.GONE}" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me"
    android:id="@+id/button"
    android:layout_gravity="left"
    android:onClick="@{onClickFriend}"/>

看一下使用 MVVM 模式的数据绑定库的示例:http://cases.azoft.com/mvvm-android-data-binding

如果你打算使用你的activity,不妨更换自动绑定的context对象,否则你就是在浪费space。

A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.

binding.setContext(this);

<variable name="context" type="com.example.MyActivity"/>

请注意,如果您只使用纯字符串 onClick="someFunc",那根本不是数据绑定功能。这是一个较旧的功能,它使用一点反射来查找上下文中的方法。

在您的 xml:

中使用此格式
android:onClick="@{handlers::onClickFriend}"

注意 ::,不要担心 xml 编辑器中的红线,因为目前 bug Android Studio xml编辑.

其中 handlers 是来自数据标记的变量:

<data>
    <variable name="handlers" type="com.example.databinding.MyHandlers"/>
</data>

onClickFriend是你的方法:

public class MyHandlers {
    public void onClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(),"Now Friend");
    }
}

已添加

对于 xml 中的句柄 onLongClick 添加:

android:onLongClick="@{handlers::onLongClickFriend}"

并在您的 ViewModel class:

中添加 onLongClickFriend 方法
public class MyHandlers {
    public boolean onLongClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(),"Long clicked Friend");
        return true;
    }
}

已添加

如果你需要显示吐司消息,你可以使用接口(更好的变体),或者在MyHandlers中传递context class在构造中:

public class MyHandlers {
    public boolean onLongClickFriend(View view) {
        Toast.makeText(view.getContext(), "On Long Click Listener", Toast.LENGTH_SHORT).show();
        return true;
    }
}

你应该做

android:onClick="@{() -> handlers.onClickFriend()}"

我发布这个是因为我在其他情况下也发生过这种情况。如果你有两个引用布局文件的活动,一个定义了 onclick 事件,另一个没有,你会得到同样的警告,奇怪的是在你定义事件的 activity 中。

要检查这一点,我建议通过 right clicking 在布局名称上找到布局文件的用法,然后按 find references。不要忘记重建应用程序后记。

我发布这篇文章只是为了涵盖实现这一目标的两种方法。 1.通过Listener绑定 2. 通过方法引用

布局:

<layout...>
<data>

        <variable
            name="handlers"
            type="com.example.databinding.MyPresenter" />
        <variable name="user" type="com.example.databinding.User"/>
</data>

<LinearLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="Using Listener Binding"
            android:onClick="@{() -> handlers.onLisClick(user)}"/>

     <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="Using Method Ref"
            android:onClick="@{handlers::onButtonClicked}"/>            

</LinearLayout>
</layout>

Activity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        MyPresenter presenter = new MyPresenter();
        User user = new User("Alex","RJ")
        binding.setUser(user);
        binding.setHandlers(presenter);
    }

我的演示者:

public class MyPresenter{

//using listener binding
public void onLisClick(User user){
//do something..
}


//using method reference
public void onButtonClicked(View view){

// do something
}

}

注:
1.While 使用方法引用,方法签名应该与您为任何其他 onClick 方法编写的相同,即 public 和 View as parameter.

2.While 使用侦听器绑定的好处是,如果需要,您也可以直接传递对象并执行任何操作。

多种点击设置方式

  1. 将处理程序传递给绑定。

    ActivityMainBinding 绑定 = DataBindingUtil.setContentView(this,R.layout.activity_main); 处理程序处理程序 = new Handler(); binding.setHandler(处理程序);

  2. 设置点击次数(使用以下任何一种)

    android:onClick="@{handler::onClickMethodReference}"

android:onClick="@{handler.onClickMethodReference}"

android:onClick="@{() -> handler.onClickLamda()}"

android:onClick="@{(v) -> handler.onClickLamdaWithView(v)}"

android:onClick="@{() -> handler.onClickLamdaWithView(model)}"

请参阅处理程序 class 了解。

public class Handler {
    public void onClickMethodReference(View view) {
        //
    }
    public void onClickLamda() {
        //
    }
    public void onClickLamdaWithView(View view) {
        //
    }
    public void onClickLamdaWithObject(Model model) {
        //
    }
}

注意

  • 您可以使用 方法参考 (::) 当您具有与属性 onClick.
  • 相同的参数时
  • 您可以传递任何对象,例如 onClickLamdaWithObject 示例。
  • 如果您需要传递 View 对象,那么只需使用 (v)-> 表达式。

进一步阅读

https://developer.android.com/topic/libraries/data-binding/expressions

For those who are having trouble in handling long click events:

首先在布局中创建一个带有 id 的视图。

<data>
        <variable
            name="tempDesc"
            type="String" />
        <variable
            name="activity"
            type="com.naruto.trangoapp.MainActivity" />
</data>

<TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{(view) -> activity.changeDescText(view)}"
            android:text="@{tempDesc}" />

在您的 onCreate 方法中使用视图的 ID 名称来设置任何侦听器:-

binding.textView.setOnLongClickListener(this::onLongClick);

然后只需创建一个具有相同名称的布尔方法,即 onLongClick,如下所示:-

private boolean onLongClick(View l) {
        Toast.makeText(this, "Description", Toast.LENGTH_SHORT).show();
        return true;
    }

就这些了!!

注意:您还可以通过在 onCreate 方法中将上下文设置为 activity 变量,将任何方法设置到布局中的任何视图:-

binding.setActivity(this);

然后,在您的布局中定义并传递带有视图的方法名称,以便在您的 Activity 文件中使用它。就像我为我的 Textview 使用了带有变量名称 "activity" 的方法 changeDescText(v) 一样。 这是我在 Activity 文件中的方法:-

public void changeDescText(View view) {
        binding.setTempDesc("Description Changed");
    }