Android Jetpack 之 ViewBinding

Android Jetpack 之 ViewBinding

1.初识ViewBinding

要求:Android Studio必须是3.6 Canary 11以及更高的版本才能使用

作用:View Binding是一项功能,使您可以更轻松地编写与视图交互的代码。在模块中启用视图绑定后,它将为该模块中存在的每个XML布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有ID的所有视图的直接引用。

像ButterKnife、Android Kotlin extensions一样都是为了简化findViewById

Jake Wharton 也在 Butter Knife开源库中添加了如下一句话:

Attention: Development on this tool is winding down. Please consider switching to view binding in the coming months.

想必 ViewBinding 在未来的地位和作用将不言而喻了吧。

2.使用

2.1 开启

修改build.gradle
// Android Studio 3.6.0
android {
    ...
    viewBinding {
        enabled = true
    }
}

在 Android Studio 4.0 中,viewBinding 将被变成属性整合到了buildFeatures 选项中,配置要改成:

// Android Studio 4.0
android {
 buildFeatures {
 	viewBinding = true
 }
}

2.2 具体使用

修改java代码
一、Activity中使用

如果你的布局文件是activity_main.xml,则会生成一个ActivityMainBinding的类,如果你的布局文件是result_profile.xml,则会生成一个ResultProfileBinding的类,以此类推。

下面以activity_main.xml及其对应的MainActivity.java为例说明:

假设activity_main.xml放置了三个控件:TextView(Id为text)、Button(Id为button)、ImageView(没有设置Id),其中ImageView因为没有设置Id,因此绑定类中不存在对它的引用,所以在代码中无法被引用。

MainActivity.java的部分代码如下:

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 	super.onCreate(savedInstanceState);
	// setContentView(R.layout.activity_main);
	LayoutInflater layoutInflater = LayoutInflater.from(this);
 	ActivityMainBinding binding = ActivityMainBinding.inflate(layoutInflater);
 	setContentView(binding.getRoot());

 	binding.text.setText("文字已变化");
 	binding.button.setOnClickListener(new View.OnClickListener() {
  		@Override
  		public void onClick(View v) {
  			Toast.makeText(getApplicationContext(), "Button被点击", Toast.LENGTH_SHORT).show();
  		}
 	});
 }

在获取布局的时候,如下这样写,更是官方文档中推荐的

//使用ViewBinding后的方法
mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());

注意事项

注意:原先的setContentView(R.layout.activity_main)需要注释掉,否则会重复设置ContentView。
布局的根视图(activity_main.xml)会自动生成一个名为 rootView 的成员变量。在 Activity 的 onCreate()方法中,要将 rootView传入 setContentView()方法,从而让 Activity 可以使用绑定对象中的布局,rootView是私有变量,需要使用getRoot()方法拿到。

二、Fragment中使用
public class BaseFragment extends Fragment {

    private Activity mActivity;
    private FrgamentBaseBinding mBind;
    private TextView mTv;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mActivity = (Activity) context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mBind = FrgamentBaseBinding.inflate(inflater, container, false);
        View root = mBind.getRoot();
        //View root = inflater.inflate(R.layout.frgament_base, container, false);
        return root;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mTv = mBind.frgamentTv;
        mBind.frgamentBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mActivity, "hello i am fragment btn", Toast.LENGTH_SHORT).show();
                mTv.setText("click fragment btn~~~");
            }
        });

        mBind.frgamentTv.setText("hello i am fragment tv");

    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mBind = null;
    }
}

注意:Fragment 的存在时间比其视图长。请务必在 Fragment 的 onDestroyView() 方法中清除对绑定类实例的所有引用。

三、在布局中使用include,但是根布局不是Merge

include填充的布局如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container_include"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_include"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="这就是测试啊" />

</RelativeLayout>

activity_test_include.xml引用这个布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".TestIncludeActivity">

    <TextView
        android:id="@+id/include_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试include" />
    <!-- 1.测试include -->
     <include
         android:id="@+id/include_include"
         layout="@layout/include_item" />

</LinearLayout>

Java代码

public class TestIncludeActivity extends AppCompatActivity {

    private ActivityTestIncludeBinding mBind;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBind = ActivityTestIncludeBinding.inflate(getLayoutInflater());
        setContentView(mBind.getRoot());
        mBind.includeTv.setText("呵呵,为了测试include");
        //1.不给这个布局中的include增加id,include的xml文件中增加id。答案是获取不到 填充部分的view

        //2.给这个布局中的include增加id,include的xml文件中增加id。答案是没问题的
        mBind.includeInclude.containerInclude.setBackgroundColor(Color.RED);
        mBind.includeInclude.tvInclude.setText("hello");

        //3.给这个布局中的include增加id,不给include的xml文件中的根布局增加id。答案是没问题的
    }
}
说明
include:如果填充的布局不是merge,那么include的id必须要加,否则就不能获取到填充布局中的控件id。
控件中的根布局id也是可以加的,能获取到。可以通过id设置背景颜色等
四、在布局中使用include,但是根布局是Merge

include填充的布局如下

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container_include"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_include"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="这就是测试啊" />

</merge>

activity_test_include.xml引用这个布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".TestIncludeActivity">

    <TextView
        android:id="@+id/include_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试include" />

    <!-- 2.测试merge和include,这里一定不能有id -->
    <include
        layout="@layout/include_item" />

</LinearLayout>

Java代码

public class TestIncludeActivity extends AppCompatActivity {

    private ActivityTestIncludeBinding mBind;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBind = ActivityTestIncludeBinding.inflate(getLayoutInflater());
        setContentView(mBind.getRoot());
        mBind.includeTv.setText("呵呵,为了测试include");

        //4.将include的xml文件的根布局改成merge,测试下有没有问题。这里是RelativeLayout改成Merge
        IncludeItemBinding binding = IncludeItemBinding.bind(mBind.getRoot());
        binding.tvInclude.setText("这就不会出现问题了吧");
        //无法获取到根布局。。。
    }
}
说明
merge:merge xml文件中的根布局id可以加,但是获取不到,没有什么意义!
如果include中引用merge,但是有id。会报如下异常
java.lang.NullPointerException: Missing required view with ID: com.example.viewbinding:id/i1
如果想要获取到Merge中的控件,只能通过IncludeItemBinding.bind(mBind.getRoot());   然后在操作想要的控件
五、自定义Dialog中使用ViewBinding

创建简单的自定义Dialog

public class TestCusDialogActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_cus_dialog);
    }

    public void onClick(View view) {
        MyDialog dialog = new MyDialog(this, R.style.AppTheme);
        dialog.show();
    }
}

Java代码中使用,我在activity布局中忽略了view bind。如果不想用view bind的布局一定记得要忽略!!!

public class TestCusDialogActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_cus_dialog);
    }

    public void onClick(View view) {
        MyDialog dialog = new MyDialog(this, R.style.AppTheme);
        dialog.show();
    }
}
六、自定义View中使用ViewBinding
(1)使用的layout文件不包含merge

cus_view_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="这是自定义布局"
        android:textSize="50sp" />

</androidx.constraintlayout.widget.ConstraintLayout>

创建的自定义LinearLayout

/***
 * 创建时间:2020/8/29 20:55
 * 创建人:10850
 * 功能描述:自定义view
 * 1.使用的layout文件不包含merge
 * init1、2、3、4是使用inflate来导入layout布局的写法,全部可以正常显示自定义的布局。
 * init10、11、12是使用ViewBinding的写法,10无法正常显示视图,11和12是两种不同的写法,道理一样。
 */
public class MyLinearLayout extends LinearLayout {

    public MyLinearLayout(Context context) {
        this(context, null);
    }

    public MyLinearLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

//        init1();
//        init2();
//        init3();
//        init4();

        //11、12都是可以的
        //10的位置就偏离中心了
        init12();
    }

    private void init1() {
        inflate(getContext(), R.layout.cus_view_layout, this);
    }

    private void init2() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_layout, this);
    }

    //和init2()方法相等
    private void init3() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_layout, this, true);
    }

    private void init4() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_layout, this, false);
        addView(view);
    }

    //视图异常,布局无法填充满
    private void init10() {
        CusViewLayoutBinding binding = CusViewLayoutBinding.inflate(LayoutInflater.from(getContext()));
        addView(binding.getRoot());
    }

    private void init11() {
        CusViewLayoutBinding binding = CusViewLayoutBinding.inflate(LayoutInflater.from(getContext()), this, true);
    }

    private void init12() {
        CusViewLayoutBinding binding = CusViewLayoutBinding.inflate(LayoutInflater.from(getContext()), this, false);
        addView(binding.getRoot());
    }
}
(2)使用的layout文件根标签为merge

cus_view_merge.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="这是自定义merge"
        android:textSize="50sp" />
</merge>

创建的自定义LinearLayout

/***
 * 创建时间:2020/8/29 20:55
 * 创建人:10850
 * 功能描述:自定义view
 * 1.使用的layout文件不包含merge
 * init1、2、3、4是使用inflate来导入layout布局的写法,全部可以正常显示自定义的布局。
 * init10、11、12是使用ViewBinding的写法,10无法正常显示视图,11和12是两种不同的写法,道理一样。
 * 2.使用的layout文件根标签为merge
 *
 */
public class MegeLinearLayout extends LinearLayout {

    public MegeLinearLayout(Context context) {
        this(context, null);
    }

    public MegeLinearLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MegeLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

//        init1();
//        init2();
//        init3();
//        init4();

        //21没效果 20是正常的
        init20();
    }

    private void init1() {
        inflate(getContext(), R.layout.cus_view_merge, this);
    }

    private void init2() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_merge, this);
    }

    //和init2()方法相等
    private void init3() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_merge, this, true);
    }

    private void init4() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.cus_view_merge, this, false);
        addView(view);
    }

    private void init20() {
        CusViewMergeBinding binding = CusViewMergeBinding.inflate(LayoutInflater.from(getContext()), this);
    }

    //没有效果,可以理解为还没有rootView
    private void init21() {
        CusViewMergeBinding binding = CusViewMergeBinding.bind(this);
    }
}
(3)使用

activity_test_cus_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:viewBindingIgnore="true"
    android:orientation="vertical"
    tools:context=".TestCusViewActivity">

    <com.example.viewbinding.MyLinearLayout
        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.example.viewbinding.MegeLinearLayout
        android:background="@color/colorAccent"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>
七、Adapter中使用ViewBinding
(1)正常下实现的rv

TestRvActivity.class

public class TestRvActivity extends AppCompatActivity {

    private RecyclerView mRv;
    private MyAdapter mAdapter;//适配器
    private List<String> list;//数据集合
    private LinearLayoutManager mLayout;//布局管理器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityTestRvBinding binding = ActivityTestRvBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        mRv = binding.rv;

        initData();//初始化数据
        mAdapter = new MyAdapter(this, list);
        //设置适配器
        mRv.setAdapter(mAdapter);
        //布局有3种 LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager
        mLayout = new LinearLayoutManager(this);
        mRv.setLayoutManager(mLayout);
        //设置Item增加、移除动画
        mRv.setItemAnimator(new DefaultItemAnimator());
        //添加默认分割线
        mRv.addItemDecoration(new DividerItemDecoration(
                this, DividerItemDecoration.VERTICAL));
        //点击和长按事件
        mAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(TestRvActivity.this, ((TextView) view).getText() + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(TestRvActivity.this, position + " Long click", Toast.LENGTH_SHORT).show();
                mAdapter.removeData(position);
                mAdapter.notifyDataSetChanged();
            }
        });
    }

    private void initData() {
        list = new ArrayList<>();
        for (int i = 0; i <= 200; i++) {
            list.add("Item " + i);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_item, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            //增加:在第二个位置增加一个item
            //删除:在第二个位置删掉一个item
            case R.id.add:
                mAdapter.addData(1);
                mAdapter.notifyDataSetChanged();
                break;
            case R.id.delete:
                mAdapter.removeData(1);
                mAdapter.notifyDataSetChanged();
                break;
        }
        return true;
    }
}

其布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TestRvActivity">

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

</RelativeLayout>

MyAdapter.class

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    //数据源
    private List<String> mList;
    private Context mContext;
    private RvItemBinding mBinding;

    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mOnItemClickListener;

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    //构造方法
    public MyAdapter(Context context, List<String> list) {
        this.mList = list;
        this.mContext = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        //View inflate = LayoutInflater.from(mContext).inflate(R.layout.rv_item, viewGroup, false);
        //仿照原来的方式,否则不充满布局
        mBinding = RvItemBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false);
        //这样不行,不能充满布局。不推荐
        //mBinding = RvItemBinding.inflate(LayoutInflater.from(mContext));
        return new ViewHolder(mBinding);
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int i) {
        viewHolder.mTextView.setText(mList.get(i));

//        ViewGroup.LayoutParams layoutParams = viewHolder.mTextView.getLayoutParams();
//        layoutParams.height = new Random().nextInt(200) + 200;
//        viewHolder.mTextView.setLayoutParams(layoutParams);
        //点击事件
        if (mOnItemClickListener != null) {
            viewHolder.mTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = viewHolder.getLayoutPosition();
                    mOnItemClickListener.onItemClick(viewHolder.mTextView, pos);
                }
            });

            viewHolder.mTextView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = viewHolder.getLayoutPosition();
                    mOnItemClickListener.onItemLongClick(viewHolder.mTextView, pos);
                    return false;
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return mList == null ? 0 : mList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        private TextView mTextView;
        private FrameLayout mFrameLayout;

        //1.这里如果使用之前的方式,onCreateViewHolder方法,返回的是new ViewHolder(mBinding.getRoot());即可
        /*public ViewHolder(@NonNull View itemView) {
            super(itemView);
            mTextView = mBinding.rvTextView;
            mFrameLayout = mBinding.rvContainer;
        }*/

        //2.使用如下方式,onCreateViewHolder方法,返回的是new ViewHolder(mBinding);即可
        public ViewHolder(@NonNull RvItemBinding binding) {
            super(binding.getRoot());
            mTextView = binding.rvTextView;
            mFrameLayout = binding.rvContainer;
        }
    }

    //添加item
    public void addData(int position) {
        mList.add(position, "Insert One");
        notifyItemInserted(position);
    }

    //删除item
    public void removeData(int position) {
        mList.remove(position);
        notifyItemRemoved(position);
    }
}

其item布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:id="@+id/rv_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/rv_text_view"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:background="@color/colorAccent"
        android:gravity="center"
        android:text="1"
        android:textSize="20sp" />

</FrameLayout>
(2)使用BaseRecyclerViewAdapterHelper
public class TestRvActivity extends AppCompatActivity {

    private RecyclerView mRv;
    private MyAdapter mAdapter;//适配器
    private List<String> list;//数据集合
    private LinearLayoutManager mLayout;//布局管理器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityTestRvBinding binding = ActivityTestRvBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        mRv = binding.rv;

        initData();//初始化数据

        AAAdapter aaAdapter = new AAAdapter(R.layout.rv_item, list);
        mRv.setAdapter(aaAdapter);
        mLayout = new LinearLayoutManager(this);
        mRv.setLayoutManager(mLayout);
    }

    private void initData() {
        list = new ArrayList<>();
        for (int i = 0; i <= 200; i++) {
            list.add("Item " + i);
        }
    }
}

AAAdapter

public class AAAdapter extends BaseQuickAdapter<String, AAA> {
    public AAAdapter(int layoutResId, @Nullable List<String> data) {
        super(layoutResId, data);
    }

    public AAAdapter(@Nullable List<String> data) {
        super(data);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void convert(@NonNull AAA aaa, String s) {
        aaa.mRvContainer.setBackgroundColor(mContext.getColor(R.color.colorPrimary));
        aaa.mTextView.setText(s + "~");
    }
}

AAA

public class AAA extends BaseViewHolder {

    public FrameLayout mRvContainer;
    public TextView mTextView;

    public AAA(View view) {
        super(view);
        RvItemBinding rvItemBinding = RvItemBinding.bind(view);
        mRvContainer = rvItemBinding.rvContainer;
        mTextView = rvItemBinding.rvTextView;
    }
}

这个看自己的喜好,愿意这么用就这么用,不愿意就算了

3.注意

3.1.忽略View bind功能

如果您希望在生成绑定类时忽略某个布局文件,请将 tools:viewBindingIgnore="true" 属性添加到相应布局文件的根视图中:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
        ...
</LinearLayout>

3.2 布局的问题

使用View bind的时候,需要注意布局的名称。因为生成的Bind类是根据布局来的,这里一定要注意!注意!注意!

3.3 如果Activity中使用fragment的时候使用View bind

上面这种情况,有两种解决方式

(1)Activity也要进行view bind
public class TestFragmentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater layoutInflater = LayoutInflater.from(this);
        ActivityTestFragmentBinding inflate = ActivityTestFragmentBinding.inflate(layoutInflater);
        setContentView(inflate.getRoot());
    }
}
(2)可直接忽略掉,在根布局中添加tools:viewBindingIgnore="true"即可
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:viewBindingIgnore="true">

    <fragment
        android:id="@+id/fragment1"
        android:name="com.zg.jetpackdemo.BaseFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

4.说明

与 findViewById 的区别

与使用 findViewById 相比,视图绑定具有一些很显著的优点:

  • Null 安全:由于视图绑定会创建对视图的直接引用,因此不存在因视图 ID 无效而引发 Null 指针异常的风险。此外,如果视图仅出现在布局的某些配置中,则绑定类中包含其引用的字段会使用 @Nullable 标记。
  • 类型安全:每个绑定类中的字段均具有与它们在 XML 文件中引用的视图相匹配的类型。这意味着不存在发生类转换异常的风险。

这些差异意味着布局和代码之间的不兼容将会导致构建在编译时(而非运行时)失败。

与数据绑定的对比(databinding)

视图绑定和数据绑定均会生成可用于直接引用视图的绑定类。但是,视图绑定旨在处理更简单的用例,与数据绑定相比,具有以下优势:

  • 更快的编译速度:视图绑定不需要处理注释,因此编译时间更短。
  • 易于使用:视图绑定不需要特别标记的 XML 布局文件,因此在应用中采用速度更快。在模块中启用视图绑定后,它会自动应用于该模块的所有布局。

反过来,与数据绑定相比,视图绑定也具有以下限制:

考虑到这些因素,在某些情况下,最好在项目中同时使用视图绑定和数据绑定。您可以在需要高级功能的布局中使用数据绑定,而在不需要高级功能的布局中使用视图绑定。

如何找到生成的java文件?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeNXGFT3-1598758462438)(E:\学习截图\新建文件夹\view_binds.png)]

5.总结

  1. ViewBinding很简单,大体上之前怎么使用的还是怎么使用
  2. 能通过xxbind.inflate()能用getLayoutInflater()的就直接使用,如果不能Inflate()尝试使用bind()
  3. 这个类名称的命名规则为:XML layout文件名去掉下划线,下划线首字母大写,最后加上Binding。例如我有一个layout文件叫activity_main.xml,那对应生成的类文件为ActivityMainBinding.java
  4. 生成的类文件位于Module的build\generated\data_binding_base_class_source_out\debug\out\包名\databinding

6.参考链接:

Android Studio3.6新特性之视图绑定ViewBinding使用指南

中文文档

简单封装

是时候拥抱ViewBinding了!!

秒懂Android开发之ViewBinding,一代神器ButterKnife的终结者

上面的这些链接可以看看。

如果有问题,欢迎指出!谢谢~~~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值