Каков наилучший способ обмена данными между действиями?

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

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

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

Есть ли способ напрямую получить и изменить переменные без использования методов get и set? Я помню, как читал статью на сайте Google dev, в которой говорится, что это не рекомендуется для производительности на Android.

Ответ 1

Вот компиляция наиболее распространенных способов достижения этого:

  • Отправить данные внутри намерения
  • Статические поля
  • HashMap WeakReferences
  • Персистентные объекты (sqlite, общие настройки, файл и т.д.).

TL; DR: существует два способа совместного использования данных: передача данных в дополнительных целях или сохранение их в другом месте. Если данные являются примитивами, строками или определенными пользователем объектами: отправьте его как часть дополнительных намерений (определяемые пользователем объекты должны реализовать Parcelable). Если передача сложных объектов сохраняет экземпляр в одноэлементном месте где-то еще и доступ к ним из запущенного действия.

Некоторые примеры того, как и почему реализовать каждый подход:

Отправить данные внутри намерений

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

Во втором действии:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

Используйте этот метод , если вы передаете примитивные данные или строки. Вы также можете передавать объекты, которые реализуют Serializable.

Хотя заманчиво, вы должны подумать дважды, прежде чем использовать Serializable: он подвержен ошибкам и ужасно медленным. Так что вообще: держаться подальше от Serializable, если это возможно. Если вы хотите передать сложные пользовательские объекты, взгляните на интерфейс Parcelable. Это сложнее реализовать, но оно имеет значительный прирост скорости по сравнению с Serializable.

Обмен данными без сохранения на диске

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

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

Использовать одноэлементный класс

Имейте класс для хранения данных:

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

От запущенной операции:

String data = DataHolder.getInstance().getData();

Использовать одноэлементное приложение

Приложение singleton представляет собой экземпляр android.app.Application, который создается при запуске приложения. Вы можете предоставить пользовательский, расширив Application:

import android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

Перед запуском деятельности:

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

Затем из запущенного действия:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

Статические поля

Идея в основном такая же, как синглтон, но в этом случае вы предоставляете статический доступ к данным:

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static String setData(String data) {DataHolder.data = data;}
}

От запущенной операции:

String data = DataHolder.getData();

HashMap WeakReferences

Такая же идея, но позволяет сборщику мусора удалять объекты без ссылок (например, когда пользователь завершает действие):

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

Перед запуском деятельности:

DataHolder.getInstance().save(someId, someObject);

От запущенной операции:

DataHolder.getInstance().retrieve(someId);

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

Сохранять объекты на диск

Идея состоит в том, чтобы сохранить данные на диске перед запуском другого действия.

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

Недостатки: его громоздкость и требуется больше времени для реализации. Требуется больше кода и, следовательно, больше шансов ввести ошибки. Это также будет намного медленнее.

Некоторые из способов сохранения объектов включают в себя:

Ответ 2

Что вы можете использовать:

  • передача данных между действиями (например, Кристиан сказал)
  • с использованием класса с множеством статических переменных (поэтому вы можете вызывать их без экземпляра класса и без использования getter/setter)
  • Использование базы данных
  • Общие настройки

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

Ответ 3

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

Это не делает копию (особенно с String, но даже объекты проходят по значению ссылки, а не по самому объекту, а getter вроде бы хорош в использовании - возможно, лучше использовать, чем другие средства, потому что они являются общими и хорошо понятны). Более старые "мифы о производительности", такие как не использование геттеров и сеттеров, по-прежнему имеют некоторую ценность, но также были обновлены в документах.

Но если вы не хотите этого делать, вы можете просто сделать переменные общедоступными или защищенными в GlobalState и получить к ним доступ напрямую. И вы можете сделать статический синглтон как Объект приложения JavaDoc указывает:

Как правило, нет необходимости в подклассе Заявка. В большинстве случаев, статические синглтоны могут обеспечивать одинаковые функциональность более модульным способом. Если ваш синглтон нуждается в глобальном контекста (например, для регистрации широковещательные приемники), функция получить его можно получить контекст который внутренне использует Context.getApplicationContext(), когда сначала построим синглтон.

Использование данных Intent, так как другие ответы здесь представляют собой другой способ передачи данных, но он обычно используется для небольших данных и простых типов. Вы можете передавать более крупные/более сложные данные, но это более активно, чем просто использование статического одиночного. Объект Application по-прежнему остается моим личным фаворитом для совместного использования более крупных/более сложных несовместимых данных между компонентами приложений Android (потому что он имеет четко определенные жизненного цикла в приложении для Android).

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

Ответ 4

Сделайте то, что вам нужно сделать Google! здесь: http://developer.android.com/resources/faq/framework.html#3

  • Примитивные типы данных
  • Непостоянные объекты
  • Singleton class - мой любимый: D
  • Открытое статическое поле/метод
  • HashMap of WeakReferences to Objects
  • Постоянные объекты (Предпочтения приложений, Файлы, ContentProviders, SQLite DB)

Ответ 5

Вы можете расширить класс Application на любые объекты, которые там есть, затем они доступны в любом месте вашего приложения.

Ответ 6

Использование хешмапа слабого ссылочного подхода, описанного выше, и в http://developer.android.com/guide/faq/framework.html кажется мне проблематичным. Как восстанавливаются целые записи, а не только значение карты? В какой области вы его распределяете? Поскольку инфраструктура контролирует жизненный цикл Activity, при наличии одной из участвующих в ней Деяний, она подвергает риску ошибки времени выполнения, когда владелец уничтожается до своих клиентов. Если приложение принадлежит ему, некоторые действия должны явно удалить запись, чтобы избежать того, чтобы хэш файл не включался в записи с действительным ключом и потенциально сфальсифицированной собранной слабой ссылкой. Кроме того, что должен делать клиент, когда значение, возвращаемое для ключа, равно null?

Мне кажется, что The WeakHashMap, принадлежащий Приложению или в рамках одного сингла, является лучшим выбором. Доступ к значению на карте осуществляется с помощью ключевого объекта, и когда нет сильных ссылок на ключ (т.е. Все действия выполняются с ключом и на что он сопоставляется), GC может восстановить запись карты.

Ответ 7

Ну, у меня есть несколько идей, но я не знаю, являются ли они тем, что вы ищете.

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

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

Это может быть совсем не то, что вы ищете, но вы также можете попробовать использовать SharedPreferences или предпочтение в целом.

В любом случае, дайте мне знать, что вы решите.

Ответ 8

Предполагая, что вы вызываете активность два из одного действия с использованием намерения.
Вы можете передавать данные с помощью намерения .putExtra(),

Возьмите это для справки. Отправка массивов с помощью Intent.putExtra

Надеюсь, что вы хотите.

Ответ 9

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

Однако, если вам действительно нужно сохранить эти значения, вы можете сохранить их в каком-то структурированном текстовом файле или базе данных на локальном хранилище. Файл свойств, файл XML или файл JSON могут хранить ваши данные и легко анализироваться во время создания активности. Не забывайте также, что у вас есть SQLite на всех устройствах Android, поэтому вы можете хранить их в таблице базы данных. Вы также можете использовать карту для хранения пар ключ-значение и сериализации карты для локального хранилища, но это может быть слишком громоздким, чтобы быть полезным для простых структур данных.

Ответ 10

Все вышеупомянутые ответы велики... Я просто добавляю, что никто еще не упомянул о сохранении данных через действия, а также использовать встроенную базу данных SQLite для Android, чтобы сохранить релевантные данные... На самом деле вы может поместить вашу базу данных в состояние приложения и вызвать ее по мере необходимости во время активации. Или просто создать вспомогательный класс и сделать вызовы БД при необходимости... Просто добавив еще один слой для вас, чтобы рассмотреть... Но все остальные ответов было бы достаточно... Действительно просто предпочтение

Ответ 11

Обмен данными между действиями пример передачи электронной почты после входа в систему

"email" - это имя, которое может использоваться для ссылки на значение для запрашиваемой активности.

1 Код на странице входа

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

2 кода на домашней странице

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");

Ответ 12

И если вы хотите работать с объектом данных, это два очень важных:

Сериализуемый против Parcelable

  • Serializable - это интерфейс маркера, который подразумевает, что пользователь не может сортировать данные в соответствии с их требованиями. Поэтому, когда объект реализует Serializable Java, он автоматически сериализует его.
  • Parcelable - собственный протокол сериализации Android. В Parcelable разработчики пишут собственный код для маршалинга и разборки. Таким образом, он создает меньше мусорных объектов по сравнению с сериализацией
  • Производительность Parcelable очень высока по сравнению с Serializable из-за ее пользовательской реализации Настоятельно рекомендуется использовать Parcelable implantation при сериализации объектов в android.

public class User implements Parcelable

подробнее в здесь

Ответ 13

**There are various way to share data between activities**

    1: **passing data between activities using Intent**

    Intent intent=new Intent(this, desirableActivity.class);
    intent.putExtra("KEY", "Value");
    startActivity(intent)

    2: Using static keyword ,  define variable as public static and use any where in project

      public static int sInitialValue=0;

      use anywhere in project using classname.variableName;

    3:  Using Database

    but its bit lengthy process, 
    you have to use query for inserting data and iterate data using cursor when need.
    but there are no chance of losing data without cleaning cache.

    4: Using shared Preferences

      much easier than database. but there is some limitation you  can not save ArrayList ,List and custome objects.

    5: Create getter setter in Aplication class and access any where in project.



     public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }
        private String data;


        here set and get from activities

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();