风味特定代码
Flavor specific code
考虑一个 Activity MainActivity
和片段 MainFragment
。该片段具有一些复杂的布局层次结构和一个来自库 com.framer:frame_me:1.1
.
的视图组 Frame
如果我有 2 种口味 foo
和 bar
,并且我希望这个 Frame
只出现在 bar
口味中,而不出现在 foo
中、XML 元素 java 代码 和依赖关系 。我应该怎么做?
我可以使用
编译依赖
barCompile 'com.framer:frame_me:1.1'
但是片段及其 XML 呢?我不想在两种风格的片段中编写 2 个变体,因为我不想在 2 个地方维护相同的代码。
在我看来,一个可能的想法(可能是一个坏想法)是:
- 将 XML 元素移动到
bar
源集中的单独文件中。在 foo
源集中添加同名的 ViewStub
元素。现在在片段 XML 中使用 include
包含此 XML 文件
- 添加一个接口来处理
main
源集中的 Frame
视图。在 foo
源集中添加一个空实现,在 bar
源集中添加一个。这样,所有逻辑都可以保留在 bar
中,而所有通用逻辑都可以保留在 main
源集中。
这一切听起来只是为了编写特定于风味的代码和 xml。
做了大量的工作
如何用 FrameLayout
容器替换 XML 中的 Frame
标签?
然后在 bar
风格的源代码中你可以实例化 Frame
并说 container.addView(frame)
。 foo
flavor 不会引用 Frame
class 并且会忽略容器。
这与您的第一种方法类似,但无需维护单独的资源集。这似乎是合理的,无论如何你都会有一些特定于风味的 java 代码。
build.gradle sourceSets 选项是什么?
您可以将 Fragment 和 XML 放在 bar 文件夹中,然后设置:
android {
productFlavors {
...
}
sourceSets {
bar.java.srcDirs = ['src/bar/java']
bar.res.srcDirs = ['src/bar/res']
}
}
你只需要抽象。由于资源是使用 R class 中的整数索引来标识的,您可以使用 int 变量作为布局文件的占位符,并且考虑到在活动布局中搜索布局元素 ID 的事实,您可以回收公共元素.首先,创建一个公共片段 class,其中包含所有公共元素:
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 创建一个实现即可。如果唯一的区别是布局文件,将所有内容放入基础 class,并使用 setContainer() 设置布局文件。如果您有更多差异,则只需将它们处理到每个抽象方法中即可。基础 class 可以存在于公共代码、实现、每个风格中。如果您不需要从外部设置任何行为代码,则可以删除该接口。
考虑一个 Activity MainActivity
和片段 MainFragment
。该片段具有一些复杂的布局层次结构和一个来自库 com.framer:frame_me:1.1
.
Frame
如果我有 2 种口味 foo
和 bar
,并且我希望这个 Frame
只出现在 bar
口味中,而不出现在 foo
中、XML 元素 java 代码 和依赖关系 。我应该怎么做?
我可以使用
编译依赖barCompile 'com.framer:frame_me:1.1'
但是片段及其 XML 呢?我不想在两种风格的片段中编写 2 个变体,因为我不想在 2 个地方维护相同的代码。
在我看来,一个可能的想法(可能是一个坏想法)是:
- 将 XML 元素移动到
bar
源集中的单独文件中。在foo
源集中添加同名的ViewStub
元素。现在在片段 XML 中使用 - 添加一个接口来处理
main
源集中的Frame
视图。在foo
源集中添加一个空实现,在bar
源集中添加一个。这样,所有逻辑都可以保留在bar
中,而所有通用逻辑都可以保留在main
源集中。
include
包含此 XML 文件
这一切听起来只是为了编写特定于风味的代码和 xml。
做了大量的工作如何用 FrameLayout
容器替换 XML 中的 Frame
标签?
然后在 bar
风格的源代码中你可以实例化 Frame
并说 container.addView(frame)
。 foo
flavor 不会引用 Frame
class 并且会忽略容器。
这与您的第一种方法类似,但无需维护单独的资源集。这似乎是合理的,无论如何你都会有一些特定于风味的 java 代码。
build.gradle sourceSets 选项是什么? 您可以将 Fragment 和 XML 放在 bar 文件夹中,然后设置:
android {
productFlavors {
...
}
sourceSets {
bar.java.srcDirs = ['src/bar/java']
bar.res.srcDirs = ['src/bar/res']
}
}
你只需要抽象。由于资源是使用 R class 中的整数索引来标识的,您可以使用 int 变量作为布局文件的占位符,并且考虑到在活动布局中搜索布局元素 ID 的事实,您可以回收公共元素.首先,创建一个公共片段 class,其中包含所有公共元素:
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 创建一个实现即可。如果唯一的区别是布局文件,将所有内容放入基础 class,并使用 setContainer() 设置布局文件。如果您有更多差异,则只需将它们处理到每个抽象方法中即可。基础 class 可以存在于公共代码、实现、每个风格中。如果您不需要从外部设置任何行为代码,则可以删除该接口。