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

Почему при использовании переменных между действиями предпочтение отдается предпочтениям?

Ежедневно существует много вопросов о следующем типе на SO:

Как получить переменную из другого Activity?

Обычно ответы рекомендуют использовать SharedPreferences или Intent.putExtra().

Для меня метод getter - это подход к доступу к переменной из другого класса. В конце концов, рассматриваемый Activity - это класс, а переменные являются членами класса.

Почему не предпочтительны методы getter, такие как SharedPreferences или Intent extras?

Я говорю о простых ситуациях, требующих доступа к переменной между действиями, например:

class OneClass extends Activity {
    int a;

    ..
    // some changes to a
    ..
}

И затем в другом классе (Activity):

class SomeOtherClass extends Activity {
    ..
    // trying to access a here
    ..
}

Существует ли метод getter правильный подход или нет?

Опять же - я не говорю о сценариях, где эти вещи на самом деле верный путь. SharedPreferences для постоянного хранения небольшого объема данных extras, как указано в документации: Это может использоваться для предоставления расширенной информации компоненту. Например, если у нас есть действие для отправки сообщения электронной почты, мы можем также включить дополнительные фрагменты данных для предоставления темы, тела и т.д.


Как некоторые из ответов, вероятно, указывают на то, что существуют определенные сценарии, такие как отсутствие гарантии того, что другой Activity жив, я думаю, есть более вероятные и правильные причины того, почему люди предлагают идти по намерениям и общим предпочтениям.

4b9b3361

Ответ 1

Ответ на ваш вопрос в два раза:

  • Для мета-аспект, который в любом случае принадлежит к meta SO, многие новички-программисты видят Android, хотят писать приложения и сосать на Java.
  • Для другого quesiton, как правило, использование getter и setter не будет работать, потому что вы не можете передавать объекты между действиями простым способом. Хотя вы можете технически сделать это с помощью Parcelable, это не рекомендуется, и лучший способ - использовать намерение передавать данные между компонентами приложения.
  • Еще одним моментом является то, что приложения для Android должны поддерживать минимальное количество внутренних компонентов. Я думаю, что это был большой успех Android. Если вы посмотрите на приложения там, то в среднем гораздо меньше глобального состояния, чем типичные программы, написанные в java. Программы также меньше, что и следовало ожидать, но тот факт, что атомная активность может представлять состояние одного экрана и тот факт, что на одном экране обычно не будет сохраняться такое состояние во всем приложении, приводит к хорошему логическому разделению между компонентами приложения.

Ответ 2

Простой ответ заключается в том, что жизненный цикл Activity контролируется ОС Android. Действия отличаются от обычных классов, которые создаются кодом пользователя и гарантированно доступны до тех пор, пока они больше не будут указаны.

Ответ 3

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

Однако, чтобы следовать вашему шаблону, вы расширяете приложение и используете для этого геттеры и сеттеры. Как объявить глобальные переменные в Android?

Ответ 4

В основном потому, что весь процесс отправки намерения не так прост. Умывка может проходить через систему, между процессами и т.д.... короче, созданный вами объект не является тем же самым объектом, который получен в конце (это можно доказать, если пытаться расширить класс намерений, отправить его другому действию и попробуйте вернуть его обратно в расширенный класс на другом конце, его просто не тот же объект).

Теперь я тоже очень ненавижу это, поэтому я создал некоторые базовые классы, которые помогают мне работать с намерениями (я называю их BundleWrappers), которые будут работать примерно так:

вы создаете POJO с геттерами/сеттерами, вы заполняете этот объект и используете его, как вам нравится,

тогда, когда время просто сериализуется в bunle и десериализует его в один и тот же объект на другом конце.

тогда у вас будет тот же объект с геттерами и сеттерами в другом действии.

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

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

public abstract class BundleWrapper implements Parcelable {

    protected static final String KEY_PARCELABLE = "key_parcelable";

    public static final String TAG = BundleWrapper.class.getSimpleName();

    public BundleWrapper() {
        super();
    }

    abstract Parcelable getParcelable();

    public Bundle toBundle(){
        final Bundle bundle = new Bundle();
        Parcelable parcelable = getParcelable();
        if (parcelable != null) {
            bundle.setClassLoader(parcelable.getClass().getClassLoader());
            bundle.putParcelable(KEY_PARCELABLE, parcelable);
        }
        return bundle;
    }

    public static Object fromBundle(final Intent intent) {
        return fromBundle(intent.getExtras());
    }

    public static Object fromBundle(final Bundle bundle) {
        if (bundle != null && bundle.containsKey(KEY_PARCELABLE)) {
            bundle.setClassLoader(BundleWrapper.class.getClassLoader());
            return bundle.getParcelable(KEY_PARCELABLE);
        }
        return null;
    }

}

Вот мой базовый класс, для его использования вы просто расширяете его и реализуете логически (отсталая часть процесса:):

public class WebViewFragmentBundle extends BundleWrapper implements Parcelable {

    public static final String TAG = WebViewFragmentBundle.class.getSimpleName();

    private String url;
    public WebViewFragmentBundle() {
        super();
    }

    public WebViewFragmentBundle(Parcel source) {
        this.url = source.readString();
    }

    public String getUrl() {
        return url;
    }


    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    Parcelable getParcelable() {
        return this;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(url);
    }

    public static final Parcelable.Creator<WebViewFragmentBundle> CREATOR = new Parcelable.Creator<WebViewFragmentBundle>() {
        @Override
        public WebViewFragmentBundle createFromParcel(Parcel source) {
            return new WebViewFragmentBundle(source);
        }

        @Override
        public WebViewFragmentBundle[] newArray(int size) {
            return new WebViewFragmentBundle[size];
        }
    };


}

и для использования:

public static void launchAugmentedRealityActivityForResult(final Activity context, WebViewFragmentBundle wrapper) {
        final Intent intent = new Intent(context, Augmented.class);
        intent.putExtras(wrapper.toBundle());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        context.startActivityForResult(intent, AUGMENTED_RESULT_CODE);
    }

и наложите его на другой конец, например:

(WebViewFragmentBundle)BundleWrapper.fromBundle(getIntent());

Ответ 5

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

Ответ 6

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

Как говорится, Android не содержит какого-либо естественного механизма доступа к экземпляру другого Activity. Это, вероятно, очень преднамеренно. Деятельность должна действовать определенным образом. Самое близкое сравнение состоит в том, что каждое действие должно быть похоже на страницу на веб-сайте (поэтому ссылка на другой экземпляр страницы не имеет большого смысла).

Ответ 7

Я не думаю, что это как-то уникально для Android. Любая относительно сложная платформа на основе Java имеет более высокие "правила", подобные этому.

  • Java Swing или AWT ограничивают возможность вызова определенных методов из определенных потоков.
  • Java ME очень похожа на Android в этом отношении.
  • В Java EE - забудьте про попытку поделиться чем-либо через сервлеты или EJB с членами static. Возможно, они даже не на одной машине.

Чтобы прямо ответить на ваш вопрос: вы не можете просто обращаться к объектам "свободно" так же, как в простой программе Java, так как некоторые предположения, которые зависят от разбивки, а именно, что эти объекты даже в одном и том же ClassLoader.

Ответ 8

Это будет работать отлично, если программа может контролировать, когда действия создаются и уничтожаются. Но проблема в том, что они управляются ОС.

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

В этих случаях используются общие предпочтения и намерения, поскольку они независимы от состояния. Независимо от того, что происходит с какой-либо деятельностью, предпочтения всегда будут доступны в том состоянии, в котором они были. Intent также является объектом, который существует сам по себе и не будет устаревшим.

Ответ 9

Чтобы использовать ваш пример, первая проблема, с которой вы сталкиваетесь, - передать ссылку на экземпляр OneClass на SomeOtherClass. SomeOtherClass нужна ссылка на экземпляр OneClass, чтобы вызвать oneClass.getVariable(). Нет простого способа сделать это, потому что, когда Activity начинает другое действие, он делает это, вызывая startActivity() и передавая Intent. Это механизм, который вы легко можете использовать для передачи параметров в Activity при его запуске, поэтому вы, вероятно, должны его использовать.

Следуя вашему примеру, другим вариантом будет использование переменной static (class) для хранения данных, которые вы хотите передать между действиями. Таким образом, вы можете сделать что-то вроде этого:

class OneClass extends Activity {
    private static int a;

    public static int getA() {
        return a;
    }

    ..
    // some changes to a
    ..
}

class SomeOtherClass extends Activity {
    ..
    // trying to access a here
    int myA = OneClass.getA();
}

Однако это в значительной степени предполагает, что будет только один экземпляр OneClass и что там, где все это разрушает IMHO. В Android, действия создаются и уничтожаются повсюду. В любой момент времени может быть несколько случаев активности, и вы никогда не знаете, сколько у вас есть или кто из них активен в настоящее время. Это приводит к тому, что статические переменные внутри классов активности трудно получить. Для передачи данных между действиями я использовал бы Extras in Intent, потому что ясно, что вы передаете данные при запуске Activity. Он самодокументирован.

С другой стороны, если у вас есть данные, которые действительно глобальны для всего вашего приложения, тогда я бы просто использовал переменные static (class) в некотором классе, которые доступны из всех классов напрямую. Подкласс людей Application для этого, но документация указывает, что вам не нужно и вообще вам не нужно. Вы можете просто сделать что-то вроде этого:

public class Globals {
    public static int a; // Publicly available, don't need getter
}

Затем любой класс может просто сохранить что-то в Globals.a или получить к нему доступ. Для этого вам не нужен подкласс Application.

Ответ 10

Решение: Активность - это компонент приложения, у него есть свой жизненный цикл и задний стек в отличие от классов. Хотя мы можем передавать объекты через разборку и сериализацию, но это не рекомендуется. Мы можем передать объект через узел в объекте намерения или использовать общие настройки для доступа к объекту. Использование геттера не было бы хорошей идеей. Или вы можете создать отдельный Constant Class и определить статический varaible там, а затем можете получить к нему доступ.