Как получить доступ к классу вкуса продукта из основного каталога?

В моем приложении есть два варианта продукта:
flavorOne(src/flavorOne/java) и flavorTwo(src/flavorTwo/java). Главная (src/main/java) – это форма каталога, в которой оба варианта используют классы. Я хочу запустить действие src/flavorTwo/java/ActivityB.java из действия, представленного в src/main/java/ActivityA. при запуске FlavorTwo он работает, но когда я переключаю FlavorOne, он показывает ошибку импорта com.packagename.ActivityB.

+ App // module
    |- src
       |- main// shared srcDir
          |- java
           |- SharedActivity
       + flavorOne
          |- java
           |- FlavorOneActivity
       + flavorTwo
          |- java
           |- FlavorTwoActivity

Вот SharedActivity.java в каталоге src/main/java/SharedActivity.java

package com.example.buildvariants;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
/**********************  works if it is in flavorOne otherwise it shows error on this package import ***********/
import com.example.buildvariants.flavorOne.LoginActivity;

public class SharedActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        //if flavor is flavorTwo hide the fab
        //else flavor is flavorOne show fab and launch activity under flavorOne/java/LoginActivity.java
        if (BuildConfig.FLAVOR.equalsIgnoreCase("flavorTwo")) {
            fab.setVisibility(View.GONE);
        } else {
            fab.setVisibility(View.VISIBLE);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                    startActivity(new Intent(SharedActivity.this, LoginActivity.class));

                }
            });
        }
    }
}

Действия в разделе flavorOne src/flavorOne/FlavorOneMainActivity.java

package com.example.buildvariants.flavorOne;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.example.buildvariants.R;
import com.example.buildvariants.SharedActivity;

public class FlavorOneMainActivity extends AppCompatActivity {

    private static final String TAG =FlavorOneMainActivity.class.getSimpleName() ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.flavor_one_activity_main);
        Intent intent = new Intent(FlavorOneMainActivity.this, SharedActivity.class);
        startActivity(intent);
    }
}

Действия в разделе flavorTwo src/flavorOne/FlavorTwoMainActivity.java

package com.example.buildvariants.flavorTwo;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.example.buildvariants.R;
import com.example.buildvariants.SharedActivity;

public class FlavorTwoMainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.flavor_two_activity_main);
        startActivity(new Intent(FlavorTwoMainActivity.this, SharedActivity.class));
    }
}

Показывает ошибку при импорте пакета SharedActivity(src/main/java/), как указано ниже, когда я изменил варианты сборки flavorTwo.

package com.example.buildvariants;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
/********error  on package import***********/
import com.example.buildvariants.flavorOne.LoginActivity;

public class SharedActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        //if flavor is flavorTwo hide the fab
        //else flavor is flavorOne show fab and launch activity under flavorOne/java/LoginActivity.java
        if (BuildConfig.FLAVOR.equalsIgnoreCase("flavorTwo")) {
            fab.setVisibility(View.GONE);
        } else {
            fab.setVisibility(View.VISIBLE);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                    startActivity(new Intent(SharedActivity.this, LoginActivity.class));

                }
            });
        }
    }
}

Что было бы лучшим решением этой проблемы?


person Rajesh Khadka    schedule 02.12.2015    source источник
comment
когда вы хотите получить доступ к классу, находящемуся вне пакета, вам нужно импортировать этот пакет, например, вы импортировали FlavourTwo внутри falvorOne/java?   -  person JBALI    schedule 02.12.2015
comment
@user3624028 user3624028, не могли бы вы опубликовать пример, как импортировать FlavorTwo внутрь falvorOne/java?   -  person Rajesh Khadka    schedule 02.12.2015
comment
ради тропы попробуйте: import flavorOne.java;   -  person JBALI    schedule 02.12.2015
comment
@user3624028 user3624028 Я импортировал этот класс, но когда я меняю варианты сборки на другой вариант, появляется ошибка при этом импорте.   -  person Rajesh Khadka    schedule 02.12.2015
comment
пожалуйста, добавьте фрагменты вашего кода   -  person JBALI    schedule 02.12.2015
comment
@ user3624028 я обновил фрагменты кода.   -  person Rajesh Khadka    schedule 04.12.2015


Ответы (2)


Это не удается, потому что при создании приложения одновременно существует только один код продукта. Итак, что вы действительно хотите сделать, так это иметь одно имя класса, используемое в двух вкусах продукта.

Представьте, что у нас есть один класс, который мы хотим заменить для каждого вкуса продукта, назовем его ReplacableActivity.java.

Чтобы замена работала, оба варианта продукта должны иметь этот класс, а исходный набор основного не будет иметь этого класса.

пример:

src/main/com/blah/myApp/ReplacableActivity #<- should not exist
# exists and is the implementation of ReplacableActivity for `flavorOne`
src/flavorOne/com/blah/myApp/ReplacableActivity.java
# exists and is the implementation of ReplaceableActivity.java for `flavorTwo`
src/flavorTwo/com/blah/myApp/ReplacableActivity.java

Теперь для всех вариантов продуктов, которые вы создаете, существует ReplacableActivity, и на него можно ссылаться из исходного набора main. Во время сборки вместе с приложением упаковывается только ReplaceableActivity для этого конкретного варианта. И теперь ваш импорт будет работать как положено import com.blah.myApp.ReplaceableActivity; из исходного набора main.

Редактировать:

Если вас беспокоит только скрытие или отображение одного элемента, то вышеперечисленное является излишним. Было бы намного проще получить его от BuildConfigField

android {
    productFlavors {
        flavorOne {
            buildConfigField "boolean", "flavorShowsFab", 'false'
        }
        flavorTwo {
            buildConfigField 'boolean', 'flavorShowsFab', 'true'
        }
    }

Затем в вашем java-коде просто выполните

findViewById(R.id.myHidableFab).setVisibility(BuildConfig.flavorShowsFab ? View.VISIBLE : View.GONE));
person JBirdVegas    schedule 02.12.2015
comment
В моем случае оба варианта имеют одинаковый пользовательский интерфейс, но разница в том, что один вариант содержит плавающую кнопку действия, а другой - нет. Я хочу запустить действие с помощью этой плавающей кнопки действия в случае SecondFlavor. Я скрыл плавающую кнопку действия, проверив варианты сборки в первом варианте. - person Rajesh Khadka; 02.12.2015
comment
Обновлен ответ, чтобы показать более простой способ скрыть вид на основе productFlavors - person JBirdVegas; 02.12.2015
comment
спасибо за решение, это единственный способ сделать это? В моем случае я сохранил ReplacableActivity в качестве основного, потому что для него нужны оба варианта и один и тот же код для обоих вариантов. Если сборка является первой разновидностью, я хочу открыть активность, присутствующую в первой разновидности, при действии кнопки плавающего действия, но не в случае второй разновидности. Если код одинаков для обоих, за исключением действий FAB, хорошо ли повторять код в обоих вариантах? - person Rajesh Khadka; 03.12.2015
comment
Gradle очень гибкий, поэтому вы можете реализовать это разными способами. Тем не менее, повторяющийся код никогда не бывает хорошим. Если вам нужно, чтобы код был одинаковым для обоих вариантов, за исключением одной точки принятия решения, то использование значения BuildConfig для if (BuildConfig.blah) {} else {} имеет наибольший смысл... Вы не хотите поддерживать две копии одного и того же кода. Что, если вы найдете ошибку/функцию в дублирующемся коде? Теперь вам нужно обновить два места вместо одного. - person JBirdVegas; 03.12.2015

Вместо того, чтобы создавать разный код для каждого варианта, вы можете поддерживать один и тот же код, используя концепцию наследования и несколько изменений в файлах gradle и manifest, мы можем достичь это в три шага

1) объединить исходные наборы для каждого варианта в файле уровня приложения build.gradle.

sourceSets {
         flavorOne {
            java.srcDirs = ['src/main/java','src/flavorOne/java']
        }
    flavorTwo {
            java.srcDirs = ['src/main/java','src/flavorTwo/java']
        }
    }

2) здесь происходит главный трюк, создайте манифест для каждой разновидности с определенной для них активностью запуска, но не в основной разновидности

В основном файле манифеста:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapplication">

        <application

    //no launcher defined here

        </application>

    </manifest>

Во вкусе один основной файл:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myapplication">

    <application>
        <activity
            android:name="{Your launcher activity}">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Во вкусе два файла манифеста:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.myapplication">

        <application>
            <activity
                android:name="{Your launcher activity}">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    </manifest>

чтобы мы не получили ошибку при объединении файла манифеста при построении gradle

3) Итак, в main java src создайте BaseSharedActivity.java и напишите свою обычную реализацию, создайте SharedActivity.java в каждом варианте и вызовите их из активности запуска, определенной в каждом варианте.

В SharedActivity.java каждого вкуса:

public class SharedActivity extends BaseSharedActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
//You can override whatever method you want from BaseSharedActivity here 
}

Таким образом, вы не добавляете один и тот же код для SharedActivity и можете дать максимальную настройку для одного и того же экрана в разных вариантах, вы также можете использовать ту же логику для активности запуска.

person mohamed farith    schedule 12.04.2020