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

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

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

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

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

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

4b9b3361

Ответ 1

для обновления данных?

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

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

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

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

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

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

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

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

  • Отображается действие.
  • Активность привязывается к службе данных и выражает свою заинтересованность в "твитах".
  • Служба данных просматривает таблицу Tweets кэша db для последнего выбранного списка твитов и немедленно возвращает это.
  • Но служба данных также вызывает сервер, чтобы дать чириканье после отметки времени последнего твита, который он локально находится в db.
  • Сервер возвращает последний набор твитов.
  • Служба данных обновляет все связанные действия, которые проявили интерес к твитам, с новыми входящими данными. Эти данные также реплицируются локально в кэше db. На этом этапе таблица твитов также оптимизируется путем удаления старых записей.
  • Действия отключаются от службы данных, поскольку активность уходит, останавливается, уничтожается и т.д.
  • Если никакой связанной деятельности не интересует "твиты", служба данных перестает загружать больше твитов.

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

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

Ответ 2

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

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

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

Ответ 3

Вы можете использовать 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][1] [как использовать LocalBroadcastManager? [https://androidcookbook.com/Recipe.seam?recipeId=4547][3]

Ответ 4

Классическим способом обработки этого типа является использование 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" будет вызван до тех пор, пока активность активна.

Ответ 5

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

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

Шаг 1:

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

public interface ActivityEventListener
{


    ActivityData getData( Context context,
            Activity activity );


}

Шаг 2:

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

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​​p >

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