Google+ APIクライアントのライフサイクルをマルチアクティビティアプリのフローと結びつけるための良い/推奨される方法は何ですか?アクティビティをonConnected APIクライアントメソッドに依存させてその機能をトリガーするか、1回限りの「アクティブ化」として使用するか、それとも完全に別の何かとして使用するか
Androidアプリには複数のアクティビティがあるため、Google +サインインを正しく使用する方法を理解するのに苦労しています。
このアイデアは、最初のフェーズでは、ユーザーを認証し、メールを受け取ったり、通知やそのようなものを送信したりするためだけにG +サインインを使用することです。最終的にはマップや他のGoogle Playサービスのような他のGoogle機能をロールアウトする予定なので、すでに実装しておくと便利です。
ただし、私のアプリは期待どおりに動作しておらず、複数のアクティビティが存在する場合のアプリサイクルのG +サインインをまだ理解していないという事実に問題を絞り込みました。
この認証方法を実装する正しいまたは推奨される方法は何ですか?多分私を正しい方向に導くことができる種類のパターンはありますか?
たとえば、私は 非常に単純な図the api clientのライフサイクルを見つけましたが、これはアプリのフローとどのように関連していますか?
最初はログインアクティビティがあり、サインインボタンを配置しています。以下 Googleのガイド サインインでき、onConnectedメソッドが呼び出されると、ホームアクティビティ(ダッシュボードやアプリのメイン画面など)を開始します。
これはやや機能します。たとえば、各アクティビティのonStartとonStopを処理する良い方法は何でしょうか?すべてのアクティビティで毎回APIクライアントに再接続して再認証する必要がありますか?ですから、これをすべて実装するBaseActivityを用意するのは良い考えかもしれません。
別の問題は、同じAPIクライアントオブジェクトを使用してそれを何らかの方法で渡したり、ベースアクティビティクラスに保存したりする必要があるかどうかです。または毎回新しいAPIクライアントオブジェクトを作成して初期化する必要がありますか?
ログインアクティビティを使用してG +で認証し、メールを取得してローカルデータベースに保存し、ユーザーに「認証済み」または「アクティブ」などのフラグを立てるのはどうですか。これにより、アプリを閉じたり接続を一時停止したりするたびに再認証を行う必要がなくなり、バッテリーをいくらか節約することもできます。
アプリは、実際にはG +の投稿やその他の機能を使用していません。理想的にはオフラインでうまく機能し、初期認証やその他の1回限りの接続などが必要です。
正しい方向への提案やポインタは非常に高く評価されています。
編集:Google+を使用する、見つけたすべてのガイドとチュートリアルを読みました。それらすべてが、単一のアクティビティの観点からこれに対処しています。これは、パターンまたは少なくとも一般的なガイドラインの恩恵を受ける十分に一般的な問題だと思います。
アクティビティごとに再接続しても問題ありません。これを実装する人々について、私が見た方法には大きく3つあります。
これらすべてが機能し、実際にすべてのアプリで使用されているのを見てきました。覚えておくべき主なことは、99%のロジック(ユーザーがサインインまたはサインアウトしていて、そのことを通知されている)を、比較的まれな「現時点でサインインする」ユースケースから分離することです。したがって、たとえば、onConnected/onConnectionが何度も起動に失敗した可能性がありますが、ほとんどの場合、アプリケーションの状態を無視するか、少しだけフリップします。ログインボタンが表示されている画面でのみ、接続結果の解決とonActivityResultなどが必要になります。 Google Play開発者サービスの接続は、主にユーザーのログインではなく、ユーザーの状態を要求するものであると考えてください。問題はありません。
Ian Barberの回答に同意しますが、もう少し詳しく説明すると、Activity
sは、サインインを解決するActivity
sと、サインインが必要なActivity
sの2つのタイプで検討する必要があります。
ほとんどのActivity
sはユーザーの認証に関係なく、アプリでも同じロジックを使用します。彼らは GoogleApiClient を作成します。これは、デバイスで実行されているGoogle Play開発者サービスプロセスに接続し、ユーザーのキャッシュされたサインイン状態を読み取ります。ユーザーがサインインしている場合はonConnected()
を返します、そうでない場合はonConnectionFailed()
。ほとんどのActivity
sは、ユーザーがサインインしていない場合、アプリケーションの状態をリセットしてLoginActivity
を開始する必要があります。各Activity
は、独自のGoogleApiClient
これは、Google Play開発者サービスプロセスが保持する共有状態へのアクセスに使用される軽量オブジェクトであるためです。この動作は、たとえば、共有BaseActivity
クラスまたは共有SignInFragment
クラスにカプセル化できますが、各インスタンスには独自のGoogleApiClient
インスタンスが必要です。
ただし、LoginActivity
は別の方法で実装する必要があります。 GoogleApiClient
も作成する必要がありますが、ユーザーがサインインしていることを示すonConnected()
を受信すると、ユーザーに適切なActivity
を開始し、finish()
。 LoginActivity
がonConnectionFailed()
を受信して、ユーザーがサインインしていないことを示している場合は、startResolutionForResult()
でサインインの問題を解決する必要があります。
せっかちなコーダーの場合、次の実装の作業バージョンは GitHub にあります。
多くの異なるアプリでログインアクティビティコードを何度か書き換えた後、簡単な(そしてそれほどエレガントではない)ソリューションは、アプリケーションクラスオブジェクトとしてGoogle APIクライアントを作成することでした。しかし、接続状態はUXフローに影響を与えるため、このアプローチには満足できませんでした。
問題を接続の概念に限定すると、次のように考えることができます。
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();
}
}
アクティビティは、メソッドconnect
、disconnect
、およびrevoke
を介してConnectionクラスと通信できますが、動作は現在の状態によって決まります。ステートマシンには次のメソッドが必要です。
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);
}
これは、内部状態が変化したときにオブジェクトがその動作を変更できるようにする動作パターンです。 GoFデザインパターンブック は、TCP接続をこのパターンで表現する方法を説明しています(これも私たちの場合です)。
状態マシンからの状態はsingleton
である必要があり、Javaでそれを行う最も簡単な方法は、Enum
という名前の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
クラスは、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);
}
このクラスを繰り返し作成する必要がないため、シングルトンとして提供します。
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;
}
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...
}