Отправка действий пользователя к действиям в backstack

Я разрабатываю социальное приложение. Предположим, у меня есть стек действий A -> B -> C -> D D находится на переднем плане, и пользователь нажимает кнопку «как» на что-то там (сообщение, комментарий, пользователь и т. Д.). Каков наилучший способ уведомить обо всех других действиях об этом действии, чтобы обновить их данные? Здесь я вижу 3 варианта:

  1. Используйте локальную базу данных и некоторые загрузчики для автоматического обновления данных. Однако для этого требуется много кода, если у нас есть разные модели данных с общими данными (например, BasicUserInfo , UserInfo , DetailedUserInfo ).
  2. Используйте EventBus с липкими событиями (продюсерами Отто). В этом случае я должен уведомлять ТОЛЬКО операции backstack и игнорировать те, которые будут созданы. Также мне приходится управлять событиями.
  3. Используйте простой шаблон наблюдателя с помощью WeakReferences для операций backstack. Но тогда у меня есть проблема с убитыми действиями, которые будут повторно создаваться.

Реальный пример:

В Instagram: я открываю профиль конкретного пользователя (A), там я открываю какую-то конкретную запись (B), снова профиль (A) и т. Д. A -> B -> A -> B -> A …. Так что это Каждый раз загружает данные из Интернета. На шаге «n + 1» появляется новый комментарий к сообщению. Если я начну возвращаться через свою заднюю часть, я увижу, что instagram отправил этот «новый» комментарий для всех операций B без перезагрузки любых данных из Интернета. Поэтому мне интересно, как они это делают.

Solutions Collecting From Web of "Отправка действий пользователя к действиям в backstack"

Чтобы обновить их данные?

Вот ответ. Деятельность не должна владеть данными. Деятельность представляет данные и позволяет пользователю действовать по ней. Сами данные должны быть в отдельном объекте, с которым могут взаимодействовать экземпляры активности, Модель.

Кроме того, не следует полагать, что в back-stack всегда есть экземпляр активности. Эти действия могут быть уничтожены, а затем повторно созданы как разные объекты по системе, когда пользователь перейдет обратно. Данные всегда обновляются, когда вся деятельность создается.

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

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

В качестве шаблона вы можете создавать классы Model для вовлеченных объектов данных. Напишите интерфейс API интерфейса, чтобы поговорить с сервером. А затем поместите уровень кэша перед интерфейсом API. Кэш сохранит исходящие изменения и входящие обновления на / из уровня API и просто отразит запросы данных, когда вызов сервера не нужен.

Кэш должен делать 3 вещи главным образом:

  1. Вывод: по мере поступления новых данных отбрасывайте наименее важные данные, поэтому кеш остается фиксированным. Большинство реализаций кэш-памяти ( например, этот ) делают это автоматически.
  2. Invalidate: несколько раз, из-за действия пользователя или внешнего события на стороне сервера, некоторые данные должны быть обновлены.
  3. Истекает: данные могут быть установлены с ограничением по времени и будут автоматически выселены. Это полезно при обеспечении периодического обновления данных.

В настоящее время большинство реализаций кэша реализованы в необработанных байтах. Я бы рекомендовал использовать что-то вроде Realm , объект db и обернуть его в кеш, как функции. Следовательно, типичным потоком запросов пользовательских твитов будет:

  1. Отобразится действие.
  2. Активность привязывается к службе данных и выражает свою заинтересованность в «твитах».
  3. Служба данных просматривает таблицу Tweets кэша db для последнего выбранного списка твитов и немедленно возвращает это.
  4. Но служба данных также вызывает сервер, чтобы дать чириканье после отметки времени последнего твита, который он имеет локально в db.
  5. Сервер возвращает последний набор твитов.
  6. Служба данных обновляет все связанные действия, которые проявили интерес к твитам, с новыми входящими данными. Эти данные также реплицируются локально в кэше db. На этом этапе таблица твитов также оптимизируется путем удаления старых записей.
  7. Активность отвлекает от службы данных, поскольку деятельность уходит, останавливается, уничтожается и т. Д.
  8. Если никакой связанной деятельности не интересует «твиты», служба данных перестает загружать больше твитов.

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

TLDR; Отделите управление данными от Activities, а затем вы сможете развить его независимо от проблем пользовательского интерфейса.

Основной вариант использования системы уведомлений (событие, наблюдатель, BroadcastReceiver , …) – это когда вы хотите, чтобы получатель действовал более или менее немедленно, когда что-то происходит.

Я думаю, что здесь не так: операции backstack не должны действовать немедленно, поскольку они не видны. Кроме того, они могут даже больше не существовать (убиты / заморожены). На самом деле им нужно получить последние данные, когда они вернутся на передний план (возможно, после воссоздания).

Почему бы просто не запустить обновление в onStart() или onResume() (используя Loader или что-нибудь, что вы уже используете)?
Если статус «понравился» должен быть сохранен, вы можете сделать это в D onPause() . Если нет, любимый объект может быть сохранен в глобальной переменной (которая на самом деле является липким событием)

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

Предположим, что в вашей деятельности D:

 private void liked() { Log.d("liked", "Broadcasting message"); Intent intent = new Intent("like-event"); // You can also include some extra data. intent.putExtra("message", "my like event occurs!"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } 

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

Например, в вашей деятельности A, B, C:

 @Override public void onCreate(Bundle savedInstanceState) { ... // Register to receive messages. // We are registering an observer (mMessageReceiver) to receive Intents // with actions named "custom-event-name". LocalBroadcastManager.getInstance(this).registerReceiver(mLikeEventReceiver , new IntentFilter("like-event")); } // Our handler for received Intents. This will be called whenever an Intent // with an action named "like-event" is broadcasted. private BroadcastReceiver mLikeEventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Get extra data included in the Intent String message = intent.getStringExtra("message"); Log.d("receiver", "Got message: " + message); } }; @Override protected void onDestroy() { // Unregister since the activity is about to be closed. LocalBroadcastManager.getInstance(this).unregisterReceiver(mLikeEventReceiver ); super.onDestroy(); } 

Ссылки: [ http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html%5D%5B1%5D [ как использовать LocalBroadcastManager? [ https://androidcookbook.com/Recipe.seam?recipeId=4547%5D%5B3%5D

  1. [1]: http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

  2. [2]: как использовать LocalBroadcastManager?

  3. [3]: https://androidcookbook.com/Recipe.seam?recipeId=4547

Классический способ обработки этого типа вещей – использовать BroadcastReceivers .

Вот пример получателя:

 public class StuffHappenedBroadcastReciever extends BroadcastReceiver { private static final String ACTION_STUFF_HAPPENED = "stuff happened"; private final StuffHappenedListener stuffHappenedListener; public StuffHappenedBroadcastReciever(@NonNull Context context, @NonNull StuffHappenedListener stuffHappenedListener) { this.stuffHappenedListener = stuffHappenedListener; context.registerReceiver(this, new IntentFilter(ACTION_STUFF_HAPPENED)); } public static void notifyStuffHappened(Context context, Bundle data) { Intent intent = new Intent(ACTION_STUFF_HAPPENED); intent.putExtras(data); context.sendBroadcast(intent); } @Override public void onReceive(Context context, Intent intent) { stuffHappenedListener.onStuffHappened(intent.getExtras()); } public interface StuffHappenedListener { void onStuffHappened(Bundle extras); } } 

И как приложить его к деятельности:

 public class MainActivity extends AppCompatActivity implements StuffHappenedBroadcastReciever.StuffHappenedListener { private StuffHappenedBroadcastReciever mStuffHappenedReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mStuffHappenedReceiver = new StuffHappenedBroadcastReciever(this, this); } @Override protected void onDestroy() { unregisterReceiver(mStuffHappenedReceiver); super.onDestroy(); } @Override public void onStuffHappened(Bundle extras) { // do stuff here } } 

«OnStuffHappened» будет вызван до тех пор, пока активность активна.

Я согласен с подходом @bwt. Эти системы уведомлений должны иметь значение, если вы хотите немедленно сообщить об этом.

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

При извлечении данных с вашего сервера вам также нужна копия ваших моделей данных в локальной базе данных. Прежде чем вы будете пинговать свой сервер, когда, например, есть что-то вроде сообщения пользователя, вам нужно установить это как Flag в локальной базе данных и отправить свой запрос Http на ваш сервер, чтобы сказать «Эй, этот пост понравился». И позже, когда вы получите ответ от этого запроса, если он будет успешным или нет, попробуйте снова изменить этот флаг.

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

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

Поскольку многие другие ответы не ускользнули, это классический пример, когда BroadcastReceiver легко выполнил бы свою работу.

Я бы также рекомендовал использовать класс LocalBroadcastManager совместно с BroadcastReceiver. Из документации BroadcastReceiver:

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

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

Шаг 1:

Создайте интерфейс следующим образом

 public interface ActivityEventListener { ActivityData getData( Context context, Activity activity ); } 

Шаг 2:

Создайте BaseActivity для ссылки на все действия ur, которые у вас есть в вашем приложении, и реализуйте интерфейс следующим образом

 public class BaseActivity extends Activity { protected AcitivityData mData= null; @Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); } protected ActivityEventListener mListener = new ActivityEventListener() { @Override public ActivityData getData( Context context, Activity activity ) { // TODO Auto-generated method stub return mData; } }; } 

Шаг 3: Расширяет вашу собственную активность с помощью BaseActivity, например A или B или C ……..

Открытый класс A расширяет BaseActivity {

  ActivityData mData; @Override protected void onCreate( Bundle savedInstanceState ) { mData = mListener.getData(this,this); updateWidgets(mData); } 

}

Где updateWidgets – это функция, в которой вы можете определить элементы пользовательского интерфейса и использовать данные, которые у вас есть с интерфейсом

Поскольку все ваши действия B / C / so могут получить ссылку ActivityData. Действия формы backstack начнут выполнение через onStart () пользователь может обрабатывать действия в том же самом характере, поскольку детали существуют в ActivityData

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