浅笑博客
浅笑博客
Android开发常用Base类的设计与使用
Android开发常用Base类的设计与使用

Java有很多优秀的特性,如继承、泛型、反射等,如何将其在实际场景中很好的应用,是考验一个Java程序员对Java的理解程度有多深。

Android开发中,例如我们很多时候会用到Activity、Fragment、Dialog、Adapter等,但每次总是基础的去使用,无疑是一个不好的选择。我们可以结合Java的优秀特性,做一些抽象封装,方便我们使用的同时,也是程序员优雅开发代码的表现。

下面分享由我在实际开发过程中,结合Java特性以及Andorid 视图自己设计使用的一些基类:

在这里,补充一下Android的视图绑定,它可以方便的将您的xml布局文件生成绑定类,其包含了布局中所有具有ID视图的引用,免去您每次获取控件还需要findVideById的烦恼,使用起来非常地方便。

使用时需在Gradle配置中开启:

android{
    ……
    buildFeatures {
        viewBinding true
    }
}

特别注意:ViewBinding仅支持AS 3.6+及Gradle3.6+版本使用。

BaseActivity

/**
 * 通用视图绑定Activity抽象基类
 *
 * @param <T> ViewBinding
 * @author QianXiao
 * @Date 2021/12/24
 */
public abstract class BaseActivity<T extends ViewBinding> extends AppCompatActivity {
    protected Context context;
    protected T binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        binding = getBinding();
        assert binding != null;
        setContentView(binding.getRoot());
        initListener();
        initData();
    }

    @SuppressWarnings("unchecked")
    private T getBinding() {
        try {
            Class<T> tClass = (Class<T>) ((ParameterizedType) Objects.requireNonNull(getClass().getGenericSuperclass())).getActualTypeArguments()[0];
            Method method = tClass.getMethod("inflate", LayoutInflater.class);
            return (T) method.invoke(null, getLayoutInflater());
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
            LogUtils.e(e.toString());
            return null;
        }
    }

    /**
     * initListener
     */
    protected abstract void initListener();

    /**
     * initData
     */
    protected abstract void initData();
}

其封装了Context对象和ViewBinding对象,内部使用反射完成Bindind初始化并设置页面布局,使用如下图:

public class MainActivity extends BaseActivity<ActivityMainBinding> {
    @Override
    protected void initListener() {
        // Todo
    }

    @Override
    protected void initData() {
        // Todo
    }
}

下同。

BaseFragment

/**
 * 通用视图绑定Fragment抽象基类
 *
 * @Author QianXiao
 * @Date 2021/12/27
 */
public abstract class BaseFragment<T extends ViewBinding> extends Fragment {
    protected T binding;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = getBinding();
        assert binding != null;
        initListener();
        initData();
        return binding.getRoot();
    }

    /**
     * initListener
     */
    protected abstract void initListener();

    /**
     * initData
     */
    protected abstract void initData();

    @SuppressWarnings("unchecked")
    private T getBinding() {
        try {
            Class<T> tClass = (Class<T>) ((ParameterizedType) Objects.requireNonNull(getClass().getGenericSuperclass())).getActualTypeArguments()[0];
            Method method = tClass.getMethod("inflate", LayoutInflater.class);
            return (T) method.invoke(null, getLayoutInflater());
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
            LogUtils.e(e.toString());
            return null;
        }
    }
}

BaseAlertDialog

/**
 * Create by QianXiao
 * On 2021/4/6
 */
public abstract class BaseAlertDialog<T extends ViewBinding> extends AlertDialog {
    protected Context context;
    protected View view;
    protected T binding;

    public BaseAlertDialog(@NonNull Context context) {
        super(context);
        this.context = context;
        Objects.requireNonNull(getWindow()).requestFeature(Window.FEATURE_NO_TITLE);
        ColorDrawable dw = new ColorDrawable(0x00000000);
        getWindow().setBackgroundDrawable(dw);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = getBinding();
        assert binding != null;
        view = binding.getRoot();
        setContentView(view);
        initListener();
        initData();
    }

    @SuppressWarnings("unchecked")
    private T getBinding() {
        try {
            Class<T> tClass = (Class<T>) ((ParameterizedType) Objects.requireNonNull(getClass().getGenericSuperclass())).getActualTypeArguments()[0];
            Method method = tClass.getMethod("inflate", LayoutInflater.class);
            return (T) method.invoke(null, getLayoutInflater());
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
            LogUtils.e(e.toString());
            return null;
        }
    }

    /**
     * initListener
     */
    protected abstract void initListener();

    /**
     * initData
     */
    protected abstract void initData();
}

BaseRecycleViewHolder

开发过程中,往往少不了RecycleView列表显示的需求,因此设计一个 方便的BaseAdapter,才能更高效、优雅的开发代码。 这里首先说的BaseRecycleViewHolder是用来支撑BaseAdapter而设计的,因为每个ItemView结合视图绑定才会使用更加方便。

/**
 * Create by QianXiao
 * On 2021/4/6
 *
 * @author QianXiao
 */
public abstract class BaseRecycleViewHolder<T extends ViewBinding> extends RecyclerView.ViewHolder {
    protected View view;
    public T binding;

    public BaseRecycleViewHolder(@NonNull View itemView) {
        super(itemView);
        this.view = itemView;
        binding = getBinding();
    }

    @SuppressWarnings("unchecked")
    protected T getBinding() {
        try {
            Class<T> tClass = (Class<T>) ((ParameterizedType) Objects.requireNonNull(getClass().getGenericSuperclass())).getActualTypeArguments()[0];
            Method method = tClass.getMethod("bind", View.class);
            return (T) method.invoke(null, view);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
    }
}

BaseAdapter

该抽象类的设计上相对比较复杂,因为其在Base类中完成了泛型ViewHolder的反射实例化。当然这种实现需要将ViewHolder类独立出来,而不能放在Adapter内(即不能为内部类),因为会导致反射失败,这个需要注意。

/**
 * 通用适配器
 *
 * @Author QianXiao
 * @Date 2022/2/19
 */
public abstract class BaseAdapter<BEAN, VH extends BaseRecycleViewHolder<?>> extends RecyclerView.Adapter<VH> {
    public final String TAG = "BaseAdapter";
    protected List<BEAN> dataList;
    protected ItemClickListener<BEAN> itemClickListener;

    public BaseAdapter(List<BEAN> dataList) {
        this.dataList = dataList;
    }

    public interface ItemClickListener<B> {
        /**
         * 条目点击事件
         *
         * @param bean item_data
         */
        void onItemClick(B bean);
    }

    public void setItemClickListener(ItemClickListener<BEAN> itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(getItemLayoutId(), parent, false);
        try {
            Class<VH> tClass = (Class<VH>) ((ParameterizedType) Objects.requireNonNull(getClass().getGenericSuperclass())).getActualTypeArguments()[1];
            Constructor<VH> constructor = tClass.getDeclaredConstructor(View.class);
            return (VH) constructor.newInstance(view);
        } catch (InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * getIteMLayoutId
     *
     * @return Item Layout Id
     */
    protected abstract int getItemLayoutId();

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        BEAN bean = dataList.get(position);
        onBindViewHolder(holder, bean);
    }

    /**
     * onBindViewHolder
     *
     * @param holder
     * @param bean
     */
    protected abstract void onBindViewHolder(@NonNull VH holder, BEAN bean);

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public void clearData() {
        dataList.clear();
        notifyDataSetChanged();
    }
}

使用示例:

首先独创建立ViewHolder类(不能为内部类),如下:

public class TaskListAdapterViewHolder extends BaseRecycleViewHolder<ItemTaskCoinFBinding> {

    public TaskListAdapterViewHolder(@NonNull View itemView) {
        super(itemView);
    }
}

创建Adapter类,需要泛型传入数据实体类和自己的ViewHolder类,其中需实现抽象方法getItemLayoutId返回Item布局Id:

public class TaskListAdapter extends BaseAdapter<Taskbean, TaskListAdapterViewHolder> {

    public TaskListAdapter(List<Taskbean> dataList) {
        super(dataList);
    }

    @Override
    protected int getItemLayoutId() {
        return R.layout.item_task_coin_f;
    }

    @Override
    protected void onBindViewHolder(@NonNull TaskListAdapterViewHolder holder, Taskbean taskbean) {
        holder.binding.tvTaskTitleItem.setText(taskbean.getTitle());
        // ……
    }
}

BaseAdapter的设计目前可能不是特别完美,今后会考虑继续优化。如您有更好的建议,欢迎评论交流。如有错误,欢迎不吝啬指正。

发表评论

textsms
account_circle
email

浅笑博客

Android开发常用Base类的设计与使用
Java有很多优秀的特性,如继承、泛型、反射等,如何将其在实际场景中很好的应用,是考验一个Java程序员对Java的理解程度有多深。 Android开发中,例如我们很多时候会用到Activity、Fra…
扫描二维码继续阅读
2022-04-10