Upgrade 2 - Dynamic URL

With Retrofit 2, you can set the full URL in the service method annotation, for example:

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

However, in my application, the URL of my web services is unknown at compile time, the application retrieves them in the downloaded file, so I am wondering how I can use Retrofit 2 with a full dynamic URL.

I tried to set the full path, for example:

 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(); 

But here Retrofit does not see that the path is actually the full URL and is trying to download http://api.mysite.com/http%3A%2F%2Fapi.mysite.com%2Fuser%2Flist

Any hint on how I could use Retrofit with such a dynamic URL?

thank

+148
android retrofit
Sep 14 '15 at 7:29
source share
8 answers

I think you are using it incorrectly. Here is an excerpt from changelog :

New: @ Url parameter annotation lets you pass the full URL for the endpoint.

So your interface should be like this:

 public interface APIService { @GET Call<Users> getUsers(@Url String url); } 
+320
Sep 14 '15 at 7:44
source share

I wanted to replace only part of the url, and with this solution I do not need to pass the whole url, just the dynamic part:

 public interface APIService { @GET("users/{user_id}/playlists") Call<List<Playlist> getUserPlaylists(@Path(value = "user_id", encoded = true) String userId); } 
+97
Mar 22 '17 at 23:26
source share

You can use the encoded flag in the @Path annotation:

 public interface APIService { @GET("{fullUrl}") Call<Users> getUsers(@Path(value = "fullUrl", encoded = true) String fullUrl); } 
  • This will prevent replacing / with %2F .
  • It will not save you from ? replaced by %3F , however you still cannot pass dynamic query strings.
+29
Sep 08 '16 at 7:38
source share

With Retrofit 2.0.0-beta2, if you have a service that responds with JSON from this URL: http: // myhost / mypath

The following does not work:

 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(); 

But it normal:

 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(); 
+17
Dec 03 '15 at 15:29
source share

You can use this:

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

Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

For more information see the documentation https://square.imtqy.com/retrofit/

+3
Apr 26 '19 at 2:26
source share

Step 1

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

Step 2 For best practice, define a class for the modified instance:

  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; } 

} Step-3, determine in your activity: -

  final APIService request =ApiRequest.getClient().create(APIService.class); Call<RootLoginModel> call = request.getForgotPassword("dynamic api name",strEmailid); 
+2
Nov 28 '18 at 8:47
source share
 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; } } 
0
Mar 30 '19 at 4:57
source share

If you have already set up your code and do not want to make changes to the various interfaces that you can, use the solution described in this link . The highlight is the changeApiBaseUrl method changeApiBaseUrl which updates the URL and recreates the Retrofit constructor.

 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 // ... } 

You can use it as follows:

 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); } } 
0
Jun 28 '19 at 6:54
source share



All Articles