【问题标题】:Retrofit 2 - Dynamic URL改造 2 - 动态 URL
【发布时间】:2015-12-10 03:10:06
【问题描述】:

使用 Retrofit 2,您可以在服务方法的注释中设置完整的 URL,例如:

public interface APIService {
  @GET("http://api.mysite.com/user/list")
  Call<Users> getUsers();
}

但是,在我的应用程序中,我的 web 服务的 URL 在编译时是未知的,应用程序在下载的文件中检索它们,所以我想知道如何使用带有完整动态 URL 的 Retrofit 2。

我尝试设置完整路径,例如:

public interface APIService {
  @GET("{fullUrl}")
  Call<Users> getUsers(@Path("fullUrl") fullUrl);
}

new Retrofit.Builder()
  .baseUrl("http://api.mysite.com/")
  .build()
  .create(APIService.class)
  .getUsers("http://api.mysite.com/user/list"); // this url should be dynamic
  .execute();

但是在这里,Retrofit 并没有看到路径实际上是一个完整的 URL,并且正在尝试下载 http://api.mysite.com/http%3A%2F%2Fapi.mysite.com%2Fuser%2Flist

任何关于我如何使用 Retrofit 和这样的动态 url 的提示?

谢谢

【问题讨论】:

标签: android retrofit


【解决方案1】:

我认为您以错误的方式使用它。这是changelog的摘录:

新增:@Url 参数注释允许为端点传递完整的 URL。

所以你的界面应该是这样的:

public interface APIService {
    @GET
    Call<Users> getUsers(@Url String url);
}

【讨论】:

  • @pdegand59 这是全新的 :) 见 changelog
  • 虽然端点的 url 是 fullurl,但为什么需要 baseurl?
  • 如果我使用这个@Url 注释。那我们应该在 .baseUrl() 中写什么呢??
  • 你应该写下你的主网址。 @Url 参数无论如何都会覆盖它。
  • 我尝试像上面那样添加 URL,但是我通常为改造构建器设置的 baseUrl 覆盖了我在参数中指定的完整 url,因此它不是 dynamic.com,而是被转换为 @ 987654324@
【解决方案2】:

我只想替换部分 url,通过这个解决方案,我不必传递整个 url,只需传递动态部分:

public interface APIService {

  @GET("users/{user_id}/playlists")
  Call<List<Playlist> getUserPlaylists(@Path(value = "user_id", encoded = true) String userId);
}

【讨论】:

  • 帮了我很多...谢谢
  • 投了赞成票。使用 retrofit2 suspend fun getUserPlaylists(@Path("id") id: String): YourOwnResponse 对我有很大帮助。谢谢
【解决方案3】:

您可以在 @Path 注释上使用 encoded 标志:

public interface APIService {
  @GET("{fullUrl}")
  Call<Users> getUsers(@Path(value = "fullUrl", encoded = true) String fullUrl);
}
  • 这将防止将/ 替换为%2F
  • 但是,它不会让您免于将 ? 替换为 %3F,因此您仍然无法传递动态查询字符串。

【讨论】:

  • 这不是错字。
  • 以及如何将 %3F 替换为 ?
  • 对于?,您无法手动处理。您应该像 @Query("page") number: Int 一样使用 @Query 来传递查询参数。您也可以添加多个参数
  • 这拯救了我的一天!
  • 此外,您可以使用更多字段:@GET("{fullUrl}/{id}") fun getData(@Path(value = "fullUrl", encoded = true) fullUrl: String, @Path(value = "id", encoded = true) id: String): Call?
【解决方案4】:

从 Retrofit 2.0.0-beta2 开始,如果您有服务从该 URL 响应 JSON: http://myhost/mypath

以下操作无效:

public interface ClientService {
    @GET("")
    Call<List<Client>> getClientList();
}

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://myhost/mypath")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

ClientService service = retrofit.create(ClientService.class);

Response<List<Client>> response = service.getClientList().execute();

但这没关系:

public interface ClientService {
    @GET
    Call<List<Client>> getClientList(@Url String anEmptyString);
}

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://myhost/mypath")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

ClientService service = retrofit.create(ClientService.class);

Response<List<Client>> response = service.getClientList("").execute();

【讨论】:

    【解决方案5】:

    你可以用这个:

    @GET("group/{id}/users")

    Call&lt;List&lt;User&gt;&gt; groupList(@Path("id") int groupId, @Query("sort") String sort);

    有关更多信息,请参阅文档https://square.github.io/retrofit/

    【讨论】:

      【解决方案6】:

      Retrofit (MVVM) 中带有 Get 和 Post 方法的动态 URL

      改造服务界面:

      public interface NetworkAPIServices {
      
      @POST()
      Observable<JsonElement> executXYZServiceAPI(@Url String url,@Body AuthTokenRequestModel param);
      
      
      @GET
      Observable<JsonElement> executeInserInfo(@Url String url);
      

      MVVM 服务类:

         public Observable<JsonElement> executXYZServiceAPI(ModelObject object) {
          return networkAPIServices.authenticateAPI("url",
                  object);
      }
      
       public Observable<JsonElement> executeInserInfo(String ID) {
          return networkAPIServices.getBank(DynamicAPIPath.mergeUrlPath("url"+ID)));
      }
      

      和改造客户端类

       @Provides
      @Singleton
      @Inject
      @Named("provideRetrofit2")
      Retrofit provideRetrofit(@Named("provideRetrofit2") Gson gson, @Named("provideRetrofit2") OkHttpClient okHttpClient) {
      
      
         builder = new Retrofit.Builder();
          if (BaseApplication.getInstance().getApplicationMode() == ApplicationMode.DEVELOPMENT) {
              builder.baseUrl(NetworkURLs.BASE_URL_UAT);
          } else {
              builder.baseUrl(NetworkURLs.BASE_URL_PRODUCTION);
          }
      
      
          builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
          builder.client(okHttpClient);
          builder.addConverterFactory(GsonConverterFactory.create(gson));
      
      
          return builder.build();
      }
      

      例如 这是网址:https://gethelp.wildapricot.com/en/articles/549-changing-your

      基本网址:https://gethelp.wildapricot.com

      剩余的@Url:/en/articles/549-changeing-your(这是你在复古服务类中传递的)

      【讨论】:

        【解决方案7】:

        第一步

          Please define a method in Api interface like:-
         @FormUrlEncoded
         @POST()
         Call<RootLoginModel> getForgotPassword(
                @Url String apiname,
                @Field(ParameterConstants.email_id) String username
         );
        

        第二步 要获得最佳实践,请为改造实例定义一个类:-

          public class ApiRequest {
               static Retrofit retrofit = null;
        
        
        
        public static Retrofit getClient() {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        
            OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
                    .addInterceptor(logging)
                    .connectTimeout(60, TimeUnit.SECONDS)
                    .readTimeout(60, TimeUnit.SECONDS)
                    .writeTimeout(60, TimeUnit.SECONDS)
                    .build();
        
            if (retrofit==null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(URLConstants.base_url)
                        .client(okHttpClient)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
            }
            return retrofit;
        }
        

        } 第三步 在您的活动中定义:-

          final APIService request =ApiRequest.getClient().create(APIService.class);
          Call<RootLoginModel> call = request.getForgotPassword("dynamic api 
          name",strEmailid);
        

        【讨论】:

          【解决方案8】:

          RetrofitHelper 用 kotlin 编写的库,可以让您使用几行代码进行 API 调用,并且您可以在每次调用中使用不同的 URL、标头和参数

          在您的应用程序类中添加多个 URL,如下所示:

          class Application : Application() {
          
              override fun onCreate() {
              super.onCreate()
          
                  retrofitClient = RetrofitClient.instance
                              //api url
                          .setBaseUrl("https://reqres.in/")
                              //you can set multiple urls
                  //                .setUrl("example","http://ngrok.io/api/")
                              //set timeouts
                          .setConnectionTimeout(4)
                          .setReadingTimeout(15)
                              //enable cache
                          .enableCaching(this)
                              //add Headers
                          .addHeader("Content-Type", "application/json")
                          .addHeader("client", "android")
                          .addHeader("language", Locale.getDefault().language)
                          .addHeader("os", android.os.Build.VERSION.RELEASE)
                      }
          
                  companion object {
                  lateinit var retrofitClient: RetrofitClient
          
                  }
              }  
          

          然后在通话中使用您需要的 URL:

          retrofitClient.Get<GetResponseModel>()
                      //set base url
                      .setBaseUrlKey("example")
                      //set path
                      .setPath("api/users/2")
                      //set url params Key-Value or HashMap
                      .setUrlParams("KEY","Value")
                      .setResponseHandler(GetResponseModel::class.java,
                          object : ResponseHandler<GetResponseModel>() {
                              override fun onSuccess(response: Response<GetResponseModel>) {
                                  super.onSuccess(response)
                                  //handle response
                              }
                          }).run(this)
          

          欲了解更多信息,请参阅documentation

          【讨论】:

            【解决方案9】:

            如果您已经设置了代码,并且不想对不同的接口进行更改,请使用link 中描述的解决方案。 重点是 changeApiBaseUrl 方法更新 URL 并重新创建 Retrofit 构建器。

            public class ServiceGenerator {  
            public static String apiBaseUrl = "http://futurestud.io/api";
            private static Retrofit retrofit;
            
            private static Retrofit.Builder builder =
                    new Retrofit.Builder()
                            .addConverterFactory(GsonConverterFactory.create())
                            .baseUrl(apiBaseUrl);
            
            private static OkHttpClient.Builder httpClient =
                    new OkHttpClient.Builder();
            
            // No need to instantiate this class.
            private ServiceGenerator() {
            }
            
            public static void changeApiBaseUrl(String newApiBaseUrl) {
                apiBaseUrl = newApiBaseUrl;
            
                builder = new Retrofit.Builder()
                                .addConverterFactory(GsonConverterFactory.create())
                                .baseUrl(apiBaseUrl);
            }
            
            public static <S> S createService(Class<S> serviceClass, AccessToken token) {
                String authToken = token.getTokenType().concat(token.getAccessToken());
                return createService(serviceClass, authToken);
            }
            
            // more methods
            // ...
            }
            

            您可以按如下方式使用它:

            public class DynamicBaseUrlActivity extends AppCompatActivity {
            
            public static final String TAG = "CallInstances";
            private Callback<ResponseBody> downloadCallback;
            
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_file_upload);
            
                downloadCallback = new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        Log.d(TAG, "server contacted at: " + call.request().url());
                    }
            
                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.d(TAG, "call failed against the url: " + call.request().url());
                    }
                };
            
                // first request
                FileDownloadService downloadService = ServiceGenerator.create(FileDownloadService.class);
                Call<ResponseBody> originalCall = downloadService.downloadFileWithFixedUrl();
                originalCall.enqueue(downloadCallback);
            
                // change base url
                ServiceGenerator.changeApiBaseUrl("http://development.futurestud.io/api");
            
                // new request against new base url
                FileDownloadService newDownloadService = ServiceGenerator.create(FileDownloadService.class);
                Call<ResponseBody> newCall = newDownloadService.downloadFileWithFixedUrl();
                newCall.enqueue(downloadCallback);
                }
            }
            

            【讨论】:

              【解决方案10】:
              step -*1 
              
              movie_list_row.xml
              <?xml version="1.0" encoding="utf-8"?>
              <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:background="?android:attr/selectableItemBackground"
                  android:clickable="true"
                  android:focusable="true"
              
                  android:orientation="horizontal"
                  android:paddingLeft="@dimen/activity_horizontal_margin"
                  android:paddingTop="@dimen/row_padding_vertical"
                  android:paddingRight="@dimen/activity_horizontal_margin"
                  android:paddingBottom="@dimen/row_padding_vertical">
              
                  <ImageView
                      android:id="@+id/ivImage"
                      android:layout_width="60dp"
                      android:layout_height="60dp"
                      android:layout_marginRight="10dp"
                      android:src="@mipmap/ic_launcher" />
              
                  <LinearLayout
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:layout_weight="1"
                      android:orientation="vertical">
              
                      <TextView
                          android:id="@+id/title"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:layout_alignParentTop="true"
                          android:text="Hello"
                          android:textColor="@color/title"
                          android:textSize="16dp"
                          android:textStyle="bold" />
              
                      <TextView
                          android:id="@+id/genre"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:layout_below="@id/title"
                          android:text="realName" />
                  </LinearLayout>
              
                  <TextView
                      android:id="@+id/year"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:layout_alignParentRight="true"
                      android:text="Team"
                      android:textColor="@color/year" />
              
              </LinearLayout>                                                                                                            
              
              Api.java                                                                                  
              import org.json.JSONObject;
              
              import java.util.List;
              
              import retrofit2.Call;
              import retrofit2.Callback;
              import retrofit2.http.Field;
              import retrofit2.http.FormUrlEncoded;
              import retrofit2.http.GET;
              import retrofit2.http.POST;
              
              public interface  Api {
              
                  String BASE_URL = "https://simplifiedcoding.net/demos/";
              
                  @GET("marvel")
                  Call<List<Hero>> getHeroes();
              
                  @FormUrlEncoded
                  @POST("/login")
                  public void login(@Field("username") String username, @Field("password") String password, Callback<List<Hero>> callback);
              
              }
              
              
              MoviesAdapter.java                                                                                       import android.content.Context;
              import android.support.v7.widget.RecyclerView;
              import android.view.LayoutInflater;
              import android.view.View;
              import android.view.ViewGroup;
              import android.widget.ImageView;
              import android.widget.TextView;
              import android.widget.Toast;
              
              import com.squareup.picasso.Picasso;
              
              import java.util.List;
              
              public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MyViewHolder> {
              
                  private List<Hero> moviesList;
              
                  Context context;
              
              
                  public class MyViewHolder extends RecyclerView.ViewHolder {
                      public TextView title, year, genre;
                      public ImageView ivImage;
              
                      public MyViewHolder(View view) {
                          super(view);
                          title = (TextView) view.findViewById(R.id.title);
                          genre = (TextView) view.findViewById(R.id.genre);
                          year = (TextView) view.findViewById(R.id.year);
                          ivImage =  view.findViewById(R.id.ivImage);
                          ivImage.setOnClickListener(new View.OnClickListener() {
                              @Override
                              public void onClick(View v) {
              
                                  Toast.makeText(context, "-" + moviesList.get(getAdapterPosition()).getName(), Toast.LENGTH_SHORT).show();
                              }
                          });
                      }
                  }
              
              
                  public MoviesAdapter(List<Hero> moviesList,Context context) {
                      this.moviesList = moviesList;
                      this.context = context;
                  }
              
                  @Override
                  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                      View itemView = LayoutInflater.from(parent.getContext())
                              .inflate(R.layout.movie_list_row, parent, false);
              
                      return new MyViewHolder(itemView);
                  }
              
                  @Override
                  public void onBindViewHolder(MyViewHolder holder, int position) {
                      Hero movie = moviesList.get(position);
                      holder.title.setText(movie.getName());
                      holder.genre.setText(movie.getRealname());
                      holder.year.setText(movie.getTeam());
              
                      Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(holder.ivImage);
                  }
              
                  @Override
                  public int getItemCount() {
                      return moviesList.size();
                  }
              }                                                                                                                                                        main activity                                                                                                               import android.support.v7.app.AppCompatActivity;
              import android.os.Bundle;
              import android.support.v7.widget.DefaultItemAnimator;
              import android.support.v7.widget.LinearLayoutManager;
              import android.support.v7.widget.RecyclerView;
              import android.widget.ArrayAdapter;
              import android.widget.ListView;
              import android.widget.Toast;
              
              import java.util.ArrayList;
              import java.util.List;
              
              import retrofit2.Call;
              import retrofit2.Callback;
              import retrofit2.Response;
              import retrofit2.Retrofit;
              import retrofit2.converter.gson.GsonConverterFactory;
              
              public class MainActivity extends AppCompatActivity {
              
                  private List<Hero> movieList = new ArrayList<>();
                  private RecyclerView recyclerView;
                  private MoviesAdapter mAdapter;
              
                  @Override
                  protected void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
                      setContentView(R.layout.activity_main);
              
                      recyclerView=findViewById(R.id.recycler_view);
                      mAdapter = new MoviesAdapter(movieList,MainActivity.this);
                      RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
                      recyclerView.setLayoutManager(mLayoutManager);
                      recyclerView.setItemAnimator(new DefaultItemAnimator());
                      recyclerView.setAdapter(mAdapter);
                      //calling the method to display the heroes
                      getHeroes();
              
                  }
              
              
                  private void getHeroes() {
                      Retrofit retrofit = new Retrofit.Builder()
                              .baseUrl(ApiInterface.BASE_URL)
                              .addConverterFactory(GsonConverterFactory.create()) //Here we are using the GsonConverterFactory to directly convert json data to object
                              .build();
              
                      ApiInterface api = retrofit.create(ApiInterface.class);
              
                      Call<List<Hero>> call = api.getHeroes();
              
                      call.enqueue(new Callback<List<Hero>>() {
                          @Override
                          public void onResponse(Call<List<Hero>> call, Response<List<Hero>> response) {
                              List<Hero> heroList = response.body();
              
                              //Creating an String array for the ListView
                              String[] heroes = new String[heroList.size()];
              
                              //looping through all the heroes and inserting the names inside the string array
                              for (int i = 0; i < heroList.size(); i++) {
                                  //heroes[i] = heroList.get(i).getName();
                                  movieList.add(new Hero( heroList.get(i).getName(), heroList.get(i).getRealname(), heroList.get(i).getTeam()));
                              }
                              mAdapter.notifyDataSetChanged();
              
                          }
              
                          @Override
                          public void onFailure(Call<List<Hero>> call, Throwable t) {
                              Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
                          }
                      });
                  }
              
              }
              Hero.java
              package com.example.owner.apipractice;
              public class Hero {
              
                  private String name;
                  private String realname;
                  private String team;
              
                  public Hero(String name, String realname, String team) {
                      this.name = name;
                      this.realname = realname;
                      this.team = team;
                  }
              
                  private String firstappearance;
                  private String createdby;
                  private String publisher;
                  private String imageurl;
                  private String bio;
              
              
                  public Hero(String name, String realname, String team, String firstappearance, String createdby, String publisher, String imageurl, String bio) {
                      this.name = name;
                      this.realname = realname;
                      this.team = team;
                      this.firstappearance = firstappearance;
                      this.createdby = createdby;
                      this.publisher = publisher;
                      this.imageurl = imageurl;
                      this.bio = bio;
                  }
              
                  public String getName() {
                      return name;
                  }
              
                  public String getRealname() {
                      return realname;
                  }
              
                  public String getTeam() {
                      return team;
                  }
              
                  public String getFirstappearance() {
                      return firstappearance;
                  }
              
                  public String getCreatedby() {
                      return createdby;
                  }
              
                  public String getPublisher() {
                      return publisher;
                  }
              
                  public String getImageurl() {
                      return imageurl;
                  }
              
                  public String getBio() {
                      return bio;
                  }
              }
              

              【讨论】:

              • 请解释一下你的答案
              猜你喜欢
              • 1970-01-01
              • 2023-03-16
              • 2014-11-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多