Подтвердить что ты не робот

Android, Лучший способ предоставить конкретные приложения в библиотечном проекте?

Я создаю проект библиотеки для ряда приложений для Android. Все приложения имеют некоторые общие функции, которые я хочу включить в проект библиотеки, но для функций проекта библиотеки требуется использование определенных для приложения констант.

Итак, я ищу способ предоставить библиотечным функциям имена констант и разрешить каждому приложению определять их

Пример конкретной константы приложения и того, как она используется в проекте библиотеки

public class AppConstants {
    public static final long APP_ID = 6;//Needs to be set for each app
}

public static long getCurrentAppId(Context context) {
    return getLongPreference(context, CURRENT_APP_ID_KEY, AppConstants.APP_ID);
}

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

Очевидно, что обычно я просто импортировал/включал конкретный проект app_constants.java, но это невозможно в файлах проектов библиотеки, поскольку он не имеет понятия о конкретных приложениях (правильно)

Итак, каков наилучший способ, чтобы каждое конкретное приложение перекрывало константы?

Обновление Я долгое время решал, какие из превосходных ответов мне были предоставлены с наилучшими моими потребностями (спасибо всем). В конце концов я выбрал xml-решение. Мне это не особенно нравится, потому что это забивает мои ресурсы приложений, и я серьезно рассматривал возможность использования решения для интерфейса, но решение xml прекрасно работает

4b9b3361

Ответ 1

Вариант № 1 Расширьте класс AppConstants в каждом проекте

Лучший вариант №2 Используйте XML-ресурсы для определения констант

<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="integer" name="app_id" format="integer">6</item>
</resources>

то вы можете получить их

Context.getResources().getInteger(R.integer.app_id);

добавьте xml файл в свои ресурсы в каждом проекте только с теми значениями, которые вам нужны разные

Ответ 2

Я не знаю, какая отличная схема для этого, но это, безусловно, будет работать следующим образом:

определите базовый класс в вашей библиотеке

// class, enum or whatever you want it to be. 
class BaseConstants {
    // use some real singleton instead
    public static final BaseConstants instance = new BaseConstants();

    // define those values - sadly static inheritance does not work
    private static final int APP_ID = 0;
    private static final int CURRENT_APP_ID_KEY = 24;

    // so we have to do that via methods
    protected int getAppId() {
        return APP_ID;
    }
    protected int getAppIdKey() {
        return CURRENT_APP_ID_KEY;
    }
}

пусть каждая активность, которая хочет что-то пользовательское, реализует, что

class App1Constants extends BaseConstants {
    public static final App1Constants instance = new App1Constants();

    private final static int APP_ID = 1;

    // want a different APP_ID here.
    protected int getAppId() {
        return APP_ID;
    }

    // getAppIdKey not implemented here, uses default
}

Используйте этот класс как контекст для констант для вашей библиотеки

class Library {
    public static long getCurrentAppId(Context context, BaseConstants settings) {
        return getLongPreference(context, settings.getAppIdKey(), settings.getAppId());
    }
}

Действия будут такими, как

class myActivity extends Activity {
    // each Activity can implement it own constants class and overwrite only some values
    private static final BaseConstants CONSTANTS = App1Constants.instance;

    private void whatever() {
        long appId = Library.getCurrentAppId(this, CONSTANTS);
    }
}

class myActivity2 extends Activity {
    // or could just use the default ones
    private static final BaseConstants CONSTANTS = BaseConstants.instance;

    private void whatever() {
        long appId = Library.getCurrentAppId(this, CONSTANTS);
    }
}

Эта схема некрасива, но она будет работать как минимум

Ответ 3

определяют их как перечисление в проекте библиотеки, например

public enum Planet { MERCURY, VENUS, MARS }

android собственно принимает другой подход, страшный постоянный интерфейс, например,

interface Planets {
  static final int MERCURY = 1;
  static final int VENUS = 2;
  ...
}

однако, это хорошо известный java-анти-шаблон (постоянный интерфейс и подробно описан в Effective Java, цитирую,

Постоянный шаблон интерфейса плохо использует интерфейсы. Который класс использует некоторые константы внутри - это деталь реализации. Внедрение постоянного интерфейса приводит к тому, что эта деталь реализации утечка в экспортируемый API классов. Это не имеет никакого значения для пользователей класса, который класс реализует постоянный интерфейс. В факт, это может даже запутать их. Хуже того, он представляет собой обязательство: если в будущей версии класс модифицируется так, что он больше не нужен для использования констант, он все равно должен реализовать интерфейс для обеспечения двоичная совместимость. Если нефинальный класс реализует константу интерфейса, все его подклассы будут иметь загрязненное пространство имен по константам в интерфейсе.

если вам нужно, чтобы константы имели значения int по какой-либо причине, а вызов toString() в перечислении недостаточен, вы можете предоставить перечислению дополнительную информацию, например,

public enum ZipCode {
  LYNNWOOD(98036), SAN_JOSE(95112), ...;

  private int zipCode;

  private ZipCode(int zipCode) { this.zipCode = zipCode; }

  public int getZipCode() { return zipCode; }
}

Обратите внимание, что перечисление немного меньше, чем целочисленные константы, но из организации кода и ясности они намного превосходят.