初步认识Retrofit

Retrofit是现在比较流行的网络框架,自己也试着弄了一下,通过断点调试,看代码一步一步执行,感觉行蛮好玩的,同时对源码的理解更加透彻一点。博客的第一部分是基本用法,只要按照一步一步来,应该有效果;第二部分是源码解析,有什么写错的还请大家指出

一、Retrofit基本用法

1.添加依赖

    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'

2.使用build模式创建一个Retrofit对象,使用build模式的好处就是能够在build()方法调用之前能够通过调用各个方法,比如说.baseUrl()配置url等你自己需要用到的参数,用什么就配置什么

MainActivity.java
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://apis.baidu.com/")   			//百度提供的API接口中的名人名言
        .addConverterFactory(GsonConverterFactory.create())	//使用Gson解析请求网络返回的数据
        .build();						
3.新建一个接口

MyService.java
public interface MyService {
    @GET("avatardata/mingrenmingyan/lookup")		//使用Get请求,将括号里面的内容拼接在上面的baseUrl后面形成一条完整的url
    Call<Famous> getMessage(@Header("apikey") String apikey,@Query("keyword")String keyword);   //使用百度提供的API接口需要传入的是一个key和一个keyword

}
4.获取一个网络请求call

MainActivity.java  
MyService s = retrofit.create(MyService.class);            //通过create方法返回一个接口实例,MyService就是自己定义的接口
Call<Famous> call = s.getMessage("你自己的key","天才"); //调用getMessage方法,传入的参数就是一个key和一个keyword</span>

5.将请求入队,这里的onResponse是运行在主线程中的,为什么呢,先用着,然后看接下来的源码分析

MainActivity.java
call.enqueue(new Callback<Famous>() {
      @Override
      public void onResponse(Call<Famous> call, Response<Famous> response) {  	//请求成功后返回的数据保存在response中,然后要对数据干什么就看你自己了
            for (int i = 0; i < response.body().getResult().size(); i++) {      //这里循环打印请求回来的数据
                 System.out.println(response.body().getResult().get(i).getFamous_name()+":"+
                        response.body().getResult().get(i).getFamous_saying());
            }
      }
      @Override
      public void onFailure(Call<Famous> call, Throwable t) {	//请求失败时调用
      }
});

二、源码解析

1、通过build()方法创建出Retrofit对象,直接贴出源码,在源码中我写了注释,直接根据注释理解源码,相信会比较快一点

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();  //新建一个okhttp请求
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
//这里的callbackExecutor就相当于位于主线程的handler,那么调用handler.post(Runnable r)中的Runnable就是在主线程中执行,具体代码可以从源码中查看
    callbackExecutor = platform.defaultCallbackExecutor();
  }

//defaultCallbackExecutor中的代码如下,这里为了方便大家理解,所以我直接从相关联的java文件中拷贝相应的代码贴在下面,方便大家理解
//@Override public Executor defaultCallbackExecutor() {
//     return new MainThreadExecutor();
//   }
//static class MainThreadExecutor implements Executor {
//      private final Handler handler = new Handler(Looper.getMainLooper());
//      @Override public void execute(Runnable r) {
//        handler.post(r);
//      }
//    }

//通过调用platform.defaultCallAdapterFactory(callbackExecutror)返回的是一个ExecutorCallAdapterFactory对象,该对象与接下来步骤2和3中的是同一个
//这里只需要记住一个callbackExecutor即位于主线程中的handler被加入到一个//ExecutorCallAdapterFactory中就可以了
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
 
//返回一个Retrofit对象
  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}

2、通过retrofit.create()方法动态代理返回自己定义的接口的类型的实例对象

3、通过Call<> call = MyService.getMessage(“各种参数”)(这里的类和方法都是自己定义的,这个的MySevice接口和getMessage方法都是我自己写的)返回一个okHttpCall,下面三行是源码,是执行的关键,当调用自定义接口Myservice中的getMessage方法,就会执行下面三行

ServiceMethod serviceMethod = loadServiceMethod(method);  
         OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
         return serviceMethod.callAdapter.adapt(okHttpCall);       
第一行:通过调用这一行,getMessage()方法里面的所有参数都会被解析,加上之前的baseUrl(),拼接成一条能够被okhttp识别的url,而解析参数的方法就是根据注解的不一样,比如说Call<Famous> getMessage(@Header("apikey")  String apikey,@Query("keyword") String keyword) ,这里的String类型的apikey就会被识别为Header,而keyword就会被识别为Query,然后进行解析

第二行:新建一个okhttp请求

第三行:执行的结果就是返回一个请求Call。将okhttp请求作为参数传入到callAdapter.adapter()中去,那么出入之后代码执行到哪里呢?接下来我在这里打了个断点,debug状态下进入到了adapt()方法内:

@Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
可以看出okhttp请求就是作为参数传入到adapter方法中,然后在再执行ExecutorCallback的构造方法,真是不容易啊,大家要hold住啊,我们来看下第一个参数又是什么,还记得我们在新建一个Retrofi对象的时候调用的build方法么,那里面有一个callbackExecutor,也就是一个在主线程中的handler,为什么我老是要强调这一点呢,因为这个handler是王牌啊,没有它,接下来的路难走啊!好,那么我们再来确认一下ExecutorCallbackCall()中的两个参数,第一个就是handler,第二个就是okhttp请求。接下来我们来看下new出的ExecutorCallbackCall又有什么用呢?我们暂时留着问题,总结一下,通过调用完第三步,我们能够获得一个ExecutorCallbackCall,在这个Call中我们传入了两个参数,一个是handler,一个是okhttpcall。

4、call.enqueue(new Callback<>)    请求入队。这里的call就是我们第三步获得的ExecutorCallbackCall,那么我们直接贴出ExecutorCallbackCall的源码,源码之前,了无秘密,然我们看下最后一步究竟干了些什么?我们直接看enqueue方法,该方法内部又调用了delegate.enqueue(),那么这个delegate又是谁呢?不要晕,看到ExecutorCallbackcall的构造方法没有,里面的第二个参数就是 delegate,还记得我们第三步做了什么么,其实第二个参数就是okhttp请求啦,所以说这里调用了ExecutorCallbackCall.enqueue其实就是调用了okhttp.enqueue,接着往下看,delegate.enqueue里面又有一个callbackExecutor.execute(new Runnable()),这个callbackExecutor就是位于主线程的handler,而执行的executor方法里面就是handler.post(Runnable),所以现在是不是明白了,为什么call.enqueue里面的onResponse是运行在主线程中了吧,完全就是因为这个handler。总结一下第四步,调用call.enqueue,本质就是在主线程中调用handler.post方法完成异步操作

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

作为一名博客新人,有什么写的不好的还望大家指出

三、代码

注意自己要先导入依赖,依赖就在上面

package com.binge.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void getMes(View view) {
        Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://apis.baidu.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        MyService s = retrofit.create(MyService.class);
        Call<Famous> call = s.getMessage("<span style="font-family: Arial, Helvetica, sans-serif;">你自己的key</span><span style="font-family: Arial, Helvetica, sans-serif;">","天才" );   //注意,这里的第一个参数是你自己在百度API上申请的账号的key</span>
        call.enqueue(new Callback<Famous>() {
            @Override
            public void onResponse(Call<Famous> call, Response<Famous> response) {
                for (int i = 0; i < response.body().getResult().size(); i++) {
                    System.out.println(response.body().getResult().get(i).getFamous_name()+":"+
                            response.body().getResult().get(i).getFamous_saying());
                }

            }

            @Override
            public void onFailure(Call<Famous> call, Throwable t) {

            }
        });

    }
}

package com.binge.myapplication;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Query;

/**
 * Created by binge on 2016/11/2.
 */
public interface MyService {
    @GET("avatardata/mingrenmingyan/lookup")
    Call<Famous> getMessage(@Header("apikey") String apikey,@Query("keyword")String keyword);

}


package com.binge.myapplication;

import java.util.List;

/**
 * Created by binge on 2016/11/2.
 */
public class Famous {
    public int total;
    public List<Result> result;
    public int error_code;

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public List<Result> getResult() {
        return result;
    }

    public void setResult(List<Result> result) {
        this.result = result;
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public String reason;
}

package com.binge.myapplication;

/**
 * Created by binge on 2016/11/2.
 */
public class Result {
    public String getFamous_name() {
        return famous_name;
    }

    public void setFamous_name(String famous_name) {
        this.famous_name = famous_name;
    }

    public String getFamous_saying() {
        return famous_saying;
    }

    public void setFamous_saying(String famous_saying) {
        this.famous_saying = famous_saying;
    }

    public String famous_name;
    public String famous_saying;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值