0

我正在编写一个类似于AQuery的库,但具有用于操作元素的精致语法。

本质上,AQuery 所做的是安全地访问视图层次结构并允许您在 ImageView 和 TextView 等对象上调用子类方法。

我使用以下代码编写了一种使用 View 子类的通用方法:

Query的对象是用于操作视图层次结构的基础对象。基本格式如下所示:

public class Query {
    private View mView;
    // ...
}

接下来是通用接口。这是 Query 对象的内部接口:

private interface Operation<T extends View> {
    public void execute(T view);
}

接下来是中的run方法Query。这将检查此查询表示的当前节点,execute如果成功则调用 Operation 对象上的方法:

private <T extends View> Query run(Class<T> cls, Operation<T> operation) {
    T t = cls.cast(mView);

    if (t == null) {
        Log.e(TAG, "view is not a " + cls.getSimpleName());
    } else {
        operation.execute(t);
    }

    return this;
}

所以现在模板代码已经写好了,我使用类似的方法来实现功能:

public Query text(final CharSequence str) {
    return run(TextView.class, new Operation<TextView>() {

        @Override
        public void execute(TextView view) {
            view.setText(str);
        }
    });
}

对于修改视图层次结构的每个方法,我都必须编写这个样板代码。

有什么方法可以重构此代码以使方法text更简单?

4

1 回答 1

2

仅供参考,您在这里所拥有的并不是真正检查 mView 的类型。如果 mView 不能分配给类型 T,Class.cast 将抛出 ClassCastException,因此那里的日志消息实际上并不代表发生了什么。当且仅当 mView 为空时,t == null 才会为真。

如果没有一些 Query 将做什么的存根,很难说出你想要实现的目标。如果您的使用允许 Query 的参数化,那么您可以使操作成为它的功能。这将为您提供与查询类型匹配的视图的编译时检查。例如

public interface Query<ViewT extends View> {
    void run(ViewT view);
}

public Query<TextView> text(final CharSequence str) {
    return new Query<TextView>() {
        public void run(TextView view) {
            view.setText(str);
        }
    };
}

如果这是不可能的(即视图类型在编译时永远不知道),那么您仍然可以参数化它的实现,并且当且仅当参数类型与查询类型匹配时才执行操作。例如:

public interface Query {
    void run(View view);
}

private abstract class TypedQuery<ViewT extends View> implements Query {
    private final Class<ViewT> viewType;

    private TypedQuery(Class<ViewT> viewType) {
        this.viewType = viewType;
    }

    public final void run(View view) {
        if (viewType.isInstance(view)) {
            runInternal((ViewT) view);
        } else {
            Log.e(TAG, "view " + view + " is not a " + viewType.getSimpleName());
        }
    }

    protected abstract void runInternal(ViewT view);
}

public Query text(final CharSequence str) {
    return new TypedQuery<TextView>(TextView.class) {
        @Override
        protected void runInternal(TextView view) {
            view.setText(str);
        }
    };
}
于 2013-08-03T03:44:42.313 回答