KotlinAndroid技术知识Android开发

02 Jetpack-ViewBinding

2021-11-22  本文已影响0人  凤邪摩羯

1 前言

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

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。

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) {

            }
        });
    }
}
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");
    }
}
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");
    }
}
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)

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 ……
      
    }
 
}
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 ……
    }
}
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有多层继承关系,需要将该方式定义在最底层
上一篇下一篇

猜你喜欢

热点阅读