02 Jetpack-ViewBinding

作者: 凤邪摩羯 | 来源:发表于2021-11-22 09:16 被阅读0次

    1 前言

    在Android开发,代码里获取View一般是使用findViewById()获取目标布局文件里的指定View。但是这样使用会有大量代码重复工作并且有空指针危险。为了减少重复工作有很多大神都八仙过海各显神通,但是这些神通多多少少都有缺点。

    • 大名鼎鼎的黄油刀bufferknife,缺点增加了编译速度(因为原理是它需要生成一份对应查找View的代码),并且需要时刻更新最新版本否则AndroidStudio更新后可能会出现无法编译的问题。(另外bufferknife与ViewBinding是冲突的)
    • DataBinding,缺点更明显,需要更多的xml编写工作量,并且一不小心会延伸到一些邪恶的用法,那就是在xml写逻辑判断,甚至在xml增加一些业务功能。这对代码维护是恐怖的,因为xml逻辑的可读性可比纯Java代码差多了。并且如果混乱到2头都写逻辑判断,维护起来十分痛苦。
    • AndroidStudio的插件功能自动生成代码,比如LayoutCreator,减少了工作量但是并没有减少代码的冗余,代码看起来一样是不简洁的。

    google在AndroidStudio 3.6 版本后推出了ViewBinding,一方面可以让代码更加简洁并且提高编译速度防止空指针。另一方面AndroidStudio是支持ViewBinding进行关联互动的,所以让你在Java代码与xml之间的跳转更方便。

    2 前提条件

    AndroidStudio 需要更新到3.6版本以上。

    在build.gradle文件里增加下面的代码,开启viewBinding

    android {
        //略...
    
        buildFeatures{
            viewBinding = true
        }
    
    }
    

    3 各处简单的使用Demo

    首先你需要知道一个关键点,在启用ViewBinding后。每一个layout文件都会自动生成一份Java类。它会自动根据下划线进行驼峰命名。比如一个叫 activity_mian_demo.xml 的布局文件,它对应自动生成的类叫ActivityMianDemoBinding。这就意味着我们可以在任何需要导入布局的地方都使用ViewBinding。

    • Activity里:
    public class MainActivity extends AppCompatActivity {
        private ActivityMianDemoBinding mBinding;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = ActivityMianDemoBinding.inflate(getLayoutInflater());
            setContentView(mBinding.getRoot());
            mBinding.btn1.setText("这是按键1");
            mBinding.btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                }
            });
        }
    }
    
    • Fragment里:
    public class FragmentDemo extends Fragment {
        private FragmentDemoBinding mBinding;
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            mBinding = FragmentDemoBinding.inflate(getLayoutInflater());
            return mBinding.getRoot();
        }
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mBinding.textView.setText("textView");
        }
    }
    
    • 在Dialog里:
    public class DemoDialog extends Dialog {
        private DialogDemoBinding mBinding;
        public DemoDialog(@NonNull Context context) {
            super(context);
            mBinding = DialogDemoBinding.inflate(getLayoutInflater());
            setContentView(mBinding.getRoot());
            mBinding.textView.setText("hello");
        }
    }
    
    • Adapter里:
    public class DemoAdapter extends RecyclerView.Adapter<DemoAdapter.ViewHolder> {
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new ViewHolder(ItemDemoBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        }
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.binding.textView2.setText("demo");
    
        }
        @Override
        public int getItemCount() {
            return 0;
        }
        public static class ViewHolder extends RecyclerView.ViewHolder {
            ItemDemoBinding binding;
            public ViewHolder(@NonNull ItemDemoBinding itemDemoBinding) {
                super(itemDemoBinding.getRoot());
                this.binding = itemDemoBinding;
            }
        }
    }
    

    4 ViewBinding封装基类(BaseActivity,BaseFragment)

    • BaseActivity:
    public class BaseActivity<T extends ViewBinding> extends AppCompatActivity {
        protected T binding;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Type superclass = getClass().getGenericSuperclass();
            Class<?> aClass = (Class<?>) ((ParameterizedType) superclass).getActualTypeArguments()[0];
            try {
                Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class);
                binding = (T) method.invoke(null, getLayoutInflater());
                setContentView(binding.getRoot());
            } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 使用
    public class MainActivity extends BaseActivity<ActivityMainBinding> {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // binding.button1 ……
          
        }
     
    }
    
    • BaseFragment
    public class BaseFragment<T extends ViewBinding> extends Fragment {
        protected T binding;
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            Type superclass = getClass().getGenericSuperclass();
            Class<?> aClass = (Class<?>) ((ParameterizedType) superclass).getActualTypeArguments()[0];
            try {
                Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class,ViewGroup.class,boolean.class);
                binding = (T) method.invoke(null, getLayoutInflater(),container,false);
            } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
                e.printStackTrace();
            }
            return binding.getRoot();
        }
    }
    
    • 使用
    public class BlankFragment extends BaseFragment<FragmentBlankBinding> {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //binding.textView ……
        }
    }
    
    • kotlin写法
    open class BaseActivity<VB:ViewBinding> :AppCompatActivity() {
        protected val binding: VB by lazy {
            //使用反射得到viewbinding的class
            val type = javaClass.genericSuperclass as ParameterizedType
            val aClass = type.actualTypeArguments[0] as Class<*>
            val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
            method.invoke(null, layoutInflater) as VB
        }
     
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(binding.root)
        }
    }
     
    open class BaseFragment<VB:ViewBinding>:Fragment(){
     
        lateinit var binding: VB
     
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            val type = javaClass.genericSuperclass as ParameterizedType
            val aClass = type.actualTypeArguments[0] as Class<*>
            val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java)
            binding = method.invoke(null,layoutInflater,container,false) as VB
            return binding.root
        }
    }
    
    • 注意事项
    1. 这样方式定义的基类调用时候,只能是直属父类
    2. 如果BaseActivity有多层继承关系,需要将该方式定义在最底层

    相关文章

      网友评论

        本文标题:02 Jetpack-ViewBinding

        本文链接:https://www.haomeiwen.com/subject/tjdxvktx.html