jetpack之数据绑定的源码解读(二)

源码版本:Android10

在上一篇 jetpack之数据绑定的源码解读(一)中介绍了DataBinding的基本原理,这篇文章主要是讲@InverseBindingAdapter以及是如何实现双向绑定的。

一、Demo源码

1.1 activity_recycler_view.xml源码
<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="refresh"
            type="com.study.jetpackstudykotlin.databinding.bean.Refresh" />
    </data>

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/srl"
        refreshing="@={refresh.swipeRefreshViewRefreshing}"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".databinding.RecyclerViewActivity">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
            <Button
                android:id="@+id/bt"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
        </FrameLayout>

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>


1.2 RecyclerViewActivity源码
package com.study.jetpackstudykotlin.databinding

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.study.jetpackstudykotlin.R
import com.study.jetpackstudykotlin.databinding.adapter.RvAdapter
import com.study.jetpackstudykotlin.databinding.bean.Refresh
import com.study.jetpackstudykotlin.databinding.bean.User

class RecyclerViewActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recycler_view)
        val binding = DataBindingUtil.setContentView<ActivityRecyclerViewBinding>(
            this,
            R.layout.activity_recycler_view
        )
        val refresh = Refresh()
        binding.refresh = refresh
        binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        var arrayList = arrayListOf<User>()
        for (j in 0..100) {
            arrayList.add(User("简单$j", "粗暴$j"))
        }
        binding.rv.adapter = RvAdapter(this, arrayList)


        binding.bt.setOnClickListener {
            Log.e("refresh::", "当前binding.refresh值为Activity" + refresh.swipeRefreshViewRefreshing.get())
            //修改刷新状态值
            refresh.swipeRefreshViewRefreshing.set(false)
        }
    }
}

1.3 ViewAdapter源码
package com.study.jetpackstudykotlin.databinding.viewAdapter;

import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.widget.AppCompatImageView;
import androidx.databinding.BindingAdapter;
import androidx.databinding.BindingConversion;
import androidx.databinding.InverseBindingAdapter;
import androidx.databinding.InverseBindingListener;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

public class ViewAdapter {


    @BindingAdapter(value = {"imgContent"})
    public static void loadImage(AppCompatImageView imageView, final String content) {
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(v.getContext(), content, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @BindingConversion
    public static ColorDrawable convertColorToDrawable(int color) {
        return new ColorDrawable(color);
    }
    
    
    //===================SwipeRefreshLayout双向绑定的具体实现===================
    @InverseBindingAdapter(attribute = "refreshing", event = "refreshingAttrChanged")
    public static boolean isRefreshing(SwipeRefreshLayout view) {
        return view.isRefreshing();
    }
	
	//InverseBindingListener refreshingAttrChanged是由apt帮忙生成的
    @BindingAdapter(value = {"refreshingAttrChanged"}, requireAll = false)
    public static void setOnRefreshListener(final SwipeRefreshLayout view,
                                            final InverseBindingListener refreshingAttrChanged) {

        if (refreshingAttrChanged != null) {
        //给view设置刷新监听
            view.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    refreshingAttrChanged.onChange();
                    Log.e("refresh::", "当前binding.refresh值为" + view.isRefreshing());
                }
            });
        }
    }

    @BindingAdapter("refreshing")
    public static void setRefreshing(SwipeRefreshLayout view, boolean refreshing) {
    //两者不相同,才去刷新SwipeRefreshLayout
        if (refreshing != view.isRefreshing()) {
            view.setRefreshing(refreshing);
        }
    }
}

二、源码分析

这里使用SwipeRefreshLayout来作为实现双向绑定的示例,xml文件中

refreshing="@={refresh.swipeRefreshViewRefreshing}",@=是实现双向绑定的关键条件之一

com.study.jetpackstudykotlin.databinding.ActivityRecyclerViewBindingImpl源码如下所示:

package com.study.jetpackstudykotlin.databinding;
import com.study.jetpackstudykotlin.R;
import com.study.jetpackstudykotlin.BR;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.View;
@SuppressWarnings("unchecked")
public class ActivityRecyclerViewBindingImpl extends ActivityRecyclerViewBinding  {

    @Nullable
    private static final androidx.databinding.ViewDataBinding.IncludedLayouts sIncludes;
    @Nullable
    private static final android.util.SparseIntArray sViewsWithIds;
    static {
        sIncludes = null;
        sViewsWithIds = new android.util.SparseIntArray();
        sViewsWithIds.put(R.id.rv, 1);
        sViewsWithIds.put(R.id.bt, 2);
    }
    // views
    // variables
    // values
    // listeners
    // Inverse Binding Event Handlers,生产双向绑定的监听类
    private androidx.databinding.InverseBindingListener srlrefreshingAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            // Inverse of refresh.swipeRefreshViewRefreshing.get()
            //         is refresh.swipeRefreshViewRefreshing.set((boolean) callbackArg_0)
            //通过调用isRefreshing方法,获取SwipeRefreshLayout刷新状态的回调值
            boolean callbackArg_0 = com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.isRefreshing(srl);
            // localize variables for thread safety
            // refresh != null
            boolean refreshJavaLangObjectNull = false;
            // refresh.swipeRefreshViewRefreshing != null
            boolean refreshSwipeRefreshViewRefreshingJavaLangObjectNull = false;
            // refresh 进入页面的首次状态值
            com.study.jetpackstudykotlin.databinding.bean.Refresh refresh = mRefresh;
            // refresh.swipeRefreshViewRefreshing.get()
            boolean refreshSwipeRefreshViewRefreshingGet = false;
            // refresh.swipeRefreshViewRefreshing
            androidx.databinding.ObservableBoolean refreshSwipeRefreshViewRefreshing = null;



            refreshJavaLangObjectNull = (refresh) != (null);
            if (refreshJavaLangObjectNull) {

				//获取xml文件中操作SwipeRefreshLayout刷新状态的对象
                refreshSwipeRefreshViewRefreshing = refresh.getSwipeRefreshViewRefreshing();

                refreshSwipeRefreshViewRefreshingJavaLangObjectNull = (refreshSwipeRefreshViewRefreshing) != (null);
                if (refreshSwipeRefreshViewRefreshingJavaLangObjectNull) {
					//将改变之后的刷新状态值交给Activity里面refreshSwipeRefreshViewRefreshing,从而实现双向绑定
                    refreshSwipeRefreshViewRefreshing.set(((boolean) (callbackArg_0)));
                }
            }
        }
    };

    public ActivityRecyclerViewBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
    }
    private ActivityRecyclerViewBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 1
            , (android.widget.Button) bindings[2]
            , (androidx.recyclerview.widget.RecyclerView) bindings[1]
            , (androidx.swiperefreshlayout.widget.SwipeRefreshLayout) bindings[0]
            );
        this.srl.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }

    @Override
    public void invalidateAll() {
        synchronized(this) {
                mDirtyFlags = 0x4L;
        }
        requestRebind();
    }

    @Override
    public boolean hasPendingBindings() {
        synchronized(this) {
            if (mDirtyFlags != 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        if (BR.refresh == variableId) {
            setRefresh((com.study.jetpackstudykotlin.databinding.bean.Refresh) variable);
        }
        else {
            variableSet = false;
        }
            return variableSet;
    }

    public void setRefresh(@Nullable com.study.jetpackstudykotlin.databinding.bean.Refresh Refresh) {
        this.mRefresh = Refresh;
        synchronized(this) {
            mDirtyFlags |= 0x2L;
        }
        notifyPropertyChanged(BR.refresh);
        super.requestRebind();
    }

    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
            case 0 :
                return onChangeRefreshSwipeRefreshViewRefreshing((androidx.databinding.ObservableBoolean) object, fieldId);
        }
        return false;
    }
    private boolean onChangeRefreshSwipeRefreshViewRefreshing(androidx.databinding.ObservableBoolean RefreshSwipeRefreshViewRefreshing, int fieldId) {
        if (fieldId == BR._all) {
            synchronized(this) {
                    mDirtyFlags |= 0x1L;
            }
            return true;
        }
        return false;
    }

    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        com.study.jetpackstudykotlin.databinding.bean.Refresh refresh = mRefresh;
        boolean refreshSwipeRefreshViewRefreshingGet = false;
        androidx.databinding.ObservableBoolean refreshSwipeRefreshViewRefreshing = null;

        if ((dirtyFlags & 0x7L) != 0) {



                if (refresh != null) {
                    // read refresh.swipeRefreshViewRefreshing
                    refreshSwipeRefreshViewRefreshing = refresh.getSwipeRefreshViewRefreshing();
                }
                updateRegistration(0, refreshSwipeRefreshViewRefreshing);


                if (refreshSwipeRefreshViewRefreshing != null) {
                    // read refresh.swipeRefreshViewRefreshing.get()
                    refreshSwipeRefreshViewRefreshingGet = refreshSwipeRefreshViewRefreshing.get();
                }
        }
        // batch finished
        if ((dirtyFlags & 0x7L) != 0) {
            // api target 1

            com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.setRefreshing(this.srl, refreshSwipeRefreshViewRefreshingGet);
        }
        if ((dirtyFlags & 0x4L) != 0) {
            // api target 1

            com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.setOnRefreshListener(this.srl, srlrefreshingAttrChanged);
        }
    }
    // Listener Stub Implementations
    // callback impls
    // dirty flag
    private  long mDirtyFlags = 0xffffffffffffffffL;
    /* flag mapping
        flag 0 (0x1L): refresh.swipeRefreshViewRefreshing
        flag 1 (0x2L): refresh
        flag 2 (0x3L): null
    flag mapping end*/
    //end
}

三、总结

数据绑定中的注解和kotlin结合使用时总是会报各种各样的异常,目前我还没找到原因,所以我是通过用java来实现这部分代码来解决掉这个问题的。更多数据绑定的使用请看官方文档 数据绑定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值