我正在编写一个类似于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
方法。这将检查此查询所代表的当前节点,如果成功,则调用Operation对象上的execute
方法:
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);
}
});
}
对于修改View层次结构的每个方法,我都必须编写这个类似样板的代码。
有什么方法可以重构这段代码,使text
这样的方法更简单?
答案 0 :(得分:2)
仅供参考,您在这里所拥有的并不是真正检查mView的类型。如果mView不能分配给类型T,则Class.cast将抛出ClassCastException,因此那里的日志消息实际上并不代表发生的情况。当且仅当mView为null时,t == null才为真。
如果没有查询将会执行什么操作,就很难说出你要实现的目标。如果您的使用允许Query的参数化,那么您可以将操作作为其功能。这将为您提供与查询类型匹配的视图的编译时检查。 e.g。
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);
}
};
}
如果那是不可能的(即在编译时从未知道视图类型),那么您仍然可以参数化它的实现,并且当且仅当参数类型与查询类型匹配时才执行操作。 e.g:
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);
}
};
}