分离 Activity 和 GoogleApiClient 的关注点

Separating the Concerns of Activity and GoogleApiClient

像往常一样,我的 LoginActivity 中有很多代码,我真的更愿意将 Activity 职责与 Google 游戏登录问题分开。

多次重写此 LoginActivity 代码后,在许多不同的应用程序中,简单(但不是那么优雅)的解决方案是创建 Google API 客户端作为 Application class 对象。但是,由于连接状态会影响用户体验流程,我对这种方法一直不满意。

是否有一种优雅的方式将 GoogleApiClient 放在 Activity 之外?

0。长话短说

对于没有耐心的编码员,可以在 GitHub.

上找到以下实现的工作版本

将我们的问题简化为连接概念,我们可以考虑:

  1. 它有有限的状态。
  2. 封装连接客户端
  3. 它(更确切地说)是独一无二的。
  4. 当前状态影响应用程序的行为。

1。状态模式

这是一种行为模式,允许对象在其内部状态发生变化时改变其行为。 GoF Design Patterns book 描述了如何用这种模式表示 TCP 连接(这也是我们的例子)。

状态机的状态应该是 singleton,在 Java 中最简单的方法是创建名为 StateEnum,如下所示:

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

    void connect(Connection connection) {}
    void disconnect(Connection connection) {}
    void revoke(Connection connection) {}
}

Activity 将通过方法 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);
}

2。代理模式

classGoogleConnection继承Connection封装了GoogleApiClient,所以必须同时提供ConnectionCallbacksOnConnectionFailedListener如下:

@Override
public void onConnected(Bundle connectionHint) {
    changeState(State.OPENED);
}

@Override
public void onConnectionSuspended(int cause) {
    mGoogleApiClient.connect();
}

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (state.equals(State.CLOSED) && result.hasResolution()) {
        changeState(State.CREATED);
        connectionResult = result;
    } else {
        connect();
    }
}

public void onActivityResult(int resultCode) {
    if (resultCode == Activity.RESULT_OK) {
        connect();
    } else {
        changeState(State.CREATED);
    }
}

本说明的第二步需要方法onSignIn()onSignUp()onSignOut()onRevokeAndSignOut

public void onSignUp() {
    try {
        Activity activity = activityWeakReference.get();
        changeState(State.OPENING);
        connectionResult.startResolutionForResult(activity, REQUEST_CODE);
    } catch (IntentSender.SendIntentException e) {
        changeState(State.CREATED);
        mGoogleApiClient.connect();
    }
}

public void onSignIn() {
    if (!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting()) {
        mGoogleApiClient.connect();
    }
}

public void onSignOut() {
    Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
    mGoogleApiClient.disconnect();
    changeState(State.CLOSED);
    mGoogleApiClient.connect();
}

public void onRevokeAndSignOut() {
    Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
    Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient);
    changeState(State.CLOSED);
    mGoogleApiClient = mGoogleApiClientBuilder.build();
    mGoogleApiClient.connect();
}

3。单例模式

由于不需要重复重新创建此 class,我们将其作为单例提供:

public static Connection getInstance(Activity activity) {
    if (null == sConnection) {
        sConnection = new GoogleConnection(activity);
    }

    return sConnection;
}

public void onActivityResult(int result) {
    if (result == Activity.RESULT_OK) {
        changeState(State.CREATED);
    } else {
        changeState(State.CLOSED);
    }
    onSignIn();
}

private GoogleConnection(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;

    googleApiClient.connect();
}

4。可观察模式

Connectionclass扩展了JavaObservable,所以一个或多个activity可以观察状态变化:

@Override
protected void onCreate(Bundle bundle) {
    mConnection = GoogleConnection.getInstance(this);
    mConnection.addObserver(this);
}

@Override
protected void onDestroy() {
    mConnection.deleteObserver(this);
}

@Override
protected void onActivityResult(int request, int result, Intent data) {
    if (Connection.REQUEST_CODE == request) {
        mConnection.onActivityResult(result);
    }
}

@Override
public void update(Observable observable, Object data) {
    if (observable == mGoogleConnection) {
        // UI/UX magic happens here ;-)
    }
}