组件化之路 - ViewBinding基类封装

既然已经对 ViewBinding一知半解 ,那么接下来肯定是要集成到项目中跑起来,所以此篇主讲关于ViewBinding集成在基类的具体方式~

兄弟篇

我看了看网上关于ViewBinding基类集成,一般都是通过反射非反射的方法去集成基类,进行使用的 > <

我自己稍作总结后,得出以下结论,通篇也以此结论进行说明

关于ViewBinding基类集成,主要集成有俩种方式

  • 常规写法,手动通过原始代码封装Base基类,达到基类封装效果,从而运用到自己的项目
  • 三方框架,如加入 ViewBindingKTX 框架,包体积虽有增大,但作者能解决一些自己后续会遇到或忽略的问题 (起初是我朋友推荐,后来在知乎看到了原作者也在推荐)

关于ViewBinding基类集成,主要集成有俩种用法

  • 非反射(不使用反射,常规写法)
  • 反射(如果代码混淆的话,容易出现找不到类的场景)

关于ViewBinding基类集成,主要集成有俩种开发语言

  • Java
  • Kotlin

因为我用Kotlin经验还不足,所以我自己写了一下Java - BaseActivity基类封装 ~

常规集成(不使用反射)

关于ViewBinding基类封装的很多知识,借鉴了此篇 blog 的尾部代码(当然,这类型代码太常见了,至少我看到多篇相似的封装方式,不过一点儿都不影响我的学习热情,加油 ) ~

Java - BaseActivity

这种方式,也是我在项目中使用的方式,经本人亲自尝试,可用 ~ 但要注意ViewBinding在不同场景的使用方式有所不同,此处仅作用于Activity相关组件, 如不懂可前往ViewBinding继续进阶 ~

//基类封装
public abstract class BaseBindingActivity<T extends ViewBinding>  extends AppCompatActivity {
    private T mBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = getViewBinding();
        setContentView(mBinding.getRoot());
    }

    public abstract T getViewBinding();
}

//使用方式
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding.textView.text = "冲刺把,卡布达~"
    }

    @Override
    public ViewBinding getViewBinding() {
        mBinding = ActivityMainBinding.inflate(getLayoutInflater());
        return mBinding;
    }
}
Kotlin - BaseActivity
//基类封装
abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
    private lateinit var _binding: T
    protected val binding get() = _binding;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = getViewBinding()
        setContentView(_binding.root)
    }

    protected abstract fun getViewBinding(): T
}

//使用方式
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.textView.text = "这是MainActivity"
    }

    override fun getViewBinding() = ActivityMainBinding.inflate(layoutInflater)
}
Kotlin - BaseFragment
//基类封装
abstract class BaseFragment<T : ViewBinding> : Fragment() {
    private lateinit var _binding: T
    protected val binding get() = _binding;
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = getViewBinding(inflater, container)
        return _binding.root
    }
    
    protected abstract fun getViewBinding(inflater: LayoutInflater, container: ViewGroup?): T
}

//使用方式
class FirstFragment : BaseFragment<FragmentFirstBinding>() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.textView.text = "这是FirstFragment"
    }

    override fun getViewBinding(
        inflater: LayoutInflater,
        container: ViewGroup?
    ) = FragmentFirstBinding.inflate(inflater, container, false)
}

反射集成

不推荐使用,会有混淆问题

Java - BaseActivity
//基类封装
public class BaseActivity<T extends ViewBinding> extends AppCompatActivity {
  protected T viewBinding;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
      Class cls = (Class) type.getActualTypeArguments()[0];
      try {
          Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class);
          viewBinding = (T) inflate.invoke(null, getLayoutInflater());
          setContentView(viewBinding.getRoot());
      } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
          e.printStackTrace();
      }
  }
}

//使用方式
public class MainActivity extends BaseActivity<ActivityMainBinding> {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewBinding.button.setText("这是 MainActivity ViewBinding");
        viewBinding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d("MainView","点击按钮");
            }
        });
    }
}
Java - BaseFragment
//基类封装
public class BaseFragment<T extends ViewBinding> extends Fragment {
    protected T viewBinding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
        Class cls = (Class) type.getActualTypeArguments()[0];
        try {
            Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            viewBinding = (T) inflate.invoke(null, inflater, container, false);
        }  catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
            e.printStackTrace();
        }
        return viewBinding.getRoot();
    }
}

//使用方式
public class MainFragment extends BaseFragment<FragmentMainBinding>{
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        viewBinding.button.setText("这是 MainFragment ViewBinding");
        viewBinding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d("MainView","点击按钮");
            }
        });
    }
}
Kotlin - BaseActivity
//基类封装
open class BaseActivity<T : ViewBinding> : AppCompatActivity() {
    protected lateinit var binding: T
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val type = javaClass.genericSuperclass as ParameterizedType
        val aClass = type.actualTypeArguments[0] as Class<*>
        val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
        binding = method.invoke(null, layoutInflater) as T
        setContentView(binding.root)
    }
}

//使用方式
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.textView.text = "这是MainActivity"
    }
}
Kotlin - BaseFragment
//基类封装
open class BaseFragment<T:ViewBinding>:Fragment(){
    lateinit var binding: T
    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 T
        return binding.root
    }
}

//使用方式
class FirstFragment : BaseFragment<FragmentFirstBinding>() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.textView.text = "这是FirstFragment"
    }
}

三方框架

这里使用的主要是 ViewBindingKTX 框架,此处仅介绍简单的使用方式,如有具体需求,可前往原作者的 Github ~

以下部分基本都是copy的原作者,实属无聊,权当记录把...

Feature
  • 支持 Kotlin 和 Java 用法
  • 支持多种使用反射和不使用反射的用法
  • 支持封装改造自己的基类,使其用上 ViewBinding
  • 支持 BaseRecyclerViewAdapterHelper
  • 支持 Activity、Fragment、Dialog、Adapter
  • 支持在 Fragment 自动释放绑定类的实例对象
  • 支持实现自定义组合控件
  • 支持 TabLayout 实现自定义标签布局
  • 支持 NavigationView 设置头部控件
  • 支持 DataBinding 自动设置 lifecycleOwner
基础配置

build(project)

allprojects {
    repositories {
        ...
        maven { url 'https://www.jitpack.io' }
    }
}

build(app)

android {
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    // 以下都是可选,请根据需要进行添加
    implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-ktx:1.2.4'
    implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-nonreflection-ktx:1.2.4'
    implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:1.2.4'
    implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-brvah:1.2.4'
}
Java改造基类

因对于Kotlin还不熟,所以仅copy - Java改造基类做个记录,有需要看Ktolin改造基类的话, 直接跳这里看Ktolin封装的基类把 ~

不使用反射

Activity

public abstract class BaseBindingActivity<VB extends ViewBinding> extends AppCompatActivity {

  private VB binding;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = onCreateViewBinding(getLayoutInflater());
    setContentView(binding.getRoot());
  }

  protected abstract VB onCreateViewBinding(@NonNull LayoutInflater layoutInflater);

  public VB getBinding() {
    return binding;
  }
}

//使用方式
public class MainActivity extends BaseBindingActivity<ActivityMainBinding> {
  @Override
  protected ActivityMainBinding onCreateViewBinding(@NonNull LayoutInflater layoutInflater) {
    return ActivityMainBinding.inflate(layoutInflater);
  }
    
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getBinding().getTvHelloWord().setText("Hello Android!");
  }
}

Fragment

public abstract class BaseBindingFragment<VB extends ViewBinding> extends Fragment {

  private VB binding;

  @Nullable
  @Override
  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    binding = onCreateViewBinding(inflater, container);
    return binding.getRoot();
  }

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

  public VB getBinding() {
    return binding;
  }

  protected abstract VB onCreateViewBinding(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent);
}

//使用方式
public class HomeFragment extends BaseBindingFragment<FragmentHomeBinding> {
  @Override
  protected FragmentHomeBinding onCreateViewBinding(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent) {
    return FragmentHomeBinding.inflate(inflater, parent, false);
  }

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getBinding().getTvHelloWord().setText("Hello Android!");
  }
}

Adapter

public abstract class BaseBindingQuickAdapter<T, VB extends ViewBinding>
    extends BaseQuickAdapter<T, BaseBindingQuickAdapter.BaseBindingHolder> {

  public BaseBindingQuickAdapter() {
    this(-1);
  }

  public BaseBindingQuickAdapter(@LayoutRes int layoutResId) {
    super(-layoutResId);
  }

  @NotNull
  @Override
  protected BaseBindingHolder onCreateDefViewHolder(@NotNull ViewGroup parent, int viewType) {
    return new BaseBindingHolder(onCreateViewBinding(LayoutInflater.from(parent.getContext()), parent));
  }

  protected abstract VB onCreateViewBinding(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent);

  public static class BaseBindingHolder extends BaseViewHolder {

    private final ViewBinding binding;

    public BaseBindingHolder(@NotNull View view) {
      this(() -> view);
    }

    public BaseBindingHolder(@NotNull ViewBinding binding) {
      super(binding.getRoot());
      this.binding = binding;
    }

    @NonNull
    @SuppressWarnings("unchecked")
    public <VB extends ViewBinding> VB getViewBinding() {
      return (VB) binding;
    }
  }
}

//使用方式
public class FooAdapter extends BaseBindingQuickAdapter<Foo, ItemFooBinding> {
  @Override
  protected ItemFooBinding onCreateViewBinding(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
    return ItemFooBinding.inflate(inflater, parent, false);
  }

  @Override
  protected void convert(@NotNull BaseBindingHolder holder, Foo item) {
    ItemFooBinding binding = holder.getViewBinding();
    binding.tvFoo.setText(item.getValue());
  }
}

MultiType

public abstract class BindingViewDelegate<T, VB extends ViewBinding> extends
    ItemViewDelegate<T, BindingViewDelegate.BindingViewHolder<VB>> {
  @NotNull
  @Override
  public BindingViewHolder<VB> onCreateViewHolder(@NotNull Context context, @NotNull ViewGroup parent) {
    return new BindingViewHolder<>(onCreateViewBinding(LayoutInflater.from(parent.getContext()), parent));
  }

  protected abstract VB onCreateViewBinding(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent);

  public static class BindingViewHolder<VB extends ViewBinding> extends RecyclerView.ViewHolder {

    private final VB binding;

    public BindingViewHolder(@NonNull VB binding) {
      super(binding.getRoot());
      this.binding = binding;
    }

    @NonNull
    public VB getBinding() {
      return binding;
    }
  }
}

//使用方式
public class FooViewDelegate extends BindingViewDelegate<Foo, ItemFooBinding> {
  @Override
  protected ItemFooBinding onCreateViewBinding(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
    return ItemFooBinding.inflate(inflater, parent, false);
  }

  @Override
  public void onBindViewHolder(@NotNull BindingViewHolder<ItemFooBinding> holder, Foo foo) {
    holder.getBinding().tvFoo.setText(item.getValue());
  }
}
反射

Activity

public abstract class BaseBindingActivity<VB extends ViewBinding> extends AppCompatActivity {

  private VB binding;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ViewBindingUtil.inflateWithGeneric(this, getLayoutInflater());
    setContentView(binding.getRoot());
  }

  public VB getBinding() {
    return binding;
  }
}

//使用方式
public class MainActivity extends BaseBindingActivity<ActivityMainBinding>{

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getBinding().getTvHelloWord().setText("Hello Android!");
  }
}

Fragment

public abstract class BaseBindingFragment<VB extends ViewBinding> extends Fragment {

  private VB binding;

  @Nullable
  @Override
  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    binding = ViewBindingUtil.inflateWithGeneric(this, getLayoutInflater(), container, false);
    return binding.getRoot();
  }

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

  public VB getBinding() {
    return binding;
  }
}

//使用方式
class HomeFragment extends BaseBindingFragment<FragmentHomeBinding> {

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getBinding().tvHelloWorld.setText("Hello Android!");
  }
}

Adapter

public abstract class BaseBindingQuickAdapter<T, VB extends ViewBinding>
    extends BaseQuickAdapter<T, BaseBindingQuickAdapter.BaseBindingHolder> {

  public BaseBindingQuickAdapter() {
    this(-1);
  }

  public BaseBindingQuickAdapter(@LayoutRes int layoutResId) {
    super(layoutResId);
  }

  @NotNull
  @Override
  protected BaseBindingHolder onCreateDefViewHolder(@NotNull ViewGroup parent, int viewType) {
    VB viewBinding = ViewBindingUtil.inflateWithGeneric(this, parent);
    return new BaseBindingHolder(viewBinding);
  }

  public static class BaseBindingHolder extends BaseViewHolder {

    private final ViewBinding binding;

    public BaseBindingHolder(@NotNull View view) {
      this(() -> view);
    }

    public BaseBindingHolder(@NotNull ViewBinding binding) {
      super(binding.getRoot());
      this.binding = binding;
    }

    @NonNull
    @SuppressWarnings("unchecked")
    public <VB extends ViewBinding> VB getViewBinding() {
      return (VB) binding;
    }
  }
}

//使用方式
class FooAdapter extends BaseBindingQuickAdapter<Foo, ItemFooBinding> {

  @Override
  public void convert(@NotNull BindingViewHolder<ItemFooBinding> holder, Foo item) {
    ItemFooBinding binding = holder.getViewBinding();
    binding.tvFoo.setText(item.getValue());
  }
}

MultiType

public abstract class BindingViewDelegate<T, VB extends ViewBinding> extends
    ItemViewDelegate<T, BindingViewDelegate.BindingViewHolder<VB>> {
  @NotNull
  @Override
  public BindingViewHolder<VB> onCreateViewHolder(@NotNull Context context, @NotNull ViewGroup parent) {
    return new BindingViewHolder<>(ViewBindingUtil.inflateWithGeneric(this, parent));
  }

  public static class BindingViewHolder<VB extends ViewBinding> extends RecyclerView.ViewHolder {

    private final VB binding;

    public BindingViewHolder(@NonNull VB binding) {
      super(binding.getRoot());
      this.binding = binding;
    }

    @NonNull
    public VB getBinding() {
      return binding;
    }
  }
}

//使用方式
class FooViewDelegate extends BindingViewDelegate<Foo, ItemFooBinding> {

  @Override
  public void onBindViewHolder(@NotNull BindingViewHolder<ItemFooBinding> holder, Foo item) {
    holder.getBinding().tvFoo.setText(item.getValue());
  }
}
  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
基类是一种特殊的继承方式,用于解决多继承中的菱形继承问题。在虚基类中,基类的成员变量只会被派生类的最顶层的基类所共享,从而避免了菱形继承中的二义性和数据冗余问题。 在人与教师学生的例子中,可以用虚基类来解决多继承带来的问题。首先,定义一个人类作为基类,然后定义一个教师类和一个学生类,它们都继承自人类。由于教师和学生都是人,因此它们都有一些共同的属性和方法,比如姓名、年龄、性别等等。 现在假设我们需要定义一个既是教师又是学生的类,即一个人既可以教书又可以学习。如果采用普通的多继承方式,会出现两个人类的实例被创建,从而导致数据冗余和方法二义性的问题。为了解决这个问题,我们可以将人类定义为虚基类,这样在派生类中只会创建一个人类的实例,从而避免了数据冗余和方法二义性的问题。 下面是一个示例代码: ```c++ #include <iostream> #include <string> using namespace std; class Person { public: Person(string name, int age, string gender) : m_name(name), m_age(age), m_gender(gender) { } void showInfo() { cout << "姓名:" << m_name << endl; cout << "年龄:" << m_age << endl; cout << "性别:" << m_gender << endl; } protected: string m_name; int m_age; string m_gender; }; class Teacher : virtual public Person { public: Teacher(string name, int age, string gender, string course) : Person(name, age, gender), m_course(course) { } void teach() { cout << m_name << "正在教授" << m_course << "课程" << endl; } protected: string m_course; }; class Student : virtual public Person { public: Student(string name, int age, string gender, string major) : Person(name, age, gender), m_major(major) { } void study() { cout << m_name << "正在学习" << m_major << "专业" << endl; } protected: string m_major; }; class TeacherStudent : public Teacher, public Student { public: TeacherStudent(string name, int age, string gender, string course, string major) : Person(name, age, gender), Teacher(name, age, gender, course), Student(name, age, gender, major) { } void showInfo() { cout << "教师学生的信息如下:" << endl; Person::showInfo(); cout << "授课科目:" << m_course << endl; cout << "所学专业:" << m_major << endl; } }; int main() { Teacher teacher("张三", 35, "男", "数学"); teacher.showInfo(); teacher.teach(); cout << endl; Student student("李四", 20, "女", "计算机科学"); student.showInfo(); student.study(); cout << endl; TeacherStudent ts("王五", 28, "男", "英语", "经济管理"); ts.showInfo(); ts.teach(); ts.study(); return 0; } ``` 在这个示例代码中,Person类被定义为虚基类,同时Teacher和Student类都继承自Person类,并且都采用虚继承方式。在TeacherStudent类中,通过调用Person、Teacher和Student类的构造函数来初始基类成员变量。需要注意的是,由于Person类是虚基类,因此在构造函数中不需要对其进行初始,该工作由最顶层的派生类(即TeacherStudent类)来完成。同时,在TeacherStudent类中,需要调用Person类的showInfo()函数来显示人的信息,其他的函数则通过调用Teacher和Student类的函数来实现。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远方那座山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值