RxAndroid and Retrofit 2.0

RxAndroid and Retrofit 2.0

关于Rx的学习我参考了这篇博客,是我在网上看到的博客中写的比较全的
http://blog.csdn.net/meegomeego/article/details/49155989/

Retrofit 2.0还是测试版, 主要是‘领导’说Retrofit 比okHttp 和 Volley要好,今天弄了下,例子是照retrofit官网敲的。
http://square.github.io/retrofit/

设计还在弄设计图,闲的没什么事,翻译一下retrofit的官网吧

Retrofit

A type-safe HTTP client for Android and Java(蛋疼,这句怎么翻译)

Introduction

Retrofit让你的http api 变成java接口

public interface GitHubService { 
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

Retrofit会生成一个GitHubService接口的实现

Retrofit retrofit = new Retrofit.Builder() 
.baseUrl("https://api.github.com/") 
.build();

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

每一个GitHubService的回调,都会make一个同步或者异步的http请求到远程的webserver

Call> repos = service.listRepos("octocat");

使用注解去描述http请求

  • url参数支持替换和查询
  • 对象转换到请求体
  • 复合的请求体和文件上传

API Declaration

注解的方法和他的参数怎样处理一个请求

REQUEST METHOD

每一个方法必须有一个http的注解,他提供了一个请求的方法和一个相对的url。一共有5中注解GET, POST, PUT, DELETE, and HEAD。资源的相对url在注解中规定

@GET("users/list")

还可以指定url的查询参数

@GET("users/list?sort=desc")   

URL MANIPULATION

一个请求的url中的参数和blocks可以被动态的替换,这个blocks要被{}包围。这个参数要使用@Path注解,并且使用同一个字符

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId);

查寻参数也可以被添加

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @Query("sort") String sort);

对于相对复杂的查询参数也可以使用map

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @QueryMap Map options);

REQUEST BODY

使用@Body注解可以指定一个对象作为HTTP请求体。

@POST("users/new")
Call createUser(@Body User user);

这个对象也可以使用一个Retrofit的实例指定的一个转换器转换,如果没有添加这个转换器,就会使用RequestBody(没看懂)

FORM ENCODED AND MULTIPART

方法也可以用来生命发送表单编码和符合数据
表单编码的数据发送当@FormUrlEncoded存在的方法。每个键-值对注释@Field包含名称和对象提供的价值。

@FormUrlEncoded
@POST("user/edit")
Call updateUser(@Field("first_name") String first, @Field("last_name") String last);

多部分请求时使用@Multipart存在的方法。部分使用@Part注释声明。

@Multipart
@PUT("user/photo")
Call updateUser(@Part("photo") RequestBody photo, @Part("description")
RequestBody description);

部分部件采用改造的转换器,也可以实现RequestBody处理自己的序列化。

HEADER MANIPULATION

可以使用@Headers注释的方法设置静态头。

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call> widgetList();
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App"})
@GET("users/{username}")
Call getUser(@Path("username") String username);

注意,头不会互相覆盖。具有相同名称的所有头文件都包括在请求

END

后面的说的就不往上粘了,因为我也看不懂

在运行例子的时候遇见了一些问题,当时看了一些其他的博客,GitHubService 是作为参数回掉的,返回值是空,运行的过程提示GitHubService 的返回值不能使空了, 不知道是不是2.0和之前的差别
接下来就是在Rx中使用Retrofit了

按照官网的做法
创建了一个GitHubService,这个接口简单的写了两个方法,第一个方法在RX中使用了Retrofit,要注意的就是每个请求前面都是/

public interface GitHubService
 {
    @GET("/{users}/mobilesiri")
    Observable getUser(@Path("users") String user);

    @GET("/users/mobilesiri")
    Call getUser2();
}

这里没使用官网上给的api接口,用的是https://api.github.com/users/mobilesiri
官网上面的数据太多了,然后用JsonFromat生成了一个bean 叫 Repo.java

接着就是主要的内容了
baseUrl是请求的通用的部分,这里设定的就是

private static final String URI = "https://api.github.com";

addConverterFactory 这个是设置用Gson转换,也可以自定义, 但自定义这个后面再说吧
addCallAdapterFactory 这个在Rx中使用的话要添加
还有提个坑就是这个依赖,一定要对应,版本不对,网又不好,在这弄了半天

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'

Rx也跟最新的版本就行了

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URI)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
GitHubService gitHubService = retrofit.create(GitHubService.class);
Call repos2 = gitHubService.getUser2();

repos2.enqueue(new Callback() {
                @Override
                public void onResponse(Response response,
                    Retrofit retrofit) {
                }

                @Override
                public void onFailure(Throwable t) {
                }
            });

以上是没有用Rx的代码
下面就是在Rx中使用Retrofit的代码了,完成一次网络请求,从实现上来说还是很简单的

gitHubService.getUser("users").subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread())
             .subscribe(new Action1() {
                  @Override
                  public void call(Repo repo) {
                }
            });

subscribeOn 指定的是observe运行线程;observeOn是subscribe的运行线程,呃……
当然subscribe中new 一个 Subscriber去实现onCompleted onError onNext
以上就是在Rx中使用Retrofit做网络请求的基本方法了

——————————————————————————————--

RxAndroid

Observable (被观察者)
Subscribers (订阅者)

Observable 我理解成了事件的发送者,Subscribers为事件的处理,这样方便理解吧……默背十遍,记住这两个概念,省得记混。
下面就照网上的教程敲一个小例子吧!!!

一、尝试

  • 导入rx所需要的包
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
  • 大概的思路是创建一个消息的发送者和接收者,然后将他们链接起来,和大象一样,也是分三步:
    第一个例子啥也不说了,直接上代码
package tiny.rxandrioddemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import rx.Observable;
import rx.Subscriber;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private Observable mObservable;
    private Subscriber mSubscriber;

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

        createObservable();
        createSubscriber();
        bindEvent();
    }

    private void bindEvent() {
        mObservable.subscribe(mSubscriber);
    }

    private void createSubscriber() {
        mSubscriber = new Subscriber() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable throwable) {
                    }

                    @Override
                    public void onNext(String s) {
                        Log.d(TAG, "onNext: " + s);
                    }
                };
    }

    private void createObservable() {
        mObservable = Observable.create(new Observable.OnSubscribe() {
                    @Override
                    public void call(Subscriber subscriber) {
                        subscriber.onNext("haha");
                        subscriber.onCompleted();
                    }
                });
    }
}

二、继续尝试

看到了rx中有from just ……这些东西, 看看这个是干嘛的吧, 之后一顿百度:
rx提供了一些快捷创建事件队列的方式,就上上面一行中提到的just和from了

  • just(T...): 将传入的参数依次发送出来。
  • from(T[])/ from(Iterable): 将传入的数组或 Iterable拆分成具体对象后,依次发送出来。
    依然还是先上代码了,上面的方法简化成下边这样
private void createObservable() {
    mObservable = Observable.just("ha1", "ha2", "ha3");
}

程序调用了三次doNext 一次 onComleted


Paste_Image.png

再将上面的代码改成这样, 也是ok的

private void createObservable(){  
List eventList = new ArrayList<>();    
eventList.add("haha1"); 
eventList.add("haha2");    
eventList.add("haha3");   
mObservable = Observable.from(eventList);
}

三、呃……还是尝试

和上面一样,事件的发送者简化了,那么还想简化一下事件的处理,之后发现了actionx 这个方法,那么就改一下createSubscriber()

private void createSubscriber(){
    mSubscriberAction = new Action1(){ 
        @Override
        public void call(String s){
            Log.d(TAG, "call: " + s);
        }
    };
}

下面是输出结果

Paste_Image.png

三、迷之变幻

  • map(): 事件对象的直接变换,可以将一个对象转变成另一个对象。它是 RxJava 最常用的变换
  • flatMap():这个事件比较复杂,就举个网上的例子来说明吧
    参考了博客http://blog.csdn.net/daditao/article/details/50606228
    首先假设这么一种需求:假设有一个数据结构『学生』,现在需要打印出一组学生的名字。实现方式很简单:
RxAndroid and Retrofit 2.0_第1张图片
Paste_Image.png

很简单。那么再假设:如果要打印出每个学生所需要修的所有课程的名称呢?(需求的区别在于,每个学生只有一个名字,但却有多个课程。)首先可以这样实现:

RxAndroid and Retrofit 2.0_第2张图片
Paste_Image.png

我哟啊是不想用for循环来输出也可以这么写

RxAndroid and Retrofit 2.0_第3张图片
Paste_Image.png

这样就简单了
具体详细的可以看上面链接中的博客,就比较全面了

  • Funcx:在变换中,使用了Funcx这个方法,这个方法同Actionx一样理解,但是Funcx一些列的方法是带有返回值的

四、线程切换

写代码测试之后,发现RxAndroid 中可以使用observeOn 方法来切换线程,但是还没有摸清subscribeOn方法是干什么用的。
之前以为observeOn是设置Observable的运行线程;而subscribeOn是规定了subscribe的线程

总结:初学到这了,基本上可以拿Rxandroid写一个例子,在写例子的时候在慢慢学习Rx吧

大概一个月之前看了看Retrofit进行网络接口, 这把手里的这个应用的网络层改成Retrofit,但是公司的应用,请求的时候都要改header和post,弄了一下,随后就又开始加班了(艹)。之前打的都快忘了,还是趁着空闲的时间先记下来吧。

package tiny.rxandrioddemo.mkmy.net.net;

import android.text.TextUtils;
import android.util.Log;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import tiny.rxandrioddemo.App;

public class RetrofitUtil
{
    private static final String TAG = "RetrofitUtil";
    private static final Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
    private static final CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create();
    public static final MediaType JSON
            = MediaType.parse("application/json; charset=utf-8");


    public static Retrofit getRetrofit(String baseUrl)
    {
        return new Retrofit.Builder()
                .client(okHttpClientConfig())
                .baseUrl(baseUrl)
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(rxJavaCallAdapterFactory)
                .build();
    }

    private static OkHttpClient okHttpClientConfig()
    {
        return new OkHttpClient.Builder()
                .addInterceptor(new LogInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .build();
    }

    public void cancel()
    {
    }


    private static class LogInterceptor implements Interceptor
    {
        @Override
        public okhttp3.Response intercept(Chain chain) throws IOException
        {

            Request originalRequest = chain.request();

            Request.Builder originalRequestBuilder = chain.request().newBuilder();


            //  headers
            String userAgent = System.getProperty("http.agent");
            userAgent = App.getInstance().getChannelName() +
                    "/" + App.getInstance().getVersionName()
                    + " " + userAgent;
            Log.d(TAG, "intercept userAgent : " + userAgent);
            originalRequestBuilder.addHeader("User-Agent", userAgent);

            String session = App.getInstance().getSp("PHPSESSID");
            Log.d(TAG, "intercept session : " + session);
            if (!TextUtils.isEmpty(session))
            {
                //originalRequestBuilder.addHeader("Cookie", "PHPSESSID=ndi4uke0r1thf9m1taimv078u3");
            }
            Log.d(TAG, "intercept body: " + (originalRequest.body() instanceof FormBody));
            if (originalRequest.body() instanceof FormBody)
            {
                FormBody originalBody = (FormBody) originalRequest.body();
                FormBody.Builder newFormBody = new FormBody.Builder();

                Log.d(TAG, "intercept POST sizer: " + originalBody.size());
                for (int i = 0; i < originalBody.size(); i++)
                {
                    Log.d(TAG, "intercept fied: " + originalBody.encodedName(i));
                    if (!originalBody.encodedName(i).equals("nu"))
                        newFormBody.addEncoded(originalBody.encodedName(i), originalBody.encodedValue(i));
                }
                String[] values = App.getInstance().getNetInfo();
                if (!TextUtils.isEmpty(values[0]) && !TextUtils.isEmpty(values[1]))
                {
                    newFormBody.add("sig", values[0]);
                    Log.d(TAG, "intercept sig: " + values[0]);
                    newFormBody.add("timestamp", values[1]);
                    Log.d(TAG, "intercept timestamp: " + values[1]);
                }

                originalRequestBuilder.method(originalRequest.method(), newFormBody.build());
            }


            Request req = originalRequestBuilder.build();
            Log.d(TAG, "intercept: x: " + req.headers().toString());
            Log.d(TAG, "intercept: method: " + req.method());
            Log.d(TAG, "intercept: url: " + req.url());
            Log.d(TAG, "intercept: body: " + req.body());

            okhttp3.Response response = chain.proceed(req);

            if (response.body() != null)
            {
                try
                {
                    String mHeader = response.headers().toString();
                    Log.i(TAG, "intercept: header1: " + mHeader);
                    Pattern pattern = Pattern.compile("Set-Cookie.*?;");
                    Matcher m = pattern.matcher(mHeader);
                    String cookieFromResponse = "";
                    if (m.find())
                    {
                        cookieFromResponse = m.group();
                    }
                    Log.i(TAG, "intercept: header2: " + cookieFromResponse);
                    // 去掉cookie末尾的分号
                    // cookieFromResponse = cookieFromResponse.substring(11, cookieFromResponse.length() - 1);
                    App.getInstance().setSp("PHPSESSID", cookieFromResponse);
                } catch (Exception e)
                {
                    e.printStackTrace();
                }

                return response;
            }
            else
            {
                return response;
            }
        }
    }
}


你可能感兴趣的:(RxAndroid and Retrofit 2.0)