我正在尝试使用Dagger 2
使用Retrofit 2.0执行登录操作以下是我如何设置Retrofit依赖
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient client) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson)
.client(client)
.baseUrl(application.getUrl())
.build();
return retrofit;
}
这是API接口。
interface LoginAPI {
@GET(relative_path)
Call<Boolean> logMe();
}
我有三个不同的基本网址,用户可以登录。因此,在设置Retrofit依赖项时,我无法设置静态URL。我在Application类上创建了一个setUrl()和getUrl()方法。用户登录后,我在调用API调用之前将url设置为Application。
我使用懒惰注射来改造这样的
Lazy<Retrofit> retrofit
这样,Dagger只有在我可以调用
时才会注入依赖关系retrofit.get()
这部分效果很好。我把url设置为改进依赖。但是,当用户键入错误的基本URL(例如,mywifi.domain.com)时,会出现问题,理解它是错误的并更改它(比如mydata.domain.com)。由于Dagger已经为改造创建了依赖关系,因此它不会再做了。 所以我必须重新打开应用程序并输入正确的URL。
我阅读了不同帖子,使用Dagger在Retrofit上设置动态网址。在我的情况下,没有什么比这更好的了。我想念什么吗?
答案 0 :(得分:41)
HostSelectionInterceptor
made by swankjesse
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/** An interceptor that allows runtime changes to the URL hostname. */
public final class HostSelectionInterceptor implements Interceptor {
private volatile String host;
public void setHost(String host) {
this.host = host;
}
@Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
//HttpUrl newUrl = request.url().newBuilder()
// .host(host)
// .build();
HttpUrl newUrl = HttpUrl.parse(host);
request = request.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(request);
}
public static void main(String[] args) throws Exception {
HostSelectionInterceptor interceptor = new HostSelectionInterceptor();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
Request request = new Request.Builder()
.url("http://www.coca-cola.com/robots.txt")
.build();
okhttp3.Call call1 = okHttpClient.newCall(request);
okhttp3.Response response1 = call1.execute();
System.out.println("RESPONSE FROM: " + response1.request().url());
System.out.println(response1.body().string());
interceptor.setHost("www.pepsi.com");
okhttp3.Call call2 = okHttpClient.newCall(request);
okhttp3.Response response2 = call2.execute();
System.out.println("RESPONSE FROM: " + response2.request().url());
System.out.println(response2.body().string());
}
}
或者您可以替换您的Retrofit实例(并且可能将实例存储在RetrofitHolder
中,您可以在其中修改实例本身,并通过Dagger提供持有者)...
public class RetrofitHolder {
Retrofit retrofit;
//getter, setter
}
或者重新使用当前的Retrofit实例,并使用反射破解新的URL,因为搞了规则。 Retrofit的baseUrl
参数为private final
,因此您只能使用反射访问它。
Field field = Retrofit.class.getDeclaredField("baseUrl");
field.setAccessible(true);
okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl);
field.set(retrofit, newHttpUrl);
答案 1 :(得分:33)
Retrofit2库附带@Url
注释。您可以像这样覆盖baseUrl
:
API接口:
public interface UserService {
@GET
public Call<ResponseBody> profilePicture(@Url String url);
}
并按照以下方式调用API:
Retrofit retrofit = Retrofit.Builder()
.baseUrl("https://your.api.url/");
.build();
UserService service = retrofit.create(UserService.class);
service.profilePicture("https://s3.amazon.com/profile-picture/path");
有关详细信息,请参阅此链接:https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests
答案 2 :(得分:5)
这在Kotlin对我有用
class HostSelectionInterceptor: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val host: String = SharedPreferencesManager.getServeIpAddress()
val newUrl = request.url().newBuilder()
.host(host)
.build()
request = request.newBuilder()
.url(newUrl)
.build()
return chain.proceed(request)
}
}
将拦截器添加到OkHttpClient构建器中
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(HostSelectionInterceptor())
.cache(null)
.build()
答案 3 :(得分:2)
感谢@EpicPandaForce的帮助。如果有人面临IllegalArgumentException,这是我的工作代码。
# A tibble: 7 x 3
obs grp sub_grp
<dbl> <chr> <chr>
1 1 A A1
2 2 A A1
3 3 A A2
4 4 A A2
5 8 C C1
6 9 C C2
7 10 C C3
答案 4 :(得分:2)
您可以使用无范围的提供方法实例化新对象。
@Provides
LoginAPI provideAPI(Gson gson, OkHttpClient client, BaseUrlHolder baseUrlHolder) {
Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)
.client(client)
.baseUrl(baseUrlHolder.get())
.build();
return retrofit.create(LoginAPI.class);
}
@AppScope
@Provides
BaseUrlHolder provideBaseUrlHolder() {
return new BaseUrlHolder("https://www.default.com")
}
public class BaseUrlHolder {
public String baseUrl;
public BaseUrlHolder(String baseUrl) {
this.baseUrl = baseUrl;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
}
现在您可以通过从组件
获取baseUrlHolder来更改基本URLApp.appComponent.getBaseUrlHolder().set("https://www.changed.com");
this.loginApi = App.appComponent.getLoginApi();
答案 5 :(得分:2)
这可能很晚,但是Retrofit
允许您使用动态URL,同时使用@Url
注释进行网络通话。
我还使用Dagger2
将Retrofit
实例注入我的存储库中,该解决方案对我来说很好用。
由您在创建Retrofit实例时提供。
@GET("/product/123")
fun fetchDataFromNetwork(): Call<Product>
并使用您将在运行时提供此调用的URL。
@GET()
fun fetchDataFromNetwork(@Url url : String): Call<Product> //
答案 6 :(得分:0)
对于最新的Retrofit库,您可以简单地使用单例实例并使用retrofitInstance.newBuilder().baseUrl(newUrl)
对其进行更改。无需创建另一个实例。
答案 7 :(得分:0)
请查看我的Dagger动态URL解决方法。
第一步:创建一个拦截器
import android.util.Patterns;
import com.nfs.ascent.mdaas.repo.network.ApiConfig;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class DomainURLInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
String requestUrl = original.url().toString();
String PROTOCOL = "(?i:http|https|rtsp)://";
String newURL = requestUrl.replaceFirst(PROTOCOL, "")
.replaceFirst(Patterns.DOMAIN_NAME.toString(), "");
newURL = validateBackSlash(newURL) ? ApiConfig.BASE_URL.concat(newURL) : newURL.replaceFirst("/", ApiConfig.BASE_URL);
original = original.newBuilder()
.url(newURL)
.build();
return chain.proceed(original);
}
private boolean validateBackSlash(String str) {
if (!str.substring(str.length() - 1).equals("/")) {
return true;
}
return false;
}
}
第2步:
在模块中添加新创建的拦截器
@Provides
@Singlton
DomainURLInterceptor getChangeURLInterceptor() {
return new DomainURLInterceptor();
}
步骤3: 将拦截器添加到HttpClient拦截器列表中
@Provides
@Singlton
OkHttpClient provideHttpClient() {
return new OkHttpClient.Builder()
.addInterceptor(getChangeURLInterceptor())
.readTimeout(ApiConfig.API_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(ApiConfig.API_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.build();
}
第4步:
@Provides
@Singlton
Retrofit provideRetrofit() {
return new Retrofit.Builder()
.baseUrl(ApiConfig.BASE_URL) // this is default URl,
.addConverterFactory(provideConverterFactory())
.client(provideHttpClient())
.build();
}
注意:如果用户必须从设置中更改基本URL,请记住使用以下方法来验证新创建的URL:
public final static boolean isValidUrl(CharSequence target) {
if (target == null) {
return false;
} else {
return Patterns.WEB_URL.matcher(target).matches();
}
}