【问题标题】:Set SharedPreference in Authenticator?在 Authenticator 中设置 SharedPreference?
【发布时间】:2017-10-03 08:21:17
【问题描述】:

我使用的是安卓系统。我使用SharedPreferences 存储我的身份验证令牌。

为了刷新身份验证令牌,我使用了Authenticator 类。

现在,我需要能够在 SharedPreferences 中设置新的身份验证令牌,但是,为了做到这一点,SharedPreferences 需要一个上下文。

当我没有上下文时,如何从 Authenticator 类设置新的(刷新的)身份验证令牌?

这是我的 Authenticator 类:

public class TokenAuthenticator implements Authenticator {
    private String authToken;

    public TokenAuthenticator(String authToken) {
        this.authToken = authToken;
    }

    @Override
    public Request authenticate(Route route, Response response) throws IOException {
        if (responseCount(response) >= 3) {
            return null;
        }

        ApiInterface apiService = ApiClient.createService(ApiInterface.class, authToken);
        Call<BasicResponse> call = apiService.refreshAuthToken();
        BasicResponse apiResponse = call.execute().body();

        String newToken = apiResponse.getData().getToken();

        // Set the new token in shared preferences (how to get context?)
        SharedPreferences sp = getSharedPreferences(context);
        sp.edit().putString("AUTH_TOKEN", token).apply();

        return response.request().newBuilder()
                .header("Authorization", "Bearer " + newToken)
                .build();
    }

    private int responseCount(Response response) {
        int result = 1;
        while ((response = response.priorResponse()) != null) {
            result++;
        }
        return result;
    }

}

这里是 Authenticator 类被调用的地方:

public class ApiClient {

    public static final String API_URL = "http://www.user324211.com/";

    private static OkHttpClient.Builder httpClient =
            new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    public static Retrofit getRetrofit() {
        return retrofit;
    }

    public static <S> S createService(Class<S> serviceClass) {
        return createService(serviceClass, null);
    }

    public static <S> S createService(Class<S> serviceClass, final String authToken) {
        if (authToken != null) {
            TokenAuthenticator tokenAuthenticator = new TokenAuthenticator(authToken);
            httpClient.authenticator(tokenAuthenticator);
        }

        builder.client(httpClient.build());
        retrofit = builder.build();

        return retrofit.create(serviceClass);
    }

}

【问题讨论】:

  • 你在哪里创建TokenAuthenticator的实例?
  • @Code-Apprentice 添加了代码。
  • 你在哪里调用 createService()?
  • @Code-Apprentice 每当我需要从我的服务器获取数据时,我的应用程序中都会出现。在我上面的代码中,它用于TokenAuthenticator 类。
  • "在我上面的代码中,它用于TokenAuthenticator 类。"我很迷惑。 TokenAuthenticator 在哪里使用 ApiClient.createService()?我在您发布的代码中看不到这一点。从我看到的依赖关系是相反的。现在我们需要上一层楼。谁打电话给getService()

标签: android retrofit retrofit2 okhttp okhttp3


【解决方案1】:

只需再添加 1 个参数

public TokenAuthenticator(Context context,String authToken) {
        this.authToken = authToken;
        this.mContext = context;
}

用法

TokenAuthenticator tA = new TokenAuthenticator(this,YOUR_AUTH_TOKEN);

编辑

如果没有上下文调用,只需传递 SharedPreferences 代替

public TokenAuthenticator(SharedPreferences shared,String authToken) {
       this.authToken = authToken;
       this.mShared = shared;
}

【讨论】:

  • 您可以通过提供如何使用此构造函数的示例来改进您的答案。
  • 好一点。您应该显示包含最后一行代码的类和方法,以便清楚 this 是什么。
  • @ZeroOne 不幸的是,身份验证器类是从一个没有给出上下文的类中调用的。
  • 也许你可以将 SharedPReferences 作为参数传递
  • “也许你可以将 SharedPReferences 作为参数传递”这可能是一个很好的解决方案。 OP 仍然需要弄清楚如何获取 SharedPreferences 引用以传递给构造函数。
【解决方案2】:

有几种方法可以做到这一点

我建议你创建一个应用程序类并在应用程序中创建一个方法 称它为 getContext() 然后该方法可以从任何地方访问

你可以像 App.getContext()

这样获得上下文

例子

package YOUR_PACKAGE_NAME;

import android.app.Application;
import android.content.Context;

public class App extends Application
{
    private static Context context;

    @Override
    public void onCreate()
    {
        super.onCreate();

        context = getApplicationContext();
    }

    public static Context GetContext()
    {
        return context;
    }
}

你可以像这样创建一个单独的共享首选项

https://github.com/BioGram/Android/blob/master/app/src/main/java/co/biogram/main/handler/SharedHandler.java

【讨论】:

  • static 变量很少是正确的解决方案。
  • @Code-Apprentice 是的,你是对的,但这是应用程序类,所以静态变量不能泄露
  • 泄漏是最不重要的问题。我更关心教授正确的编码实践。
  • 这是一个全局解决方案,在大型应用程序中可能需要 xD
  • 静态永远不是“必需的”。您始终可以传递参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多