Каков наилучший способ обмена данными между действиями? - PullRequest
227 голосов
/ 02 февраля 2011

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

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

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

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

Ответы [ 14 ]

460 голосов
/ 02 февраля 2011

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

  • Отправка данных внутри цели
  • Статические поля
  • 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 interface . Его сложнее реализовать, но он значительно увеличил скорость по сравнению с Serializable.

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

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

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

Используйте класс Singleton

Есть класс для хранения данных:

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);

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

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

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

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

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

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

22 голосов
/ 02 февраля 2011

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

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

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

16 голосов
/ 30 октября 2011

Делайте то, что Google приказывает вам делать!здесь: http://developer.android.com/resources/faq/framework.html#3

  • Примитивные типы данных
  • Непостоянные объекты
  • Класс Singleton - мой любимый: D
  • Aоткрытое статическое поле / метод
  • Хэш-карта слабых ссылок на объекты
  • Постоянные объекты (настройки приложения, файлы, контент-провайдеры, БД SQLite)
14 голосов
/ 02 февраля 2011

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

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

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

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

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

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

7 голосов
/ 03 февраля 2011

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

2 голосов
/ 04 ноября 2018

Существует новый и лучший способ обмена данными между действиями, это LiveData . Обратите внимание, в частности, на эту цитату со страницы разработчика Android:

Тот факт, что объекты LiveData учитывают жизненный цикл, означает, что вы можете делиться ими между несколькими действиями, фрагментами и службами. Для простоты примера вы можете реализовать класс LiveData как singleton

Смысл этого огромен - любые данные модели могут быть разделены в общем одноэлементном классе внутри оболочки LiveData. Это может быть введено из действий в их соответствующие ViewModel для проверки. И вам больше не нужно беспокоиться о слабых ссылках для предотвращения утечек памяти.

2 голосов
/ 18 июля 2017

Существует несколько способов обмена данными между действиями

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

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

2: Используя ключевое слово static, определите переменную как public static и используйте любое место в проекте

      public static int sInitialValue=0;

использовать в любом месте проекта, используя classname.variableName;

3: Использование базы данных

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

4: Использование общих настроек

намного проще, чем база данных. но есть некоторые ограничения: вы не можете сохранять объекты ArrayList, List и custome.

5: Создайте установщик геттера в классе Aplication и получите доступ к любому месту в проекте.

      private String data;
      public String getData() {
          return data;
      }

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

здесь установить и получить от деятельности

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

         String data=((YourApplicationClass)getApplicationContext()).getData();  
2 голосов
/ 29 апреля 2014

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

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

1 голос
/ 28 сентября 2014

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

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

1 Код для входа в системуpage

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

2 код на главной странице

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
1 голос
/ 01 августа 2013

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

...