Android 风味特定代码
考虑一个带有片段的活动Android 风味特定代码,android,android-flavors,Android,Android Flavors,考虑一个带有片段的活动MainFragment。片段有一些复杂的布局层次结构和一个视图组Frame,它来自一个库com.framer:Frame\u me:1.1 如果我有两种风格foo和bar,我希望这个Frame只存在于bar风格中,而不存在于foo中,那么XML元素java代码和依赖项。我该怎么做 我可以使用 barCompile 'com.framer:frame_me:1.1' 但是片段和它的XML呢。我不想用两种风格编写两个变体,因为我不想在两个地方维护相同的代码 我脑海中一个可
MainFragment
。片段有一些复杂的布局层次结构和一个视图组Frame
,它来自一个库com.framer:Frame\u me:1.1
如果我有两种风格foo
和bar
,我希望这个Frame
只存在于bar
风格中,而不存在于foo
中,那么XML元素java代码和依赖项。我该怎么做
我可以使用
barCompile 'com.framer:frame_me:1.1'
但是片段和它的XML呢。我不想用两种风格编写两个变体,因为我不想在两个地方维护相同的代码
我脑海中一个可能的想法(可能是个坏主意)是:
bar
源集中的单独文件中移动XML元素。在foo
源集中添加具有相同名称的ViewStub
元素。现在使用include
在片段XML中包含这个XML文件main
源代码集中添加一个界面来处理Frame
视图。在foo
源集中添加一个空实现,在bar
源集中添加一个空实现。这样,所有逻辑都可以保留在条中
,而所有公共逻辑都保留在main
源集中仅仅为了编写特定于味道的代码和xml,这听起来是一项非常艰巨的工作。用
FrameLayout
容器替换xml中的Frame
标记如何
然后在bar
flavor的源代码中,您可以实例化Frame
并说container.addView(Frame)
。而foo
flavor将不引用Frame
类,并将忽略容器
这与第一种方法类似,但不必维护单独的资源集。这似乎是合理的,您将有一些特定于风格的java代码。build.gradle sourceset选项是什么? 您可以将片段和XML放入bar文件夹中,然后设置:
android {
productFlavors {
...
}
sourceSets {
bar.java.srcDirs = ['src/bar/java']
bar.res.srcDirs = ['src/bar/res']
}
}
你只需要抽象。由于资源是使用R类中的整数索引标识的,因此可以使用int变量作为布局文件的占位符,并且如果在活动布局中搜索了布局元素ID,则可以循环使用公共元素。首先,创建一个公共片段类,包含所有公共元素:
public abstract class BaseFlavorFragment extends Fragment {
/*Define an interface for whatever code the fragment may need from the outside and a member for keeping reference of that. You can also use the host activity, this is just for flexibility*/
public interface whateverThisDoes{
void do();
}
/*All the common fragment members go here, as protected so you can reach them from every subclass*/
protected TextView title;
protected Button mainButton;
protected whateverThisDoes listener;
public void setWhateverThisDoes(whateverThisDoes listener){
this.listener = listener;
}
/*Finally, create a int variable that will hold the reference to the layout file you need to use. you will set this in every flavor using the setContainer method.*/
protected int layout = 0;
/*this will allow you to select which XML to use
layout = R.layout.flavorlayout*/
public abstract setContainer();
/*Use this method to inflate any flavor members, like the Frame you mentioned*/
public abstract void inflateComponents();
/*Use this to set listeners, data, or anything the flavor controls do*/
public abstract void setBehaviors();
/*Set here anything the common controls do*/
protected void setCommonBehaviors(){
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//whatever
}
});
setBehaviors();
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContainer();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(layout, container, false);
/*Inflate common components*/
title = (TextView) root.findViewById(R.id.title);
button = (Button) root.findViewById(R.id.button);
/*inflate flavor components, if there's any*/
inflateComponents();
/*assign data, listeners, whatever the flavor controls do*/
setBehaviors();
return view;
}
}
现在,您可以为Foo和Bar创建一个实现。如果唯一的区别是布局文件,请将所有内容放入基类,并使用setContainer()设置布局文件。如果您有更多的差异,您只需要在每个抽象方法中处理它们。基类可以存在于公共代码、实现和每种风格中。如果不需要从外部设置任何行为代码,可以删除该接口。为什么不扩展框架的视图,将该视图放在main.xml中,但只有在flavor上运行时才启用它?您可以在View
barCompile
的新子类中增加一个额外的xml!框架
甚至不存在于foo
flavor中,这将抛出一个错误。或者我没有正确理解您的评论?您的xml也需要依赖项吗?是的,Frame
类存在于依赖项中。我无法添加不存在的xml视图。可以在主xml中为框架使用容器ViewGroup子类。但它仍然倾向于你提出的解决方案。您必须实现这个ViewGroup子类两次,每种风格一次。但是我如何保持特定于风格的Java代码独立,而不在两种风格中复制整个片段?您可以将部分代码移动到帮助器类,将该文件复制到第二种风格,然后在那里修改它。但是你必须有两种风格的完整源文件,所以本质上和我建议的一样,只是有点不同。我想这是唯一的办法。可悲的是,这似乎并不是压倒性的。您可以通过创建一个非常小的帮助器类来最小化工作量,该类只包含特定于味道的代码。是的,但是随着两种味道的不同变得越来越不同,但仍然共享许多常见代码,这会变得越来越复杂。我修复了几分钟前的代码,将所有常用代码移到一个基类,并将2个类扩展为2种风格,使其中一个完全为空。这看起来在将来也能很好地工作。在接受这个答案之前,我将等待几天,以防有更好的答案显示我了解源代码集,我的问题是如何在不复制2个风格java源代码集中的大量代码的情况下实现这一点。因为我不喜欢代码重复,所以我做了类似的事情,不是用这么多抽象方法,而是简单地重写一些方法来动态添加功能和视图。系统如何知道为特定的风格运行什么代码?我假设,您在检查当前的风格之后加载特定的片段实现?