Как сохранить дополнительную ценность данных после переключения действий? [Дубликат]

Проблема

C ++ включает полезные общие функции, такие как std::for_each и std::transform, что может быть очень удобно. К сожалению, они также могут быть довольно громоздкими в использовании, особенно если functor , который вы хотите применить, уникален для конкретной функции.

#include 
#include 

namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };
}

void func(std::vector& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);
}

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

В C ++ 03 у вас может возникнуть соблазн написать что-то вроде следующего, чтобы сохранить functor local:

void func2(std::vector& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

однако это недопустимо, f не может быть передано функции template в C ++ 03.

новое решение

C ++ 11 вводит lambdas, чтобы вы могли написать встроенный анонимный функтор для замены struct f. Для небольших простых примеров это может быть более чистым для чтения (он хранит все в одном месте) и потенциально проще поддерживать, например, в простейшей форме:

void func3(std::vector& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Лямбда-функции - это просто синтаксический сахар для анонимных функторов .

Типы возвращаемых данных

В простых случаях для вас выводится тип возврата лямбда, например:

void func4(std::vector& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

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

void func4(std::vector& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

Чтобы разрешить это, вам разрешено явно указывать тип возврата для лямбда-функции, используя -> T:

void func4(std::vector& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

«Захват» переменных

До сих пор мы не использовали ничего, кроме того, что было передано лямбда внутри него, но мы также можем использовать другие переменные, в пределах лямбда. Если вы хотите получить доступ к другим переменным, вы можете использовать предложение capture ([] выражения), которое до сих пор не использовалось в этих примерах, например:

void func5(std::vector& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });
}

Вы можете выполнять захват обоими ссылку и значение, которые вы можете указать с помощью & и = соответственно:

  • [&epsilon] захват по ссылке
  • [&] захватывает все переменные, используемые в lambda по ссылке
  • [=] фиксирует все переменные, используемые в лямбда по значению
  • [&, epsilon] захватывает переменные, такие как [& amp;], но epsilon по значению
  • [=, &epsilon] захватывает переменные, такие как [=], но epsilon по ссылке

Порожденный operator() по умолчанию const, с импликацией, которая захватывает, будет const когда вы обращаетесь к ним по умолчанию. Это приводит к тому, что каждый вызов с одним и тем же входом даст тот же результат, однако вы можете пометить лямбда как mutable , чтобы запросить, что созданный operator() не const.

203
задан Wai Ha Lee 28 December 2015 в 17:57
поделиться

13 ответов

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

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

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

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

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

1
ответ дан AedonEtLIRA 16 August 2018 в 03:49
поделиться

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

  • Отправка данных внутри намерения
  • Статические поля
  • 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.

Совместное использование данных, не сохраняющихся на диске

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

Примечание: иногда, когда пользователь покидает вашу деятельность (не покидая ее), 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();

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

Синтаксис приложения - это экземпляр 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);

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

Персистировать объекты на диске

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

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

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

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

433
ответ дан Artem Sokolov 16 August 2018 в 03:49
поделиться
  • 1
    Я бы сказал, что это не "нормальный" путь для более крупных / более сложных данных. Гораздо проще использовать статический синглтон или объект приложения, и он отлично работает. Теперь, когда говорилось, что OP использовал строку в примере, для этого Intent является идеальным и предпочтительным. – Charlie Collins 2 February 2011 в 19:40
  • 2
    Serializable обнаружил серьезные проблемы с производительностью в модели процесса Android. Вот почему они представили Parcelable. Прочитайте Parcelable вместо Serializable в приведенном выше ответе. – Subin Sebastian 14 August 2012 в 03:44
  • 3
    Это передача данных из основной деятельности во вторичную деятельность, а что наоборот? – Dennis 5 December 2012 в 17:03
  • 4
    Это делается с помощью метода setResult. Кроме того, в этом случае вторичная активность должна быть вызвана с использованием метода startActivityForResult. – Cristian 6 December 2012 в 19:24
  • 5
    Отличное резюме! Что касается проблемы уничтожения одиночных элементов, для приложений с большим количеством действий и объектов существует простое решение: используйте подкласс Activity повсюду, а в своем onCreate() проверьте любое статическое поле синглтона, которое вы заполняете при запуске приложение. Если это поле пуст, вернитесь к началу действия, используя FLAG_ACTIVITY_CLEAR_TASK или BroadcastReceiver, чтобы убить другие действия. – Janosch 19 June 2014 в 17:52

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

1
ответ дан avatar 16 August 2018 в 03:49
поделиться

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

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

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

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

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

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

14
ответ дан Charlie Collins 16 August 2018 в 03:49
поделиться
  • 1
    На самом деле, я недавно наткнулся на это в документах: developer.android.com/guide/appendix/faq/framework.html#3 . Для "непостоянных сложных объектов" он рекомендует использовать класс Application для создания и сбрасывания статического синглтона! Таким образом, вы получаете четко определенный жизненный цикл приложения и простоту использования статического синглтона. – Charlie Collins 6 February 2011 в 16:21
  • 2
    этот раздел faq, кажется, теперь удален (я вижу только «непостоянные объекты» и не упоминает класс Application). В любом случае, вы можете уточнить? – Tony Chan 10 May 2012 в 02:27
  • 3
    В настоящее время он находится в developer.android.com/guide/faq/framework.html#3 «Как передавать данные между действиями / службами в одном приложении?» И не упоминать о приложении класс. – Jerry101 14 March 2014 в 04:44
  • 4
    Мне нравится использовать объект Application, следуя прецеденту, установленному в «Android в действии». Но многим потенциальным работодателям это не нравится, когда они видят это в проблемах с кодом. Они могут ошибаться, но они бросают свой вес. BTW: ссылка 'framework.html # 3 больше не работает. – Matt J. 26 April 2017 в 02:24

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

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

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

1
ответ дан Community 16 August 2018 в 03:49
поделиться

Есть разные способы обмена данными между действиями

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

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

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

      public static int sInitialValue=0;

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

3: используя Database

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

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();  
1
ответ дан cricket_007 16 August 2018 в 03:49
поделиться

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

Serializable vs Parcelable

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

public class User implements Parcelable

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

0
ответ дан Diego Venâncio 16 August 2018 в 03:49
поделиться

Обмен данными между примерами активности, передающими электронное письмо после входа в систему

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

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

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

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

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
1
ответ дан Flexo 16 August 2018 в 03:49
поделиться

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

7
ответ дан Jimmy 16 August 2018 в 03:49
поделиться

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

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

2
ответ дан Mark Rosenberg 16 August 2018 в 03:49
поделиться

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

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

1
ответ дан Mike Yockey 16 August 2018 в 03:49
поделиться

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

  • Примитивные типы данных
  • Persistent Objects
  • Singleton class - мой любимый: D
  • Публичное статическое поле / метод
  • HashMap of WeakReferences to Objects
  • Постоянный Объекты (Предпочтения приложений, Файлы, contentProviders, SQLite DB)
15
ответ дан Pixel Elephant 16 August 2018 в 03:49
поделиться
  • 1
    Google Link для постоянных объектов: developer.android.com/guide/topics/data/data-storage.html – NicoMinsk 11 April 2016 в 17:34
  • 2
    Только antipatterns, Singleton class является первым шаблоном проектирования, класс со статическим полем / методом ведет себя как синглеты и создает базу данных для постоянных объектов busniss, иногда это нехорошо, конечно, это не ваша вина, и вы перечисляете возможные способы добиться этого, но я удивляюсь, почему Google усложнил такую ​​очень глупую вещь, проблемы с производительностью или что? !!!! или я не понимаю способ Android? !!!! – La VloZ Merrill 12 May 2016 в 20:47
  • 3
    ссылка не работает :( – Shayan_Aryan 2 November 2016 в 09:23

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

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

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

22
ответ дан WarrenFaith 16 August 2018 в 03:49
поделиться
  • 1
    Обратите внимание, что статика очищается от смерти процесса – EpicPandaForce 19 June 2017 в 16:43
  • 2
    @EpicPandaForce, конечно, а также когда устройство было отключено. – WarrenFaith 19 June 2017 в 16:54
  • 3
    Но если устройство выключено, приложение перезапускается из действия MAIN. После смерти процесса вы перезапускаете все действия, открытые в последний раз, и это может быть страница с подробной информацией, где-то в приложении. – EpicPandaForce 19 June 2017 в 17:07
  • 4
    @EpicPandaForce кажется, что вы пропустили мою иронию, даже если вы Cpt Obvious. – WarrenFaith 19 June 2017 в 17:15
  • 5
    ................... – EpicPandaForce 19 June 2017 в 17:21
Другие вопросы по тегам:

Похожие вопросы: