在Android中使用Retrofit

45

我有一个包含三个活动的Android应用:

  1. 登录活动
  2. 任务活动,其中显示与用户相关的所有任务(使用数组适配器填充)
  3. 任务详细信息活动,由单击列表中任务结果而生成

我需要使用REST Api。到目前为止,我所做的研究指导我使用Retrofit。我查看了如何使用它并发现:

  1. 在主要活动(我的是登录活动)中设置基本URL。
  2. 我需要创建一个API类并使用注释定义我的函数。
  3. 在活动中使用Rest Adapter类并定义回调。

如果我的应用是单一活动应用程序,我将压缩MainActivity.java中的所有内容,但不知道如何在我的三个活动中放置来自步骤1、2、3的代码以供使用。请告诉我如何在我的应用程序中使用Retrofit。非常感谢。

具体而言,我需要进行以下网络调用: 1. 登录用户 2. 获取用户的所有任务。 对于两者,我都将使用给定的REST api。

*********************************************
          Calling Api USing Retrofit
*********************************************
**Dependancies** :-
      implementation 'com.android.support:recyclerview-v7:27.1.1'
        implementation 'com.squareup.picasso:picasso:2.5.2'
        implementation 'com.android.support:cardview-v7:27.1.1'
    enter code here
**Model**
use the Pozo class

**Api Call**
 -> getLogin()    // use the method



  //API call for Login
    private void getLogin()
    {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
        AsyncHttpClient client = new AsyncHttpClient();
        RequestParams requestParams = new RequestParams();
        requestParams.put("email_id", edit_email.getText().toString());
        requestParams.put("password", edit_password.getText().toString());
        Log.e("", "LOGIN URL==>" + Urls.LOGIN + requestParams);
        Log.d("device_token", "Device_ Token" + FirebaseInstanceId.getInstance().getToken());
        client.post(Urls.LOGIN, requestParams, new JsonHttpResponseHandler() {
            @Override
            public void onStart() {
                super.onStart();
                ShowProgress();
            }

            @Override
            public void onFinish() {
                super.onFinish();
                Hideprogress();

            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                super.onSuccess(statusCode, headers, response);
                Log.e("", "Login RESPONSE-" + response);
                Login login = new Gson().fromJson(String.valueOf(response), Login.class);
                edit_email.setText("");
                edit_password.setText("");
                if (login.getStatus().equals("true")) {
                    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                    MDToast mdToast = MDToast.makeText(SignInActivity.this, String.valueOf("User Login Successfully!"),
                            MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS);
                    mdToast.show();
                    Utils.WriteSharePrefrence(SignInActivity.this, Util_Main.Constant.EMAIL, login.getData().getEmailId());
                    Utils.WriteSharePrefrence(SignInActivity.this, Constant.USERID, login.getData().getId());

                    Utils.WriteSharePrefrence(SignInActivity.this, Constant.USERNAME, login.getData().getFirstName());
                    Utils.WriteSharePrefrence(SignInActivity.this, Constant.PROFILE, login.getData().getProfileImage());
                    hideKeyboard(SignInActivity.this);
                    Intent intent = new Intent(SignInActivity.this, DashboardActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    startActivity(intent);
                    finish();
                } else {
                    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                    MDToast mdToast = MDToast.makeText(SignInActivity.this, String.valueOf("Login Denied"),
                            MDToast.LENGTH_SHORT, MDToast.TYPE_ERROR);
                    mdToast.show();
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                super.onFailure(statusCode, headers, responseString, throwable);
                Log.e("", throwable.getMessage());
                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                MDToast mdToast = MDToast.makeText(SignInActivity.this, "Something went wrong",
                        MDToast.LENGTH_SHORT, MDToast.TYPE_ERROR);
                mdToast.show();
            }
        });
    }

6
我找不到足够的关于如何使用Retrofit的文档/教程。 - Stack Man
1
你解决了吗? - Rafed Nole
1
最好使用Volley进行快速网络通信。 - Pankaj Arora
8
有点晚了,但对于未来的搜索者:你可以在这里找到一个相当详细的改装指南 here - peitek
19个回答

101

使用 Retrofit 非常简单和直接。

首先,你需要将 Retrofit 添加到你的项目中,例如使用 Gradle 构建系统。

compile 'com.squareup.retrofit:retrofit:1.7.1' |

你可以通过另一种方式下载`.jar`文件并将其放置在`libs`文件夹中。

接下来,您需要定义接口,以供Retrofit使用,用于调用REST端点的API。例如,对于用户:

public interface YourUsersApi {

   //You can use rx.java for sophisticated composition of requests 
   @GET("/users/{user}")
   public Observable<SomeUserModel> fetchUser(@Path("user") String user);

   //or you can just get your model if you use json api
   @GET("/users/{user}")
   public SomeUserModel fetchUser(@Path("user") String user);

   //or if there are some special cases you can process your response manually 
   @GET("/users/{user}")
   public Response fetchUser(@Path("user") String user);

}

好的。现在你已经定义了API接口,可以尝试使用它。

首先需要创建一个RestAdapter实例,并设置API后端的基本URL。这也很简单:

RestAdapter restAdapter = new RestAdapter.Builder()
   .setEndpoint("https://yourserveraddress.com")
    .build();

YourUsersApi yourUsersApi = restAdapter.create(YourUsersApi.class);

在这里,Retrofit将从接口中读取您的信息,并在后台创建RestHandler,根据您提供的元信息实际上将执行HTTP请求。

然后,在响应接收到时,在json API的情况下,您的数据将使用Gson库转换为您的模型,因此您应该知道在Gson中存在的限制实际上也存在于Retrofit中。

如果要扩展/覆盖序列化程序/反序列化程序将响应数据转换为您的模型,则可能希望向Retrofit提供自定义序列化程序/反序列化程序。

在这里,您需要实现Converter接口并实现两个方法fromBody()toBody()

以下是示例:

public class SomeCustomRetrofitConverter implements Converter {

    private GsonBuilder gb;

    public SomeCustomRetrofitConverter() {
        gb = new GsonBuilder();

        //register your cursom custom type serialisers/deserialisers if needed
        gb.registerTypeAdapter(SomeCutsomType.class, new SomeCutsomTypeDeserializer());
    }

    public static final String ENCODING = "UTF-8";

    @Override
    public Object fromBody(TypedInput body, Type type) throws ConversionException {
        String charset = "UTF-8";
        if (body.mimeType() != null) {
            charset = MimeUtil.parseCharset(body.mimeType());
        }
        InputStreamReader isr = null;
        try {
           isr = new InputStreamReader(body.in(), charset);
           Gson gson = gb.create();
           return gson.fromJson(isr, type);
        } catch (IOException e) {
            throw new ConversionException(e);
        } catch (JsonParseException e) {
            throw new ConversionException(e);
        } finally {
            if (isr != null) {
                   try {
                      isr.close();
                   } catch (IOException ignored) {
                }
            }
        }
    }

    @Override
    public TypedOutput toBody(Object object) {
        try {
            Gson gson = gb.create();
            return new JsonTypedOutput(gson.toJson(object).getBytes(ENCODING), ENCODING);
        } catch (UnsupportedEncodingException e) {
            throw new AssertionError(e);
        }
     }

    private static class JsonTypedOutput implements TypedOutput {
        private final byte[] jsonBytes;
        private final String mimeType;

        JsonTypedOutput(byte[] jsonBytes, String encode) {
            this.jsonBytes = jsonBytes;
            this.mimeType = "application/json; charset=" + encode;
        }

        @Override
        public String fileName() {
            return null;
        }

       @Override
       public String mimeType() {
           return mimeType;
       }

       @Override
       public long length() {
          return jsonBytes.length;
       }

       @Override
       public void writeTo(OutputStream out) throws IOException {
           out.write(jsonBytes);
       }
    }
 }

现在,如果需要,您需要使用在构建RestAdapter时使用setConverter()来启用自定义适配器。

好的。现在您已经知道如何将数据从服务器获取到Android应用程序中。但是,您需要以某种方式管理数据并在正确的位置调用REST调用。我建议使用android Service或AsyncTask或loader或rx.java,在后台线程中查询您的数据,以便不会阻塞您的UI。

因此,现在您可以找到最合适的位置来调用。

SomeUserModel yourUser = yourUsersApi.fetchUser("someUsers")

获取您的远程数据。


2
未解决的引用: RestAdapter. 在版本2中似乎不再使用RestAdapter. 这个问题有助于解释: https://dev59.com/LlwY5IYBdhLWcg3wnY13 - Rock Lee
这是Retrofit 1。现在人们正在使用Retrofit 2。语法不同。 - Kai Wang
只需一次设置,轻松地通过单击一个按钮在您的项目中添加Retrofit。 https://medium.com/@mestri.vinayak.n/quick-install-retrofit-in-your-android-project-custom-template-a14a6adc77c2 - Vinayak Mestri

25
我刚刚使用了Retrofit几周,一开始在我的应用程序中使用它很难。我想向您分享在应用程序中使用Retrofit的最简单方法。稍后如果您已经熟练掌握了Retrofit,您可以增强您的代码(将UI与API分离并使用回调),或许从上面的文章中获取一些技巧。
在您的应用程序中,您有登录、任务列表活动和查看详细任务的活动。
首先,您需要在您的应用程序中添加Retrofit,并且有两种方法,请参考上面的@artemis文章。
Retrofit使用接口作为您的API。因此,请创建一个接口类。
public interface MyApi{

/*LOGIN*/
@GET("/api_reciever/login") //your login function in your api
public void login(@Query("username") String username,@Query("password") String password,Callback<String> calback); //this is for your login, and you can used String as response or you can use a POJO, retrofit is very rubust to convert JSON to POJO

/*GET LIST*/
@GET("/api_reciever/getlist") //a function in your api to get all the list
public void getTaskList(@Query("user_uuid") String user_uuid,Callback<ArrayList<Task>> callback); //this is an example of response POJO - make sure your variable name is the same with your json tagging

/*GET LIST*/
@GET("/api_reciever/getlistdetails") //a function in your api to get all the list
public void getTaskDetail(@Query("task_uuid") String task_uuid,Callback<Task> callback);   //this is an example of response POJO - make sure your variable name is the same with your json tagging

}

创建另一个接口类来保存您的API基础地址。
public interface Constants{
   public String URL = "www.yoururl.com"
}

在您的登录活动中创建一个方法来处理Retrofit。
private void myLogin(String username,String password){

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(Constants.URL)  //call your base url
    .build();


MyApi mylogin = restAdapter.create(MyApi.class); //this is how retrofit create your api
mylogin.login(username,password,new Callback<String>() {
        @Override
        public void success(String s, Response response) {
            //process your response if login successfull you can call Intent and launch your main activity

        }

        @Override
        public void failure(RetrofitError retrofitError) {
            retrofitError.printStackTrace(); //to see if you have errors
        }
    });
}

在你的MainActivity列表中

private void myList(String user_uuid){

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(Constants.URL)  //call your base url
    .build();


MyApi mytask = restAdapter.create(MyApi.class); //this is how retrofit create your api
mytask.getTaskDetail(user_uuid,new Callback<Task>>() {
        @Override
        public void success(ArrayList<Task> list, Response response) {
            //process your response if successful load the list in your listview adapter

        }

        @Override
        public void failure(RetrofitError retrofitError) {
            retrofitError.printStackTrace(); //to see if you have errors
        }
    });
}

在您的详细清单中
private void myDetailed(String task_uuid){

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(Constants.URL)  //call your base url
    .build();


MyApi mytask = restAdapter.create(MyApi.class); //this is how retrofit create your api
mytask.getTaskList(task_uuid,new Callback<Task>() {
        @Override
        public void success(Task task, Response response) {
            //process your response if successful do what you want in your task

        }

        @Override
        public void failure(RetrofitError retrofitError) {
            retrofitError.printStackTrace(); //to see if you have errors
        }
    });
}

希望这能对你有所帮助,虽然使用Retrofit的最简单方式就是这样。


1
非常抱歉,如果我的问题非常琐碎,但我真的很难开始使用Retrofit(尚未取得任何进展)。我们是否应该有类似于php页面来完成这个任务? - Mohsen Kamrani
2
Retrofit是Android的REST API,基本上你需要有一个服务器端应用程序,比如PHP,你还需要构建你的API。如果你还没有尝试过在Android中使用REST创建简单的移动应用程序,你可以从这个教程开始,http://www.androidhive.info/2012/01/android-login-and-registration-with-php-mysql-and-sqlite/。如果你已经有了REST的经验,Retrofit将是一个很好的库来使用。 - chkm8
谢谢。确实,我已经尝试过这个了,我能够理解它。您创建一个 PHP 页面,以 POST 方式接收发送的内容,并以 JSON 格式生成响应。您是否有类似于Retrofit的教程? - Mohsen Kamrani
2
实际上这不是一个php页面,而应该是一个api,通常是接受JSON/XML格式的POST/GET请求的纯php脚本。以下是一个api示例。function login_post(){ $email = $this->post('email'); $password = $this->post('password'); $data = $this->Auth_model->authenticate($email, $password); print_r($data); } - chkm8

4

看看这篇关于如何将Retrofit与Otto结合使用的博客,这两个库都来自Square。

http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html

基本思路是在你的Application类中持有一个“repository”对象的引用。该对象将具有订阅rest api事件请求的方法。当收到请求时,它将进行适当的Retrofit调用,然后“发布”响应,这样另一个组件(例如发出请求的活动)就可以“订阅”它。
一旦正确设置了所有内容,通过您的rest api访问数据变得非常容易。例如,获取数据的请求看起来像这样:
    mBus.post(new GetMicropostsRequest(mUserId));

而获取数据的过程可能看起来像这样:

@Subscribe
public void onGetUserProfileResponse(GetUserProfileResponse event) {
    mView.setUserIcon("http://www.gravatar.com/avatar/" + event.getGravatar_id());
    mView.setUserName(event.getName());

}

需要一些前期的努力,但最终通过Rest从我们的后端访问任何你需要的东西变得“微不足道”。


3
使用Retrofit非常简单。
  • Add dependecy in build.gradle.

        compile 'com.squareup.retrofit:retrofit:1.9.0'
    
        compile 'com.squareup.okhttp:okhttp:2.4.0' 
    
  • Make an Interface for all http methods.

  • Copy your json output and create pojo class to recieve json of your
    response, you can make pojo from JsonSchema2pojo site .

  • make an adapter and call your method

    for complete demo try this tutorial Retrofit Android example


3
您可以尝试在应用程序类中保存对API的引用。然后,您可以从任何活动或片段获取其实例并从那里获取API。这听起来有点奇怪,但它可能是一种简单的依赖注入替代方法。如果您只在应用程序类中存储引用,则不会成为上帝对象。UPD:http://square.github.io/retrofit/ - 这里有一些文档,可能会有所帮助。

2
首先,在 MainActivity 中放置所有内容会是不好的做法,你最终会得到一个 God objectRetrofit 网站上的文档非常棒,因此我将阅读您关于如何构建项目的问题。我编写了一个非常小的应用程序作为演示。它从 cat API 加载猫,并且应该很容易理解正在发生什么。
它提供了使用 JSON 或 XML 解析来自服务的数据的示例。您可以在 https://github.com/codepath/android_guides/wiki/Consuming-APIs-with-Retrofit 找到它。
希望您能够推断出我为什么以这种方式构建它。我很乐意在评论中回答您的任何问题并更新答案。

2
请查看这个应用程序,它演示了Retrofit如何集成到Google Tasks API中。
在MainActivity中,有关于使用Retrofit api(TaskApi)的活动AsyncTask的例子,也有使用后台服务中Sync Adapter的例子。
虽然@nPn回答中发布的文章中的策略可能是更优雅的解决方案,但您至少可以查看另一个工作示例。 https://github.com/sschendel/SyncManagerAndroid-DemoGoogleTasks

2
我发现这些教程AndroidHiveCodePath对我很有帮助。
我将简要描述我所学到的内容。 步骤1:在build.gradle中添加这三个依赖项,并在Manifest中添加Internet权限。
compile 'com.google.code.gson:gson:2.6.2' // for string to class conversion. Not Compulsory
compile 'com.squareup.retrofit2:retrofit:2.1.0'// compulsory
compile 'com.squareup.retrofit2:converter-gson:2.1.0' //for retrofit conversion

将它们添加到清单文件中。
<uses-permission android:name="android.permission.INTERNET" />

步骤2 创建ApiClient和ApiInterface。

public class ApiClient {

    public static final String BASE_URL = "http://yourwebsite/services/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

找到 ApiInterface.class 的位置

public interface ApiInterface {

    // getting same data in three different ways.
    @GET("GetCompanyDetailByID")
    Call<CompanyResponse> getDetailOfComapanies(@Query("CompanyID") int companyID);


    @GET("GetCompanyDetailByID")
    Call<ResponseBody> getRawDetailOfCompanies(@Query("CompanyID") int companyID);

    @GET("{pathToAdd}")
    Call<CompanyResponse> getDetailOfComapaniesWithPath(@Path("pathToAdd") String pathToAppend, @Query("CompanyID") int companyID);
}

然后像这样调用该服务:

ApiInterface apiService =
                ApiClient.getClient().create(ApiInterface.class);

        Call<CompanyResponse> companyResponseCall = apiService.getDetailOfComapanies(2);
        //Call<CompanyResponse> companyResponseCall = apiService.getDetailOfComapaniesWithPath("GetCompanyDetailByID",2);

        companyResponseCall.enqueue(new Callback<CompanyResponse>() {
            @Override
            public void onResponse(Call<CompanyResponse> call, Response<CompanyResponse> response) {
                CompanyResponse comapnyResponse = response.body();
                Boolean status  = comapnyResponse.getStatus();
            }

            @Override
            public void onFailure(Call<CompanyResponse> call, Throwable t) {
            }
        });

获取原始的Json字符串

Call<ResponseBody> call = apiService.getRawDetailOfCompanies(2);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    String jsonStr = response.body().string();
                    if(!jsonStr.isEmpty()){
                        Gson gson = new Gson();

                        JSONObject jObject = new JSONObject(jsonStr).getJSONObject("data");

                        //1st Method
                        Data dataKiType = gson.fromJson(jObject.toString(), Data.class);
                        dataKiType.getCompanyDetail();

                        //2nd method for creaing class or List at runTime
                        Type listType = new TypeToken<Data>(){}.getType();
                        Data yourClassList = new Gson().fromJson(jObject.toString(), listType);
                        yourClassList.getCompanyDetail();
                    }  e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
            }
        });

您可以使用http://www.jsonschema2pojo.org/创建您的业务对象,只需粘贴JSON,并将源类型选择为JSON,注释样式选择为GSon即可。

1
首先,将以下内容添加到Gradle文件中。
compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.google.code.gson:gson:2.7'
    compile 'com.squareup:otto:1.3.8'
    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

在Activity的OnCreate方法中创建对象。保留HTML格式,不进行解释。
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);    
OkHttpClient client= new OkHttpClient
                .Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(interceptor).build();
Gson gson=new GsonBuilder()
          .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
          .create();
Retrofit retrofit= new Retrofit.Builder()
                .baseUrl("url")
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

创建一个界面。
public interface summaryListAPI {
//post
    @FormUrlEncoded
    @POST("index.php")
    Call<summaryList> post(
            @Field("status") String status,
            @Field("sox") String sox
    );
//get
@GET("yesbdeChatHistoryList/{userId}/")
    Call<List<ChatTabTwoResp>> getFriends(
            @Path("userId") int userId
    );
}

创建类
public class summaryList {
    @SerializedName("bookingSummary") @Expose private List<summaryListData> status = new ArrayList<summaryListData>();
}   

public class summaryListData {
    @SerializedName("date") @Expose private String date;
}

将此方法添加到您的活动中。
 public void apiSummaryListMain(final Retrofit retrofit) {
        retrofit.create(summaryListAPI.class).post("8547861657","100").enqueue(new Callback<summaryList>() {
            @Override
            public void onResponse(Call<summaryList> call, Response<summaryList> response) {
                if (response.isSuccessful()) {
                    progressBar.setVisibility(View.INVISIBLE);
                     List<summaryListData> summary_List= response.body().getStatus();                   
                }else{              
                }
            }
            @Override
            public void onFailure(Call<summaryList> call, Throwable t) {

            }
        });

    }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接