使用 DataBinding 库绑定事件

Posted

技术标签:

【中文标题】使用 DataBinding 库绑定事件【英文标题】:Using DataBinding library for binding events 【发布时间】:2015-11-04 20:48:23 【问题描述】:

我正在尝试使用 android M 附带的 DataBinding 库 将事件与 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_
    android:layout_
    android:text="@user.firstName"
    android:visibility="@user.isFriend ? View.VISIBLE : View.GONE" />
 <Button
    android:layout_
    android:layout_
    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");
  

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

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

是的,如果您将 Activity 类用作处理程序,那么您只需要这样做:binding.setHandlers(this); 如果你有许多相同的动作,你可以使用这个库来简单起见 - github.com/drstranges/ActionHandler @dorsz +100 给你!我搜索了好几个小时! 如果您正在使用演示者,演示者也是如此 这太棒了!我希望文档能更好地概述这一点!感谢您的精彩回答!【参考方案2】:

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

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_
    android:layout_
    android:text="@user.firstName"
    android:visibility="@user.isFriend ? View.VISIBLE : View.GONE" />

<Button
    android:layout_
    android:layout_
    android:text="Click Me"
    android:id="@+id/button"
    android:layout_gravity="left"
    android:onClick="@onClickFriend"/>

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

【讨论】:

好吧android:onClick="@onClickFriend" 没用,但android:onClick="onClickFriend" 正常工作.. 这几乎是真的。你可以使用你的Activity作为handler,layout中的onClick类似于android:onClick="@handlers::onClickFriend",但是你需要在Activity中绑定handler,像这样:binding.setHandlers(this); 嗨,你知道如何处理onlongclick事件吗?【参考方案3】:

如果你要使用你的activity,不妨把自动绑定的context对象替换掉,不然就浪费空间了。

生成一个名为 context 的特殊变量,用于绑定 根据需要表达。 context 的值是来自 根视图的 getContext()。上下文变量将被覆盖 具有该名称的显式变量声明。

binding.setContext(this);

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

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

【讨论】:

【参考方案4】:

在你的 xml 中使用这种格式:

android:onClick="@handlers::onClickFriend"

注意::,不用担心xml编辑器中的红线,因为目前这是为Android Studio xml编辑器打开的bug。

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 类中添加 onLongClickFriend 方法:

public class MyHandlers 
    public boolean onLongClickFriend(View view) 
        Log.i(MyHandlers.class.getSimpleName(),"Long clicked Friend");
        return true;
    

添加

如果需要显示toast消息,可以使用interface(更好的变体),或者在构造中传递MyHandlers类中的context

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

【讨论】:

嗨,你知道如何处理onlongclick事件吗? 它没有用。无法编译项目。 Unknown attribute android:onLongClick. 对不起,尝试将void改成boolean这样的方法:public boolean onLongClickFriend(View view),最后加上return true; @walkmn 如何在 onClickFriend 方法中显示 toast 或传递上下文 我们可以使用view.getContext() 方法在每个方法中获取context,因此无需使用构造函数传递它。【参考方案5】:

你应该这样做

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

【讨论】:

您的意思是 android:onClick="@(view) -&gt; handlers.onClickFriend",否则 lambda 将与 onClick 事件的签名不匹配。 @AymenDaoudi 更正确应该是android:onClick="@(view) -&gt; handlers.onClickFriend()" 唯一对我有用的方法来自@AlekseyMasny。谢了! () -&gt; function() 语法完全有效。请查看文档:developer.android.com/topic/libraries/data-binding/…【参考方案6】:

我发布此消息是因为我遇到过发生这种情况的其他情况。如果您有两个引用布局文件的活动,一个定义了 onclick 事件,而另一个定义了 onclick 事件,那么您在定义事件的活动中却没有收到相同的警告,而且奇怪的是。

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

【讨论】:

【参考方案7】:

我发布此内容只是为了涵盖实现此目的的两种方式。 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_
  android:layout_>

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

     <Button
            android:layout_
            android:layout_
            android:layout_marginTop="32dp"
            android:text="Using Method Ref"
            android:onClick="@handlers::onButtonClicked"/>            

</LinearLayout>
</layout>

活动:

@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.在使用方法引用时,方法签名应该与您为任何其他 onClick 方法编写的相同,即 public 和 View 作为参数。

2.在使用监听器绑定的同时,您还可以根据需要直接传递对象并执行任何操作。

【讨论】:

【参考方案8】:

设置点击的多种方式

    将处理程序传递给绑定。

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

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

    android:onClick="@handler::onClickMethodReference"

android:onClick="@handler.onClickMethodReference"

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

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

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

请参阅 Handler 类了解。

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)-&gt; 表达式即可。

进一步阅读

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

【讨论】:

这是一个很好的答案。请注意,只有带箭头符号的底部三个是唯一允许您从 xml Ctrl-跳转到处理程序中的代码的代码(截至 3 月 19 日)【参考方案9】:

对于那些无法处理长点击事件的人:

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

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

<TextView
            android:id="@+id/textView"
            android:layout_
            android:layout_
            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 方法中为活动变量设置上下文来为布局中的任何视图设置任何方法:-

binding.setActivity(this);

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

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

【讨论】:

不要在数据绑定中保存活动引用,否则会导致内存泄漏。 @TheLibrarian 你有这方面的资料吗?

以上是关于使用 DataBinding 库绑定事件的主要内容,如果未能解决你的问题,请参考以下文章

仅对具有 DataBinding 事件的对象提供数据绑定表达式支持。System.Web.UI.WebControls.HyperLinkField 没

Android dataBinding 之 配合使用BaseAdapter适配器

一起Talk Android吧(第三百八十五回:数据绑定-DataBinding总结)

Android官方文档之DataBinding库

Android基础——框架模式MVVM之DataBinding的实践

数据绑定库和MVVM