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 extends T>): 将传入的数组或 Iterable拆分成具体对象后,依次发送出来。
依然还是先上代码了,上面的方法简化成下边这样
private void createObservable() {
mObservable = Observable.just("ha1", "ha2", "ha3");
}
程序调用了三次doNext 一次 onComleted
再将上面的代码改成这样, 也是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);
}
};
}
下面是输出结果
三、迷之变幻
- map(): 事件对象的直接变换,可以将一个对象转变成另一个对象。它是 RxJava 最常用的变换
- flatMap():这个事件比较复杂,就举个网上的例子来说明吧
参考了博客http://blog.csdn.net/daditao/article/details/50606228
首先假设这么一种需求:假设有一个数据结构『学生』,现在需要打印出一组学生的名字。实现方式很简单:
很简单。那么再假设:如果要打印出每个学生所需要修的所有课程的名称呢?(需求的区别在于,每个学生只有一个名字,但却有多个课程。)首先可以这样实现:
我哟啊是不想用for循环来输出也可以这么写
这样就简单了
具体详细的可以看上面链接中的博客,就比较全面了
- 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;
}
}
}
}