对于我的项目,我正在使用Retrofit进行API调用。 对于身份验证我正在使用JWT令牌。 对于该令牌的存储和刷新流程,我正在使用Google's AccountManager。
ApiService类是我构建的单例,如下所示:
private ApiService(AccountManager accountManager) {
mAccountManager = accountManager;
build();
}
public static synchronized ApiService getInstance(AccountManager accountManager) {
if (mInstance == null) {
mInstance = new ApiService(accountManager);
}
return mInstance;
}
在本课程中,我正在构建OkHttp3客户端和Retrofit服务。
当服务器响应挑战时,Okhttp3有一个很好的方法,所以我这样设置:
OkHttpClient client = new OkHttpClient.Builder()
.authenticator(new ApiAuthenticator(mAccountManager))
正如您所看到的,我正在设置Okhttp3身份验证器的自定义实现,如下所示:
/**
* 2017 App-vise.
* Created by daangeurts on 31/07/2017.
*/
public class ApiAuthenticator implements Authenticator {
private static final String TAG = "ApiAuthenticator";
private AccountManager accountManager;
ApiAuthenticator(AccountManager accountManager) {
this.accountManager = accountManager;
}
private static int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
/**
* Returns a request that includes a credential to satisfy an authentication challenge in {@code
* response}. Returns null if the challenge cannot be satisfied.
*
* @param route
* @param response
*/
@Nullable
@Override
public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
if (response.request().url().encodedPath().startsWith("login_check") || response.request().url().encodedPath().startsWith("token"))
return null;
if (responseCount(response) >= 2) {
// If both the original call and the call with refreshed token failed,
// it will probably keep failing, so don't try again.
return null;
}
for (Challenge challenge : response.challenges()) {
if (challenge.scheme().equals("Bearer")) {
Account[] accounts = accountManager.getAccountsByType(AuthConstants.ACCOUNT_TYPE);
if (accounts.length != 0) {
String oldToken = accountManager.peekAuthToken(accounts[0], AuthConstants.AUTHTOKEN_TYPE_FULL_ACCESS);
if (oldToken != null) {
accountManager.invalidateAuthToken(AuthConstants.ACCOUNT_TYPE, oldToken);
}
try {
String token = accountManager.blockingGetAuthToken(accounts[0], AuthConstants.AUTHTOKEN_TYPE_FULL_ACCESS, false);
if (token == null) {
accountManager.removeAccount(accounts[0], null, null);
}
if (token != null) {
Request.Builder builder = response.request().newBuilder();
return builder.header("Authorization", "Bearer " + token).build();
}
} catch (OperationCanceledException | AuthenticatorException e) {
e.printStackTrace();
Log.d(TAG, e.getLocalizedMessage());
}
}
}
}
return null;
}
}
我的某些功能的存储库如下所示:
public class ApiCheckinRepository implements CheckinRepository {
private AccountManager accountManager;
public ApiCheckinRepository(AccountManager accountManager) {
this.accountManager = accountManager;
}
@Override
public Observable<Response<Message>> checkin(QrCode qrCode) {
return ApiService.getInstance(accountManager).checkin(qrCode);
}
}
但是现在我得到了由accountManager依赖引起的内存泄漏,我再也看不到解决方案......
答案 0 :(得分:0)
希望它能帮助您解决问题: -
public class AccountLeakHandler {
public static AccountManagerFuture<Bundle> safeGetAuthToken(AccountManager accountManager,
Account account,
String authTokenType,
Bundle options,
Activity activity,
AccountManagerCallback<Bundle> callback,
Handler handler) {
return accountManager.getAuthToken(
account,
authTokenType,
options,
null,
new ResolveLeakAccountManagerCallback(callback, activity),
handler);
}
public static class ResolveLeakAccountManagerCallback implements AccountManagerCallback<Bundle> {
private AccountManagerCallback<Bundle> originalCallback = null;
private Activity originalActivity = null;
public ResolveLeakAccountManagerCallback(AccountManagerCallback<Bundle> callback, Activity activity) {
originalCallback = callback;
originalActivity = activity;
}
@Override
public void run(AccountManagerFuture<Bundle> future) {
Bundle bundle = null;
try {
bundle = future.getResult();
} catch (Exception e) {
// error happen
}
if (bundle == null) {
callAndClear(future);
} else {
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
if (intent != null) {
if (originalActivity != null) {
try {
//make FutureTask callback again
new RInstance(FutureTask.class, future).setValue("state", 0);
} catch (Exception e) {}
originalActivity.startActivity(intent);
} else {
callAndClear(future);
}
} else {
callAndClear(future);
}
}
}
private void callAndClear(AccountManagerFuture<Bundle> future) {
if (originalCallback != null) {
originalCallback.run(future);
originalCallback = null;
}
originalActivity = null;
}
}
}
了解更多信息请访问以下链接: -