Rxjava、retrofit初探

本文介绍了RxJava的基础概念,如Observable、OnSubscribe、Subscriber等,以及如何使用flatMap、filter、take等操作符处理数据流。此外,还展示了RxJava与Retrofit结合使用的方法,以及在界面开发中如何利用RxJava提高代码质量。通过实例演示了如何在取数据前检查缓存,如何控制线程执行,以及如何在复杂的数据变换中应用RxJava。

刚开始学习,先记录一些东西,以后再做整理

建议查看深入浅出RxJava

Awesome-RxJava lzyzsd收集的关于Rxjava的知识

给 Android 开发者的 RxJava 详解

———————–所以下面就不用看了,只是搜集一些我觉得挺重要的,要条理的话看上面的

package com.example.kevin.rxjava;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func1;

public class MainActivity extends AppCompatActivity {

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

        Observable<String> myObservable = Observable.create(
                new Observable.OnSubscribe<String>(){

                    @Override
                    public void call(Subscriber<? super String> subscriber) {
                        subscriber.onNext("Hello Rxjava");
                        subscriber.onCompleted();
                    }
                }
        );

        Subscriber<String> mySubscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }
        };

        myObservable.subscribe(mySubscriber);


        Observable.just("Hello RxJava")
                .map(new Func1<String, Integer>() {
                    @Override
                    public Integer call(String s) {
                        return s.hashCode();
                    }
                }).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer s) {
                System.out.println(s);
            }
        });
    }
}

需要搞懂:
Observable、OnSubscribe、Subscriber
flatMap():接收一个Observable的输出作为输入,同时输出另外一个Observable
filter():输出和输入相同的元素,并且会过滤掉那些不满足检查条件的。
take()
from():它接收一个集合作为输入,然后每次输出一个元素给subscriber:
doOnNext()允许我们在每次输出一个元素之前做一些额外的事情,比如这里的保存标题。

.subscribeOn(Schedulers.io())
observerOn()

a. 打印字符串数组

将字符串数组 names 中的所有字符串依次打印出来:

String[] names = ...;
Observable.from(names)
    .subscribe(new Action1<String>() {
        @Override
        public void call(String name) {
            Log.d(tag, name);
        }
    });

b. 由 id 取得图片并显示

由指定的一个 drawable 文件 id drawableRes 取得图片,并显示在 ImageView 中,并在出现异常的时候打印 Toast 报错:

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});

线程控制 —— Scheduler,有了Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。

  • Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
  • Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
  • Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和
    newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io()
    比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O
    等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在
    computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android
    主线程运行。
Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1、2、3、4 将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 数字的打印将发生在主线程 。事实上,这种在 subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。

Scheduler 的原理

RxJava 提供了对事件序列进行变换的支持,这是它的核心功能之一,也是大多数人说『RxJava 真是太好用了』的最大原因。所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。

retrofit + rxjava

Retrofit

大名鼎鼎的Retrofit库内置了对RxJava的支持。通常调用发可以通过使用一个Callback对象来获取异步的结果:

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

两个请求并发的发出:

Observable.zip(
    service.getUserPhoto(id),
    service.getPhotoMetadata(id),
    (photo, metadata) -> createPhotoWithData(photo, metadata))
    .subscribe(photoWithData -> showPhoto(photoWithData));
@GET("/token")
public Observable<String> getToken();

@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);

...

getToken()
    .flatMap(new Func1<String, Observable<User>>() {
        @Override
        public Observable<User> onNext(String token) {
            return getUser(token, userId);
        })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<User>() {
        @Override
        public void onNext(User user) {
            userView.setUser(user);
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable error) {
            // Error handling
            ...
        }
    });

RxJava使用场景小结

取数据先检查缓存的场景

取数据,首先检查内存是否有缓存
然后检查文件缓存中是否有
最后才从网络中取
前面任何一个条件满足,就不会执行后面的

final Observable<String> memory = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        if (memoryCache != null) {
            subscriber.onNext(memoryCache);
        } else {
            subscriber.onCompleted();
        }
    }
});
Observable<String> disk = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        String cachePref = rxPreferences.getString("cache").get();
        if (!TextUtils.isEmpty(cachePref)) {
            subscriber.onNext(cachePref);
        } else {
            subscriber.onCompleted();
        }
    }
});
Observable<String> network = Observable.just("network");

//主要就是靠concat operator来实现
Observable.concat(memory, disk, network)
.first()
.subscribeOn(Schedulers.newThread())
.subscribe(s -> {
    memoryCache = "memory";
    System.out.println("--------------subscribe: " + s);
});

界面需要等到多个接口并发取完数据,再更新

//拼接两个Observable的输出,不保证顺序,按照事件产生的顺序发送给订阅者
private void testMerge() {
    Observable<String> observable1 = DemoUtils.createObservable1().subscribeOn(Schedulers.newThread());
    Observable<String> observable2 = DemoUtils.createObservable2().subscribeOn(Schedulers.newThread());

    Observable.merge(observable1, observable2)
            .subscribeOn(Schedulers.newThread())
            .subscribe(System.out::println);
}

一个接口的请求依赖另一个API请求返回的数据

举个例子,我们经常在需要登陆之后,根据拿到的token去获取消息列表。

这里用RxJava主要解决嵌套回调的问题,有一个专有名词叫Callback hell

NetworkService.getToken("username", "password")
    .flatMap(s -> NetworkService.getMessage(s))
    .subscribe(s -> {
        System.out.println("message: " + s);
    });

界面按钮需要防止连续点击的情况

RxView.clicks(findViewById(R.id.btn_throttle))
    .throttleFirst(1, TimeUnit.SECONDS)
    .subscribe(aVoid -> {
        System.out.println("click");
    });

响应式的界面

比如勾选了某个checkbox,自动更新对应的preference

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences);

Preference<Boolean> checked = rxPreferences.getBoolean("checked", true);

CheckBox checkBox = (CheckBox) findViewById(R.id.cb_test);
RxCompoundButton.checkedChanges(checkBox)
        .subscribe(checked.asAction());

复杂的数据变换

Observable.just("1", "2", "2", "3", "4", "5")
    .map(Integer::parseInt)
    .filter(s -> s > 1)
    .distinct()
    .take(3)
    .reduce((integer, integer2) -> integer.intValue() + integer2.intValue())
    .subscribe(System.out::println);//9
### 集成 RxJavaRetrofit 和 OkHttp 的方法 在 Android 开发中,将 RxJavaRetrofit 和 OkHttp 集成使用是一种常见的网络编程实践。以下是集成这些库的详细步骤和示例代码。 #### 1. 添加依赖项 首先需要在项目的 `build.gradle` 文件中添加必要的依赖项。以下是一个完整的依赖配置示例: ```gradle // 添加 Retrofit 依赖 implementation 'com.squareup.retrofit2:retrofit:2.9.0' // 添加 RxJava 适配器 implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' // 添加 Gson 转换器(用于解析 JSON 数据) implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 添加 OkHttp 依赖 implementation 'com.squareup.okhttp3:okhttp:4.10.0' // 添加 OkHttp 日志拦截器(调试用) implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0' ``` 上述依赖项涵盖了 RetrofitRxJava 适配器、Gson 转换器以及 OkHttp 和其日志拦截器的功能[^1]。 #### 2. 配置 OkHttpClient OkHttp 是 Retrofit 的底层 HTTP 客户端。可以通过自定义 OkHttpClient 来增强功能,例如添加日志拦截器或设置超时时间。 ```java import okhttp3.OkHttpClient; import java.util.concurrent.TimeUnit; public class HttpClient { public static OkHttpClient getOkHttpClient() { return new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) // 设置连接超时时间 .readTimeout(30, TimeUnit.SECONDS) // 设置读取超时时间 .writeTimeout(30, TimeUnit.SECONDS) // 设置写入超时时间 .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) // 添加日志拦截器 .build(); } } ``` #### 3. 配置 Retrofit 通过 Retrofit 构建一个网络请求接口,并指定使用 RxJava 和 OkHttpClient。 ```java import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; public class ApiClient { private static final String BASE_URL = "https://api.example.com/"; public static Retrofit getRetrofitInstance() { return new Retrofit.Builder() .baseUrl(BASE_URL) .client(HttpClient.getOkHttpClient()) // 使用自定义的 OkHttpClient .addConverterFactory(GsonConverterFactory.create()) // 使用 Gson 转换器 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用 RxJava 适配器 .build(); } } ``` #### 4. 创建 API 接口 定义一个接口来描述网络请求的方法。以下是一个简单的 GET 请求示例: ```java import io.reactivex.Observable; import retrofit2.http.GET; import retrofit2.http.Path; public interface ApiService { @GET("users/{user}") Observable<User> getUser(@Path("user") String user); } ``` #### 5. 使用 RxJava 进行网络请求 通过 Retrofit 获取 API 实例,并使用 RxJava 处理响应。 ```java import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; public class NetworkRequest { public static void fetchUser(String username) { ApiService apiService = ApiClient.getRetrofitInstance().create(ApiService.class); Disposable disposable = apiService.getUser(username) .subscribeOn(Schedulers.io()) // 在 IO 线程上执行网络请求 .observeOn(AndroidSchedulers.mainThread()) // 切换到主线程处理结果 .subscribeWith(new DisposableObserver<User>() { @Override public void onNext(User user) { // 处理成功的结果 System.out.println("User: " + user.getName()); } @Override public void onError(Throwable e) { // 处理错误 System.err.println("Error: " + e.getMessage()); } @Override public void onComplete() { // 请求完成 System.out.println("Completed"); } }); } } ``` #### 注意事项 - 确保在 `AndroidManifest.xml` 中声明了互联网权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> ``` - 如果需要支持 HTTPS,请确保服务器证书有效,或者在开发环境中配置信任所有证书(不推荐用于生产环境)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值