Commit c9fbcaf0 by 段启岩

用户token刷新完成

parent c5e2294c
package cn.yunliyunwai.beyondclouds.adapter.common;
import android.util.Log;
import androidx.lifecycle.LiveData;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import cn.yunliyunwai.beyondclouds.data.model.AuthenticationResult;
import cn.yunliyunwai.beyondclouds.data.model.Result;
import cn.yunliyunwai.beyondclouds.viewmodel.AuthenticationViewModel;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.POST;
public class LiveDataCallAdapter<T> implements CallAdapter<T, LiveData<T>> {
private Type responseType;
private AuthenticationViewModel authenticationViewModel;
public LiveDataCallAdapter(Type responseType) {
public LiveDataCallAdapter(Type responseType, AuthenticationViewModel authenticationViewModel) {
this.responseType = responseType;
this.authenticationViewModel = authenticationViewModel;
}
public Type responseType() {
......@@ -26,15 +38,63 @@ public class LiveDataCallAdapter<T> implements CallAdapter<T, LiveData<T>> {
public LiveData<T> adapt(Call<T> call) {
return new LiveData<T>() {
private AtomicBoolean started = new AtomicBoolean(false);
@Override
protected void onActive() {
super.onActive();
private void doRequest(boolean reRequest) {
Call<T> realCall = call;
if (reRequest) {
started.set(false);
realCall = call.clone();
}
if (started.compareAndSet(false, true)) {
call.enqueue(new Callback<T>() {
realCall.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
if(response.code() == 200) {
// 请求成功
postValue(response.body());
} else if (response.code() == 401 && !reRequest) {
// 认证失败,可能是token失效,尝试用refreshToken刷新
AuthenticationViewModel.AuthenticationState authenticationState = authenticationViewModel.getAuthenticationState().getValue();
Log.d(getClass().getName(), "token过期," + authenticationState.name());
// 用户之前没有认证,直接返回未认证
if (authenticationState != AuthenticationViewModel.AuthenticationState.AUTHENTICATED) {
postValue((T) new Result(-2, "未认证", response.errorBody()));
return;
}
// 开始刷新token
Log.d(getClass().getName(), "开始刷新token,refreshToken:," + authenticationViewModel.getRefreshToken());
Call<Result<AuthenticationResult>> refreshTokenCall = createRefreshTokenApiStore().refreshToken(IRefreshTokenApiStore.RefreshTokenForm.create(authenticationViewModel.getRefreshToken()));
refreshTokenCall.enqueue(new Callback<Result<AuthenticationResult>>() {
@Override
public void onResponse(Call<Result<AuthenticationResult>> call, Response<Result<AuthenticationResult>> response) {
Result<AuthenticationResult> result = response.body();
if (result.getCode() != 0) {
// token刷新失败,将当前认证状态改为认证已过期
authenticationViewModel.makeAuthenticationExpire();
postValue((T) new Result(-2, "认证过期", response.errorBody()));
Log.d(getClass().getName(), "token刷新失败." );
} else {
// token刷新成功,重新请求
authenticationViewModel.refreshToken(result.getData());
Log.d(getClass().getName(), "刷新token成功,正在重新发起请求." );
doRequest(true);
}
}
@Override
public void onFailure(Call<Result<AuthenticationResult>> call, Throwable t) {
// token刷新失败,将当前认证状态改为认证已过期
authenticationViewModel.makeAuthenticationExpire();
postValue((T) new Result(-2, "认证过期", response.errorBody()));
Log.d(getClass().getName(), "token刷新失败." );
}
});
} else {
postValue((T) new Result(-10, "请求出错", response.errorBody()));
}
......@@ -49,6 +109,53 @@ public class LiveDataCallAdapter<T> implements CallAdapter<T, LiveData<T>> {
});
}
}
@Override
protected void onActive() {
super.onActive();
doRequest(false);
}
};
}
private Retrofit createCommonRetrofit() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS).build();
return new Retrofit.Builder()
.baseUrl("https://api.yunliyunwai.cn/api/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
private IRefreshTokenApiStore createRefreshTokenApiStore() {
return createCommonRetrofit().create(IRefreshTokenApiStore.class);
}
private interface IRefreshTokenApiStore {
class RefreshTokenForm {
private String refreshToken;
private RefreshTokenForm(String refreshToken) {
this.refreshToken = refreshToken;
}
public static RefreshTokenForm create(String refreshToken) {
return new RefreshTokenForm(refreshToken);
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}
@POST("auth/refresh")
Call<Result<AuthenticationResult>> refreshToken(@Body RefreshTokenForm refreshTokenForm);
}
}
......@@ -8,11 +8,24 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.inject.Inject;
import javax.inject.Singleton;
import cn.yunliyunwai.beyondclouds.data.model.Result;
import cn.yunliyunwai.beyondclouds.viewmodel.AuthenticationViewModel;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
@Singleton
public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
private AuthenticationViewModel authenticationViewModel;
@Inject
public LiveDataCallAdapterFactory(AuthenticationViewModel authenticationViewModel) {
this.authenticationViewModel = authenticationViewModel;
}
@Nullable
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
......@@ -28,6 +41,6 @@ public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resource must be parameterized");
}
return new LiveDataCallAdapter<>(observableType);
return new LiveDataCallAdapter<>(observableType, authenticationViewModel);
}
}
......@@ -11,4 +11,8 @@ public interface IPostRepository {
LiveData<Result<Page<Post>>> getLatestPostList(Integer type, Integer page, int pageSize);
LiveData<Result<Page<Post>>> getRecommendPostList(Integer page, int pageSize);
LiveData<Result<Page<Post>>> getMyPostList(Integer page, int pageSize);
LiveData<Result<Page<Post>>> getFollowedPostList(Integer page, int pageSize);
}
......@@ -30,4 +30,14 @@ public class PostRepositoryImpl implements IPostRepository {
public LiveData<Result<Page<Post>>> getRecommendPostList(Integer page, int pageSize) {
return postApiStore.getRecommendBlogList(page, pageSize);
}
@Override
public LiveData<Result<Page<Post>>> getMyPostList(Integer page, int pageSize) {
return postApiStore.getMyPostList(page, pageSize);
}
@Override
public LiveData<Result<Page<Post>>> getFollowedPostList(Integer page, int pageSize) {
return postApiStore.getFollowedPostList(page, pageSize);
}
}
......@@ -29,4 +29,24 @@ public interface PostApiStore {
@GET("posts")
LiveData<Result<Page<Post>>> getLatestPostList(@Query("type") Integer type, @Query("page") Integer page,
@Query("size") int pageSize);
/**
* 我的动态
* @param page
* @param pageSize
* @return
*/
@GET("my/posts")
LiveData<Result<Page<Post>>> getMyPostList(@Query("page") Integer page,
@Query("size") int pageSize);
/**
* 我关注的人的的动态
* @param page
* @param pageSize
* @return
*/
@GET("posts/followed")
LiveData<Result<Page<Post>>> getFollowedPostList(@Query("page") Integer page,
@Query("size") int pageSize);
}
......@@ -109,7 +109,7 @@ public class AppModule {
@Singleton
@Provides
public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
public Retrofit provideRetrofit(OkHttpClient okHttpClient, LiveDataCallAdapterFactory liveDataCallAdapterFactory) {
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String dateStr = json.getAsJsonPrimitive().getAsString();
......@@ -125,7 +125,7 @@ public class AppModule {
return new Retrofit.Builder()
.baseUrl("https://api.yunliyunwai.cn/api/")
.client(okHttpClient)
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.addCallAdapterFactory(liveDataCallAdapterFactory)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
......
......@@ -47,6 +47,11 @@ public class AuthenticationViewModel extends ViewModel {
AUTHENTICATE_FAILURE,
/**
* 认证过期
*/
AUTHENTICATE_EXPIRED,
/**
* 已认证
*/
AUTHENTICATED
......@@ -163,6 +168,10 @@ public class AuthenticationViewModel extends ViewModel {
return mToken;
}
public String getRefreshToken() {
return mRefreshToken;
}
public String getAuthErrorMsg() {
return mAuthErrorMsg;
}
......@@ -258,6 +267,17 @@ public class AuthenticationViewModel extends ViewModel {
}
/**
* 将当前认证状态置为认证已过期
*/
public void makeAuthenticationExpire() {
mToken = null;
mRefreshToken = null;
mUserInfo = null;
authenticationState.postValue(AuthenticationState.AUTHENTICATE_EXPIRED);
removeUserInfoAndTokenToLocal();
}
/**
* 将用户信息和token保存到本地
*/
private void saveUserInfoAndTokenToLocal() {
......@@ -270,6 +290,18 @@ public class AuthenticationViewModel extends ViewModel {
}
/**
* 将用户信息和token从本地移除
*/
private void removeUserInfoAndTokenToLocal() {
SharedPreferences sharedPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME_AUTHENTICATION, Context.MODE_PRIVATE);
sharedPreferences.edit()
.remove(SHARED_PREFERENCES_AUTHENTICATION_KEY_TOKEN)
.remove(SHARED_PREFERENCES_AUTHENTICATION_KEY_REFRESH_TOKEN)
.remove(SHARED_PREFERENCES_AUTHENTICATION_KEY_USER_INFO)
.commit();
}
/**
* 从本地加载token和用户信息
*/
private void loadTokenAndUserInfoFromLocal() {
......@@ -286,4 +318,19 @@ public class AuthenticationViewModel extends ViewModel {
this.authenticationState.setValue(AuthenticationState.UN_AUTHENTICATE);
}
}
/**
* 刷新token
* @param authenticationResult
*/
public void refreshToken(AuthenticationResult authenticationResult) {
mToken = authenticationResult.getAccessToken();
mRefreshToken = authenticationResult.getRefreshToken();
SharedPreferences sharedPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME_AUTHENTICATION, Context.MODE_PRIVATE);
sharedPreferences.edit()
.putString(SHARED_PREFERENCES_AUTHENTICATION_KEY_TOKEN, mToken)
.putString(SHARED_PREFERENCES_AUTHENTICATION_KEY_REFRESH_TOKEN, mRefreshToken)
.commit();
}
}
......@@ -27,9 +27,13 @@ public class DynamicListFragmentViewModel extends PageableViewModel<Post> {
postRepository.getRecommendPostList(page, defaultPageSize).observeForever(observer);
break;
case LATEST:
postRepository.getLatestPostList(null, page, defaultPageSize).observeForever(observer);
break;
case FOLLOW:
postRepository.getFollowedPostList(page, defaultPageSize).observeForever(observer);
break;
case MY:
postRepository.getLatestPostList(null, page, defaultPageSize).observeForever(observer);
postRepository.getMyPostList(page, defaultPageSize).observeForever(observer);
break;
case WORDS:
postRepository.getLatestPostList(0, page, defaultPageSize).observeForever(observer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment