web-dev-qa-db-fra.com

Retrofit 2 - URL dynamique

Avec Retrofit 2, vous pouvez définir une URL complète dans l'annotation d'une méthode de service, telle que:

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

Cependant, dans mon application, les URL de mes services Web ne sont pas connues au moment de la compilation. L'application les récupère dans un fichier téléchargé. Je me demande donc comment utiliser Retrofit 2 avec une URL dynamique complète.

J'ai essayé de définir un chemin complet comme:

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

Mais ici, Retrofit ne voit pas que le chemin est en fait une URL complète et tente de télécharger http://api.mysite.com/http%3A%2F%2Fapi.mysite.com%2Fuser%2Flist

Avez-vous une idée de la façon dont je pourrais utiliser Retrofit avec une URL aussi dynamique?

Je vous remercie

140
pdegand59

Je pense que vous l'utilisez mal. Voici un extrait du changelog :

Nouveau: L'annotation de paramètre @Url permet de transmettre une URL complète pour un noeud final.

Donc, votre interface devrait être comme ça:

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

Je voulais remplacer seulement une partie de l'URL, et avec cette solution, je n'ai pas à passer l'URL complète, mais seulement la partie dynamique:

public interface APIService {

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

Vous pouvez utiliser le drapeau codé sur l'annotation @Path:

public interface APIService {
  @GET("{fullUrl}")
  Call<Users> getUsers(@Path(value = "fullUrl", encoded = true) String fullUrl);
}
  • Cela empêchera le remplacement de / par %2F.
  • Cela ne vous épargnera pas le remplacement de ? par %3F, de sorte que vous ne pourrez toujours pas transmettre de chaînes de requête dynamiques.
26
fgysin

A compter de Retrofit 2.0.0-beta2, si vous disposez d'un service répondant JSON à partir de cette URL: http: // myhost/mypath

Ce qui suit ne fonctionne pas:

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

Mais c'est ok:

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();
16
yann-h

Vous pouvez utiliser ceci:

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

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

Pour plus d'informations, voir la documentation https://square.github.io/retrofit/

3
Dev_Abraham

Étape 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 Pour une meilleure pratique, définissez une classe pour une instance de modification: -

  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- définissez dans votre activité: -

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

Si vous avez déjà configuré votre code et que vous ne souhaitez pas modifier les différentes interfaces, utilisez la solution décrite dans ce lien . Le point principal est la méthode changeApiBaseUrl qui met à jour l'URL et recrée le générateur 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
// ...
}

Vous pouvez l'utiliser comme suit:

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
Abdelalim Hassouna
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
Nis