像往常一样,我的LoginActivity中有很多代码,我真的更愿意将活动职责与Google Play登录问题分开.
在多次重写此LoginActivity代码之后,在许多不同的应用程序中,简单(而不是那么优雅)的解决方案是将Google API客户端创建为Application类对象.但是,由于连接状态会影响用户体验流程,因此我从未对这种方法感到高兴.
是否有一种优雅的方式将GoogleApiClient置于活动之外?
解决方法
0. TL; DR
对于不耐烦的编码器,可以在GitHub找到以下实现的工作版本.
将我们的问题仅减少到连接概念,我们可以考虑:
>它有限状态.
>它封装了连接客户端.
>它(相当)是独一无二的.
>当前状态会影响应用程序的行为.
1.国家格局
这是一种行为模式,允许对象在其内部状态发生变化时改变其行为. GoF Design Patterns book描述了这种模式如何表示TCP连接(这也是我们的例子).
状态机中的状态应该是单例,并且在Java中最简单的方法是创建名为State的Enum,如下所示:
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()方法与Connection抽象类(包含上下文)进行通信.当前状态定义了这些方法的行为方式:
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.代理模式
GoogleConnection类继承自Connection并封装了GoogleApiClient,因此它必须提供ConnectionCallbacks和OnConnectionFailedListener,如下所示:
@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.单身模式
由于不需要重复重新创建此类,因此我们将其作为单例提供:
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.可观察的模式
Connection类扩展了Java Observable,因此一个或多个活动可以观察状态更改:
@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 ;-) } }