Невозможно разрешить метод getAllUserGroupByName() из другой студии android android
Считаю, что у меня есть два продукта в моем проекте Android с именем "local" и "international".
Я просто даю скелет моей ситуации, поэтому любезно игнорирую другие ошибки.
Рассмотрим, что у меня уже есть другой источник Set для разных вкусов.
Теперь в моем "местном" вкусе мне нужен только один метод, как указано ниже.
// local flavor file
interface UserDao {
List<User> getAllUser();
}
В моем международном вкусе мне также нужна дополнительная функция, чтобы получить пользователя в группе по имени. Итак, имея два метода.
// international flavor file
interface UserDao {
List<User> getAllUser();
List<User> getAllUserGroupByName();
}
Но проблема в том,
У меня есть одно действие, из которого я вызываю этот метод.
Когда я вызываю метод getAllUserGroupByName()
из активности, он компилируется, если
текущий вкус " международный", но он не будет компилироваться на " локальном", так как он не содержит этого метода.
Я пробовал называть этот метод, обертывая, если условие, как показано ниже,
// BuildUtils is my helper class to get current flavor check easily.
if (BuildUtils.isInternational()) {
getAppDatabase().UserDao().getAllUserGroupByName();
}
Но он тоже не работает.
Мне не нужно следующее решение.
- Два действия для каждого вкуса.
- Я уже решил это, объединив оба интерфейса в одном интерфейсе. (который также действителен, так как он не содержит никакой реализации).
Обновление
После некоторых исследований и ответов, предоставленных @manouti
Проблема в том, что Java является статически типизированным языком, поэтому размещение если условие не означает, что компилятор избегает проверки код с вызовом getAllUserGroupByName.
Итак, есть ли способ, с помощью которого система сборки может игнорировать конкретный код в соответствии с вкусом для компиляции кода?
ИЛИ
любой инструмент или функция IDE для студии Android, которая отбросит конкретный код в соответствии с вкусом для компиляции.
Ответы
Ответ 1
Есть несколько способов сделать это. Конечно, вы можете написать два разных класса активности, как упомянутый другой ответ, и поместить их в каждый набор источников вкусов, и это будет отлично работать. Но я предполагаю, что вы действительно не хотите этого делать, потому что это было бы излишним дублированием кода, возможно, с очень небольшим изменением между двумя версиями.
Вот два способа, о которых я могу думать, которые позволяют сохранить только один класс Activity (т.е. в основном исходном наборе):
-
Используйте отражение, чтобы вызвать метод getAllUserGroupByName
, если он определен. Детали этого подхода очень хорошо проиллюстрированы в этом сообщении. Проблема в том, что Java является статически типизированным языком, поэтому размещение условия if
не означает, что компилятор избегает проверки кода с помощью вызова getAllUserGroupByName
. С помощью этого решения вы можете использовать рефлексию, чтобы проверить, определен ли метод, и если это так, вы можете называть его рефлексивно.
-
Другое решение, которое IMO чище, чем использование кода отражения, заключается в инкапсуляции логики получения информации о группе пользователей в своем классе и в том же пакете, скажем UserGroupLoader
, и определении двух версий этого класса, одного для каждого аромата. В локальном вкусе реализация вернет фиктивный результат (например, пустой список пользователей) и в международном вкусе он будет использовать фактический код загрузки пользователей:
public class UserGroupInfoLoader {
public List<User> getAllUserGroupByName() {
// for international flavor, call UserDao.getAllUserGroupByName
// for local flavor, return empty list (you may even use the Optional class as a return type instead of List<User>)
}
}
Вы также можете управлять областью логики для инкапсуляции в этом классе. Например, вместо того, чтобы просто возвращать список групп пользователей, вы можете вернуть ему объединенный результат как всех пользователей (первый метод в UserDao
), так и всех пользователей по имени группы (применяется только к реализации для международного вкуса). Это делает код более читаемым, потому что просто наличие метода, который возвращает фиктивные данные для одного аромата, может показаться противоречивым для читателей.
Ответ 2
Вы можете создать интерфейс, содержащий только метод getAllUserGroupByName()
и сделать его доступным для международной версии.
С помощью этого вы можете выполнить проверку экземпляра userDao.
Интерфейс с методом getAllUserGroupByName()
(он должен быть помещен в общий набор источников):
interface InternationalInterface {
List<User> getAllUserGroupByName();
}
Сделайте UserDao в международной версии, расширьте его:
// international flavor file
interface UserDao extends InternationalInterface {
List<User> getAllUser();
}
И в вашей деятельности проверьте, является ли UserDao экземпляром InternationalInterface
. Если утверждение будет верно только для приложения, созданного с использованием международного вкуса. Теперь вам больше не нужно использовать BuildUtils.
UserDao userDao = getAppDatabase().UserDao();
if (userDao instanceof InternationalInterface) {
((InternationalInterface)userDao).getAllUserGroupByName();
}
Ответ 3
Как сделать ваш текущий вид деятельности абстрактным с помощью метода типа:
protected abstract void onGetAllUserGroupByName();
а затем продолжите его с двумя версиями того же действия, что и
public class MyActivityImpl extends MyActivity {
@Override
protected void onGetAllUserGroupByName() {
...
}
}
Когда аромат локальный, то переопределенный метод пуст, а когда он международный, он будет:
@Override
protected void onGetAllUserGroupByName() {
getAppDatabase().UserDao().getAllUserGroupByName();
}
Вам не нужно будет копировать любые ваши функции, уже присутствующие в родительской активности.