Как правильно использовать Google Plus для входа в систему с несколькими действиями?

Что было бы хорошим / рекомендуемым способом связывания жизненного цикла клиента api Google+ с потоком многозадачного приложения? Сделать действия зависят от метода onConnected api client, чтобы вызвать его функциональность, использовать его как одноразовую «активацию» или, может быть, что-то еще?

В настоящее время я пытаюсь понять, как правильно использовать знак Google+ в своем приложении для Android, в котором задействовано несколько операций.

Идея состоит в том, чтобы на первом этапе использовать знак G + только для аутентификации пользователя и получения электронной почты, отправки уведомлений и тому подобного. В конце концов я планирую выпустить другие функции Google, например, Карты или другие сервисы Google Play, поэтому я думаю, что это уже полезно реализовать.

Тем не менее, мое приложение не ведет себя так, как ожидалось, и я сузил проблему до того, что я еще не понял знак G + в цикле приложений, когда присутствует более одного действия.

Каков правильный или рекомендуемый способ реализации этого метода auth? Может ли быть какая-то модель, которая могла бы помочь мне в правильном направлении?

Например, я нашел очень простую диаграмму жизненного цикла клиента api , но как это связано с потоком приложения?

Первоначально у меня есть функция входа в систему, где я помещаю кнопку входа. Следуя руководству Google, я могу войти в систему, и когда вызывается метод onConnected, я запускаю домашнюю активность (вроде как панель инструментов или главный экран приложения).

Это работает несколько. Например, что было бы хорошим способом обработки onStart и onStop для каждого вида деятельности? Следует ли мне повторно подключать и повторно аутентифицировать клиент api каждый раз для каждого вида деятельности? Так что, может быть, это хорошая идея иметь BaseActivity для реализации всего этого.

Другая проблема заключается в том, должен ли я использовать один и тот же объект-клиент api и каким-то образом передавать его или, возможно, хранить его в классе Base Activity? Или я должен каждый раз создавать и инициализировать новый клиентский объект api?

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

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

Любые предложения или указатели в правильном направлении очень ценятся.

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

Solutions Collecting From Web of "Как правильно использовать Google Plus для входа в систему с несколькими действиями?"

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

  1. Реализуйте в основном в baseactivity, и другие расширяют это. Это соединение / разъединение в каждом действии, но с кодом только в одном месте.
  2. Внедрить соединение / отсоединение в фрагменте и включить его в действия, требующие авторизации. Это полезно, если у вас уже есть базовая активность, которую вы не можете продлить (например, некоторые игры).
  3. Внедрите сервис для подключения / отключения. Это может привести к возбуждению трансляции или аналогичному, если требуется вход.

Все эти работы, и я видел, как все они использовались в реальных приложениях. Главное, чтобы помнить, состоит в том, чтобы отделить 99% -ную логику (пользователь либо подписан, либо выписан, и об этом вам сообщается) из-за относительно редкого «использования в настоящий момент». Так, например, вы могли бы отключить onConnected / onConnection, но в основном вы игнорируете или просто слегка перебрасываете состояние приложения. Только на экране с кнопкой входа в систему вам нужно разрешение результата соединения и материал onActivityResult. Подумайте о соединении сервисов Google Play как о том, чтобы в основном запрашивать состояние пользователя, а не подписывать их, и все должно быть в порядке.

Я согласен с ответом Яна Барбера, но для того, чтобы объяснить немного дальше, ваша Activity должна рассматриваться в двух типах: Activity s, которые разрешают вход, и Activity s, которые требуют входа.

Большинство Activity не относятся к аутентификации пользователя и будут иметь одинаковую логику в вашем приложении. Они создадут GoogleApiClient , который подключится к процессу сервисов Google Play, запущенному на устройстве, и прочитает состояние входа в onConnected() пользователя – возврат onConnected() если пользователь onConnectionFailed() , и onConnectionFailed() если нет. Большая часть вашей Activity s захочет сбросить состояние вашего приложения и запустить вашу LoginActivity если пользователь не был подписан. Каждое действие должно содержать собственный экземпляр GoogleApiClient поскольку это легкий объект, используемый для доступа к общему состоянию, GoogleApiClient в Google Play Услуг. Такое поведение может быть, например, инкапсулировано в общий класс BaseActivity или совместно SignInFragment класс SignInFragment , но каждый экземпляр должен иметь свой собственный экземпляр GoogleApiClient .

Однако ваша LoginActivity должна быть реализована по-разному. Он также должен создать GoogleApiClient , но когда он получает onConnected() указывающий, что пользователь подписан, он должен запустить соответствующее действие для пользователя и finish() . Когда ваш LoginActivity получает onConnectionFailed() указывающий, что пользователь не подписан, вы должны попытаться разрешить проблемы с startResolutionForResult() .

0. TL; DR

Для нетерпеливого кодера в GitHub можно найти рабочую версию следующей реализации.

После многократного переписывания кода активности входа во многие разные приложения легкое (и не очень элегантное) решение создало клиент Google API как объект класса приложения. Но, поскольку состояние соединения влияет на поток UX, я никогда не был доволен этим подходом.

Сокращая нашу проблему только до концепции соединения , мы можем считать, что:

  1. Он скрывает клиента API Google.
  2. Он имеет конечные состояния.
  3. Это (скорее) уникально.
  4. Текущее состояние влияет на поведение приложения.

1. Шаблон прокси-сервера

Поскольку Connection инкапсулирует GoogleApiClient , он будет реализовывать ConnectionCallbacks и OnConnectionFailedListener :

 @Override public void onConnected(Bundle hint) { changeState(State.OPENED); } @Override public void onConnectionSuspended(int cause) { changeState(State.CLOSED); connect(); } @Override public void onConnectionFailed(ConnectionResult result) { if (currentState.equals(State.CLOSED) && result.hasResolution()) { changeState(State.CREATED); connectionResult = result; } else { connect(); } } 

Действия могут связываться с классом Connection с помощью методов connect , disconnect и revoke , но их поведение определяется текущим состоянием. Конечным автоматом требуются следующие методы:

 protected void onSignIn() { if (!googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiClient.connect(); } } protected void onSignOut() { if (googleApiClient.isConnected()) { Plus.AccountApi.clearDefaultAccount(googleApiClient); googleApiClient.disconnect(); googleApiClient.connect(); changeState(State.CLOSED); } } protected void onSignUp() { Activity activity = activityWeakReference.get(); try { changeState(State.OPENING); connectionResult.startResolutionForResult(activity, REQUEST_CODE); } catch (IntentSender.SendIntentException e) { changeState(State.CREATED); googleApiClient.connect(); } } protected void onRevoke() { Plus.AccountApi.clearDefaultAccount(googleApiClient); Plus.AccountApi.revokeAccessAndDisconnect(googleApiClient); googleApiClient = googleApiClientBuilder.build(); googleApiClient.connect(); changeState(State.CLOSED); } 

2. Шаблон состояния

Это поведенческий шаблон, позволяющий объекту изменять его поведение при изменении его внутреннего состояния. В книге шаблонов проектирования GoF описывается, как TCP-соединение может быть представлено этим шаблоном (что также является нашим делом).

Состояние из конечного автомата должно быть singleton , и проще всего сделать это на Java, чтобы создать Enum named State следующим образом:

 public enum State { CREATED { @Override void connect(Connection connection) { connection.onSignUp(); } @Override void disconnect(Connection connection) { connection.onSignOut(); } }, OPENING {}, OPENED { @Override void disconnect(Connection connection) { connection.onSignOut(); } @Override void revoke(Connection connection) { connection.onRevoke(); } }, CLOSED { @Override void connect(Connection connection) { connection.onSignIn(); } }; void connect(Connection connection) {} void disconnect(Connection connection) {} void revoke(Connection connection) {} 

Класс Connection содержит контекст, то есть текущее состояние, определяющее способ connect , disconnect и revoke .

 public void connect() { currentState.connect(this); } public void disconnect() { currentState.disconnect(this); } public void revoke() { currentState.revoke(this); } private void changeState(State state) { currentState = state; setChanged(); notifyObservers(state); } 

3. Шаблон Singleton

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

 public static Connection getInstance(Activity activity) { if (null == sConnection) { sConnection = new Connection(activity); } return sConnection; } public void onActivityResult(int result) { if (result == Activity.RESULT_OK) { changeState(State.CREATED); } else { changeState(State.CLOSED); } onSignIn(); } private Connection(Activity activity) { activityWeakReference = new WeakReference<>(activity); googleApiClientBuilder = new GoogleApiClient .Builder(activity) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(Plus.API, Plus.PlusOptions.builder().build()) .addScope(new Scope("email")); googleApiClient = googleApiClientBuilder.build(); currentState = State.CLOSED; } 

4. Наблюдаемый шаблон

Класс Connection расширяет Java Observable , поэтому 1 или несколько действий могут наблюдать изменения состояния:

 @Override protected void onCreate(Bundle bundle) { connection = Connection.getInstance(this); connection.addObserver(this); } @Override protected void onStart() { connection.connect(); } @Override protected void onDestroy() { connection.deleteObserver(this); connection.disconnect(); } @Override protected void onActivityResult(int request, int result, Intent data) { if (Connection.REQUEST_CODE == request) { connection.onActivityResult(result); } } @Override public void update(Observable observable, Object data) { if (observable != connection) { return; } // Your presentation logic goes here... }