风味特定代码

时间:2017-03-18 19:01:24

标签: android android-flavors

考虑带有片段MainActivity的活动MainFragment。该片段具有一些复杂的布局层次结构和一个来自库Frame的视图组com.framer:frame_me:1.1

如果我有两种foobar,我希望此Frame仅在bar风格而不在foo中, XML元素java代码和依赖。我该怎么做?

我可以使用

编译依赖项
barCompile 'com.framer:frame_me:1.1'

但是片段及其XML如何呢?我不想在两种风格中编写2个变体片段,因为我不想在2个地方保持相同的代码。

在我看来,一个可能的想法(可能是坏的想法)就是:

  1. 将XML元素移动到bar源集中的单独文件中。在ViewStub源集中添加具有相同名称的foo元素。现在,在片段XML
  2. 中使用include包含此XML文件
  3. 添加界面以处理Frame源集中的main视图。在foo源集和bar源集中添加一个空实现。这样,所有逻辑都可以保留在bar中,而所有常见逻辑都保留在main源集中。
  4. 这一切听起来只是为了编写特定于风味的代码和xml。

3 个答案:

答案 0 :(得分:1)

如何用Frame容器替换XML中的FrameLayout标记?

然后在bar风格的源代码中,您可以实例化Frame并说出container.addView(frame)。虽然foo风格没有引用Frame类,但会忽略容器。

这与您的第一种方法类似,但无需维护单独的资源集。这似乎是合理的,无论如何你都会有一些特定于风味的java代码。

答案 1 :(得分:0)

build.gradle sourceSets选项是什么? 您可以将Fragment和XML放在条形文件夹中,然后设置:

android {
    productFlavors {
         ...
    }
    sourceSets {
         bar.java.srcDirs = ['src/bar/java']
         bar.res.srcDirs = ['src/bar/res']
    }
}

答案 2 :(得分:0)

你只需要抽象。由于使用整数索引将资源标识到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()设置布局文件。如果你有更多的差异,你只需要在每个抽象方法中处理它们。基类可以存在于每个风格的公共代码和实现中。如果您不需要从外部设置任何行为代码,则可以删除界面。