ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用Android体系结构组件将单向数据绑定转换为双向数据

2019-07-01 09:24:12  阅读:205  来源: 互联网

标签:android android-databinding android-architecture-components android-jetpack two-


我正在重构我的Android应用程序,以便大学项目使用Architecture Components,而我很难在SwitchCompat上实现双向数据绑定.该应用程序有一个简单的用户界面,TextView显示位置更新的状态和前面提到的SwitchCompat,它可以打开和关闭位置更新.
目前我在SwitchCompat的checked属性上使用单向数据绑定,但是想使用two-way databinding.
使用Model-View-ViewModel体系结构的当前实现如下:
MainViewModel.java:

public class MainViewModel extends ViewModel {

    private LiveData<Resource<Location>> mLocationResource;

    public MainViewModel() {
        mLocationResource = Repository.getInstance().getLocationResource();
    }

    public LiveData<Resource<Location>> getLocationResource() {
        return mLocationResource;
    }

    public void onCheckedChanged (Context context, boolean isChecked) {
        if (isChecked) {
            Repository.getInstance().requestLocationUpdates(context);
        } else {
            Repository.getInstance().removeLocationUpdates(context);
        }
    }
}

资源与LT;地点> (看到了想法here)是一个包含可空数据(Location)的类和TextView可以处理的非null状态:
State.java

public enum State {
    LOADING,
    UPDATE,
    UNKNOWN,
    STOPPED
}

现在在fragment_main.xml中的android:onCheckedChanged实现:

android:onCheckedChanged="@{(buttonView, isChecked) -> viewModel.onCheckedChanged(context, isChecked)}"

最后自定义绑定适配器从状态转换为布尔检查状态:

@BindingAdapter({"android:checked"})
public static void setChecked(CompoundButton view, Resource<Location> locationResource) {
    State state = locationResource.getState();
    boolean checked;
    if (state == State.STOPPED) {
        checked = false;
    } else {
        checked = true;
    }
    if (view.isChecked() != checked) {
        view.setChecked(checked);
    }
}

以及fragment_main.xml中android:checked属性的实现:

android:checked="@{viewModel.getLocationResource}"

正如上面链接的Android开发者指南所说,我怎样才能在android内部完成所有工作:检查而不是同时拥有android:checked和android:onCheckedChanged(单向数据绑定到双向数据绑定)?
另外,如果您认为我的应用程序的架构/逻辑可以改进,请告诉我:)

解决方法:

我就是这样做的(抱歉Kotlin代码):

首先,我将重构资源< T> class并使状态变量成为MutableLiveData< State>宾语:

enum class State {
    LOADING,
    UPDATE,
    UNKNOWN,
    STOPPED
}

class Resource<T>() {
    var state = MutableLiveData<State>().apply { 
        value = State.STOPPED //Setting the initial value to State.STOPPED
    }
}

然后我将创建以下ViewModel:

class MainViewModel: ViewModel() {

     val locationResource = Resource<Location>()

}

在数据绑定布局中,我将编写以下内容:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="viewModel"
            type="MainViewModel" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.appcompat.widget.SwitchCompat
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:resourceState="@={viewModel.locationResource.state}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(viewModel.locationResource.state)}" />

    </LinearLayout>

</layout>

请注意SwitchCompat视图中的双向数据绑定表达式@ =.

现在到BindingAdapter和InverseBindingAdapter:

@BindingAdapter("resourceState")
fun setResourceState(compoundButton: CompoundButton, resourceState: State) {
    compoundButton.isChecked = when (resourceState) {
        // You can decide yourself how the mapping should look like:
        State.LOADING -> true 
        State.UPDATE -> true
        State.UNKNOWN -> true
        State.STOPPED -> false
    }
}

@InverseBindingAdapter(attribute = "resourceState", event = "resourceStateAttrChanged")
fun getResourceStateAttrChanged(compoundButton: CompoundButton): State =
    // You can decide yourself how the mapping should look like:
    if (compoundButton.isChecked) State.UPDATE else State.STOPPED

@BindingAdapter("resourceStateAttrChanged")
fun setResourceStateAttrChanged(
    compoundButton: CompoundButton,
    attrChange: InverseBindingListener
) {
    compoundButton.setOnCheckedChangeListener { _, isChecked -> 
        attrChange.onChange()

        // Not the best place to put this, but it will work for now:
        if (isChecked) {
            Repository.getInstance().requestLocationUpdates(context);
        } else {
            Repository.getInstance().removeLocationUpdates(context);
        }
    }
}

就是这样.现在:

>每当locationResource.state更改为State.STOPPED时,SwitchCompat按钮将进入未选中状态.
>每当locationResource.state从State.STOPPED更改为另一个状态时,SwitchCompat按钮将进入选中状态.
>每当轻触Swit​​chCompat按钮并更改为选中状态,则locationResource.state的值将更改为State.UPDATE.
>只要轻触Swit​​chCompat按钮并更改为未选中状态,则locationResource.state的值将更改为State.STOPPED.

如果不清楚,请随时问我任何问题.

标签:android,android-databinding,android-architecture-components,android-jetpack,two-
来源: https://codeday.me/bug/20190701/1345667.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有