Tutorial de aprendizaje de RxJava2 (2) programación de subprocesos

La programación de subprocesos también se denomina cambio de subprocesos.En Rxjava, la regla predeterminada es que el problema (completado por el observador) y el consumo (completado por el observador) están en el mismo subproceso. Encontró una situación similar: operaciones que requieren mucho tiempo en el subproceso, y luego de vuelta al subproceso principal para las operaciones de la interfaz de usuario, en este caso, obviamente, es necesario cambiar el subproceso, ¿cómo lo completamos? Esta sección lo explicará.

Pistas del artículo:

  • Hilo de trabajo predeterminado observable (observado) y Observador ()
  • Cómo cambiar entre diferentes hilos para observador y observador
  • ¿Qué sabemos sobre ObserverOn () y SubscribeOn ()?
  • ¿Qué hilos están integrados en Rxjava? ¿Cuál es la diferencia?
  • Comprender y aprender la programación de hilos en Rxjava2 a través del combate real

Cómo cambiar hilos

Observable y Observer se ejecutan en el hilo principal por defecto
  Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
                Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());
                emitter.onComplete();
            }
        }).subscribe(new Observer<Integer>() {

            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "onSubscribe");
            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());
                Log.d(TAG, "onNext: " + integer);

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete");
            }
        });

Los resultados son los siguientes:

GfW9Pg.png

Como se puede ver en el código, cuando no se especifica el hilo donde se encuentran el Observable y el Observador, todos trabajan en el hilo principal de forma predeterminada, y el observador emite 1, 2, 3 y 4 eventos de datos enteros en el hilo principal respectivamente. El hilo principal recibe a su vez hasta que se complete el evento.

Cómo cambiar entre observador y observador

En el ejemplo anterior, por defecto, el observador y el observador trabajan en el hilo principal, es decir, el hilo principal envía datos y el hilo principal recibe. Si tenemos que darnos cuenta de que el observador envía datos en el hilo secundario, y luego el observador en el hilo principal Reciba en el hilo, luego se puede lograr fácilmente a través del programador de hilos incorporado de RxJava, el código de implementación es el siguiente:

   Observable.create(new ObservableOnSubscribe<Integer>() {
            @SuppressLint("LongLogTag")
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在子线程为" + Thread.currentThread().getName() + "生产一个事件: " + i );
                    emitter.onNext(i);
                    SystemClock.sleep(3000);
                }
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new Observer<Integer>() {
              @Override
              public void onSubscribe(Disposable d) {

              }

              @SuppressLint("LongLogTag")
              @Override
              public void onNext(Integer integer) {
                  Log.d(TAG, "下游观察者Observer在主线程:" + Thread.currentThread().getName()+"onNext事件中接收了:"+integer);

              }

              @Override
              public void onError(Throwable e) {

              }

              @SuppressLint("LongLogTag")
              @Override
              public void onComplete() {
                  Log.d(TAG, "onComplete: 下游观察者接收完毕");
              }
          });

Los resultados son los siguientes:

El observador en sentido ascendente envía un evento en el subproceso de E / S cada 3 segundos y el observador en sentido descendente lo recibe en el subproceso principal. En el proceso, se agregan las siguientes dos líneas de código:

.subscribeOn(Schedulers.newThread())   
.observeOn(AndroidSchedulers.mainThread())

La primera línea de código especifica el hilo del observador a través de subscribeOn, y la segunda línea de código especifica el hilo del observador. Entonces la pregunta es, ¿qué programador de hilos está integrado en RxJava?

Tipos de planificadores de subprocesos
Tipo de planificador Efecto
AndroidSchedulers.mainThread () El subproceso principal, subproceso de interfaz de usuario, se puede utilizar para actualizar la interfaz
Schedulers.newThread () Crea un nuevo hilo para cada tarea
Schedulers.io () Se utiliza para operaciones intensivas de E / S, como leer y escribir archivos de tarjetas SD, consultar bases de datos, acceder a la red, etc., con un mecanismo de almacenamiento en caché de subprocesos. Después de que el planificador recibe una tarea, primero verifica si hay subprocesos inactivos en el grupo de caché de subprocesos. En caso afirmativo, reutilice. Si no, cree un nuevo hilo y agréguelo al grupo de hilos. Si no se usa un hilo inactivo cada vez, puede crear un nuevo hilo sin un límite superior.
Schedulers.computation () Se utiliza para tareas informáticas intensivas en CPU, es decir, operaciones que consumen mucho tiempo y que no estarán limitadas por E / S y otras operaciones, como análisis de archivos xml y json, muestreo de compresión de imágenes de mapa de bits, etc., con un grupo de subprocesos fijos y un núcleo de CPU Numero No se puede usar para operaciones de E / S porque el tiempo de espera para las operaciones de E / S desperdicia la CPU.
Schedulers.from (ejecutor) Use el ejecutor especificado como el planificador
Schedulers.immediate () Inicie la tarea inmediatamente en el hilo actual (en desuso en Rxjava2), la función es equivalente a Schedulers.trampoline () en RxJava2
Schedulers.trampoline () La tarea se ejecuta inmediatamente en el subproceso actual. Si hay una tarea en el subproceso actual, se suspenderá. Después de ejecutar la tarea insertada, se ejecutará la tarea inacabada. (Cortar en línea)
subscribeOn () 和 ObserveOn ()
  • Rxjava proporciona el método subscribeOn () para el operador de cada objeto observable en qué hilo; el método ObserveOn () para cada operador del objeto Suscriptor (Observador) en qué hilo
  • SubscribeOn () solo se ejecuta una vez cuando se cambia el hilo. Si hay múltiples ocurrencias, prevalecerá el hilo utilizado para la primera ocurrencia. observeOn () se puede llamar varias veces y cambiar a un subproceso diferente especificado
Llame a subscribeOn () dos veces y ObserverOn () una vez

Cuando usamos subscribeOn () dos veces, solo el hilo especificado por primera vez será el principal. El código es el siguiente:

  //使用两次subscribeOn() 和 一次observeOn()的线程调度
        //通过两次设置subscribeOn()发射和处理数据在不同的线程,但是最终起作用的是第一次设置的工作线程
        //由此可以得出多次设置subscribeOn()设置被观察者Observable工作的线程最终起作用的是第一次设置的线程
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @SuppressLint("LongLogTag")
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.d(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(1000);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .map(new Function<Integer, Integer>() {
                    @SuppressLint("LongLogTag")
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "map操作符在" + Thread.currentThread().getName() + "线程处理了事件: " + integer);
                        return integer * 2;
                    }
                })
                .observeOn(Schedulers.io())
                .subscribe(new Consumer<Integer>() {
                    @SuppressLint("LongLogTag")
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "下游观察者Observer在IO线程" + Thread.currentThread().getName() + "接收响应到了事件: " + integer);
                    }
                });

Los resultados son los siguientes:

Como puede ver, especificamos el hilo donde la persona observada se encuentra dos veces, pero al final, el operador del mapa se imprime en el hilo principal principalmente por primera vez.

.subscribeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
Llame a subscribeOn () una vez y observeOn () dos veces
 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                LogUtil.d("上游被观察者所在IO线程为:"+Thread.currentThread().getName());
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(new Function<Integer, String>() {
                    @Override
                    public String apply(Integer integer) throws Exception {
                        LogUtil.d("下游观察者线程为"+Thread.currentThread().getName());
                        return 2*integer+"";
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        LogUtil.d("onNext():下游观察者所在线程为"+Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable e) {
                    }
                    @Override
                    public void onComplete() {

                    }
                });

El resultado de ejecutar el código es el siguiente:

Se puede ver que el observador aguas abajo estaba en el hilo de E / S antes y luego cambió al hilo principal. El código de la llave principal es:

  .observeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())

Entonces, cuando observeOn () se llama dos veces, el hilo del observador aguas abajo se cambiará dos veces.

Practica

Requisitos: en el caso de registro e inicio de sesión, debemos implementar la operación de inicio de sesión automático después de que el usuario se haya registrado correctamente.
Material:
  • Antecedentes: tomando el registro y el inicio de sesión del sitio web https://wanandroid.com/ como ejemplo, es necesario realizar la función de inicio de sesión automático después del registro
  • Interfaz:
public interface ApiService {
    /**
    * 注册
    * */

    @FormUrlEncoded
    @POST( "user/register")
    Observable<RegisterResp> register(@Field("username")String username, @Field("password")String password, @Field("repassword")String repassword);

    /**
     * 登录
     */
    @FormUrlEncoded
    @POST("user/login")
    Observable<LoginResponse> login(@Field("username") String name, @Field("password") String password);
}
Método de procesamiento original:
 //登录逻辑
 private void originLogin(){
       apiService.login(username, password)
               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())  //回到主线程去处理请求结果
               .subscribe(new Consumer<LoginResponse>() {
                   @Override
                   public void accept(LoginResponse loginResponse) throws Exception {
                       ToastUtil.showToast("登录成功");

                   }
               },new Consumer<Throwable>() {
                   @Override
                   public void accept(Throwable throwable) throws Exception {
                       ToastUtil.showToast("登录失败");
                   }
               });
   }
   
   // 注册后自动登录逻辑
   private void regisLogin(){
       apiService.register(username,password,repassword)
                  .subscribeOn(Schedulers.io()) //在IO线程进行网络请求
                  .observeOn(AndroidSchedulers.mainThread()) 
                  .subscribe(new Consumer<RegisterResp>() {
                      @Override
                      public void accept(RegisterResp registerResp) throws Exception {
                          LogUtil.d("registCode:"+registerResp.getErrorCode());
                          if (-1==registerResp.getErrorCode()){
                             ToastUtil.showToast("用户名已注册");
                          }else {
                              ToastUtil.showToast("注册成功。开始登录");
                              originLogin();
                          }
                      }
                  }, new Consumer<Throwable>() {
                      @Override
                      public void accept(Throwable throwable) throws Exception {
                          ToastUtil.showToast("注册失败");
                      }
                  });
   }

Se puede ver que antes de aprender la programación de subprocesos, necesitamos implementar el registro y el inicio de sesión por separado, y no consideramos la eficiencia de la ejecución. El procesamiento del código es muy engorroso. Hay que escribir dos métodos y procesar dos módulos. ¿Hay alguna ¿Cuál es la forma de optimizar el código anterior sin afectar el efecto? Observe el siguiente código:

Tratamiento actual (mejorado)
  //使用接口请求对象创建call对象
        apiService.register(username,password,repassword)
            .subscribeOn(Schedulers.io()) ////在IO线程进行注册和登录的网络请求
             .flatMap(new Function<RegisterResp, ObservableSource<LoginResponse>>() {
            @Override
            public ObservableSource<LoginResponse> apply(RegisterResp registerResp) throws Exception {
              if (-1==registerResp.getErrorCode()){
                  return Observable.error(new Throwable("用户名已经注册"));
              }else if ( -1001==registerResp.getErrorCode()){
                  return Observable.error(new Throwable("注册失败"));
              }

                return api.login(username, password);
            }
        }).observeOn(AndroidSchedulers.mainThread()) // 回到主线程处理
         .subscribe(new Observer<LoginResponse>() {
             @Override
             public void onSubscribe(Disposable d) {

             }

             @Override
             public void onNext(LoginResponse loginResponse) {
                 Toast.makeText(MainActivity.this, "恭喜你登录成功", Toast.LENGTH_SHORT).show();
             }

             @Override
             public void onError(Throwable e) {
                 if ("注册失败".equals(e.getMessage())){
                     Toast.makeText(MainActivity.this, "注册失败", Toast.LENGTH_SHORT).show();
                 }else if (("用户名已经注册".equals(e.getMessage()))){
                     Toast.makeText(MainActivity.this, "用户名已经注册", Toast.LENGTH_SHORT).show();
                     }
                 }

             @Override
             public void onComplete() {

             }
         });

Como puede ver en el código, primero procesaremos los resultados del registro en el hilo IO. Si el registro es exitoso, el hilo IO existente se usa directamente para realizar la solicitud de operación de inicio de sesión. Si el registro falla, el resultado se devuelve al hilo principal para su procesamiento. El código es conciso La lógica es simple.

Pasado

Aquí aprenderemos sobre la programación de subprocesos en Rxjava2, y continuaremos compartiendo el conocimiento relacionado más adelante. El siguiente artículo explicará los operadores en Rxjava2. Sí, sí, es similar a create (), flatMap (), etc. en el código anterior. Etc.

Publicado 8 artículos originales · Me gusta9 · Visita 6200

Supongo que te gusta

Origin blog.csdn.net/DolphKong/article/details/105688517
Recomendado
Clasificación