Android+Rxjava3入门小例子--读取图片并显示

第三次学习Rxjava了,记点什么吧。。。

为什么要学习这个东东呢?

经常碰到与安卓系统交互的外部设备是应答式的,就是你一步步的问它,它一步步的回答,例如某厂商的指纹仪进行指纹比对操作,需要的步骤如下:

打开设备-下载指纹特征码到缓冲区A-采集指纹到缓冲区B(循环等待)-再次采集-合成特征码-与缓冲区A对比

类似这样的需要一步步推进的业务流程,通常的做法是异步回调、或者消息订阅,能用是能用,但是怎么说呢?它有点混乱:回调-回调-回调~~,或者:消息-消息-消息~~,半个月后发现之前写的代码阅读起来有点困难,跳来跳去的。

听说rxjava特点是基于事件流、异步,既然有这样的好东西了就学一下吧,可是看next(1);next(2);next(3);这样的例子,完全不得门而入。

本文将完成一个小例子有三个部分,第一个是从网络上下载一个图片,然后展示出来;第二个增加了一个步骤,在下载完毕后添加水印,然后再展示出来;第三个是异常处理。

先看第一个部分:下载图片并展示。

1,由于用到了网络,需要在项目的AndroidManifest.xml文件中添加权限

<uses-permission android:name="android.permission.INTERNET" />

2,布局,仅有一个图像控件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

3,主界面Activity


import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

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

    private static final String PATH = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";

    private void testNetIo() {
        Observable.just(PATH).map(new Function<String, Bitmap>() {
                    @Override
                    public Bitmap apply(String s) throws Throwable {
                        URL url = new URL(s);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        int respCode = conn.getResponseCode();
                        if (respCode == HttpURLConnection.HTTP_OK) {
                            InputStream inputStream = conn.getInputStream();
                            return BitmapFactory.decodeStream(inputStream);
                        }
                        Log.d(TAG, "反馈其它:" + respCode);
                        return null;
                    }
                }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        showProgressDialog();
                    }

                    @Override
                    public void onNext(@NonNull Bitmap bitmap) {
                        if(bitmap == null){
                            Log.e(TAG, "onNext反馈null");
                            return;
                        }

                        ((ImageView) MainActivity.this.findViewById(R.id.imageView1)).setImageBitmap(bitmap);
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d(TAG, "------onError----------" + e);
                    }

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

    private ProgressDialog progressDialog;

    public void showProgressDialog() {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(this);
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(false);
        }
        progressDialog.setMessage("your message");
        progressDialog.show();
    }

    public void dismissProgressDialog() {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
    }
}

代码里使用了已经被抛弃的对话框方法,也没有优化代码,不要去管他,就是简单方便的表达用法就好了。

这样一个简单的例子就完成了,我也不懂为什么要just、为什么要map,就先这样写吧,到目前为止,它能够表达出来的流程性的特点并不明显,接下来增加一个添加水印的步骤,加强一下“流程”、“步骤”。

只需要在map方法的后面,再加一个map方法即可,像这样:

        Observable.just(PATH).map(new Function<String, Bitmap>() {
                    @Override
                    public Bitmap apply(String s) throws Throwable {
                        URL url = new URL(s);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        int respCode = conn.getResponseCode();
                        if (respCode == HttpURLConnection.HTTP_OK) {
                            InputStream inputStream = conn.getInputStream();
                            return BitmapFactory.decodeStream(inputStream);
                        }
                        Log.d(TAG, "反馈其它:" + respCode);
                        return null;
                    }
                })
                .map(new Function<Bitmap, Bitmap>() {//新添加的map方法
                    @Override
                    public Bitmap apply(Bitmap bitmap) throws Throwable {
                        return waterMarkCover(bitmap, "rxjava入门");
                    }
                })

看吧,要加一个步骤只要写一段map即可。

新添加的水印方法也是网上抄抄的,如下:

    private Bitmap waterMarkCover(Bitmap bitmap, String text) {
        if (bitmap == null) return null;
        Bitmap newImage = bitmap.copy(bitmap.getConfig(), true);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Canvas canvas = new Canvas(newImage);
        paint.setColor(Color.RED);
        paint.setTextSize(100);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        canvas.drawText(text, 0, bounds.height(), paint);//bounds.height()是文字高度,你把它换成0试试就知道为什么要用文字高度了
        bitmap.recycle();
        return newImage;
    }

做好这两步基本上可以用上了,再加上异常处理,基本上算入门吧:在两个map之后,加上异常、重试。

                .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Throwable {
                        return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                            @Override
                            public ObservableSource<?> apply(Throwable throwable) throws Throwable {
                                Log.d(TAG, "发生异常:" + throwable);
                                if (throwable instanceof NullPointerException) {
                                    Log.d(TAG, "获取内容失败");
                                } else if (throwable instanceof IOException) {
                                    Log.d(TAG, "请求失败");
                                    tryCount++;
                                    if (tryCount < 3) {
                                        Log.d(TAG, "未满次数,再次请求" + tryCount);
                                        return Observable.just(1).delay(3, TimeUnit.SECONDS);
                                    }
                                }
                                Log.d(TAG, "失败了");
                                return null;
                            }
                        });
                    }
                })

当然,出现异常不能直接打个日志就完事,可以顶一个反馈对象用来承载出错信息,我这里直接用null了。

完整的代码如下:


public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

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

    private static final String PATH = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";

    private int tryCount = 0;

    private void testNetIo() {
        Observable<String> obs = Observable.just(PATH);
        //Observable.just(PATH)
        obs.map(new Function<String, Bitmap>() {
                    @Override
                    public Bitmap apply(String s) throws Throwable {
                        Log.d(TAG, "-----apply-----------");
                        URL url = new URL(s);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        int respCode = conn.getResponseCode();
                        if (respCode == HttpURLConnection.HTTP_OK) {
                            InputStream inputStream = conn.getInputStream();
                            return BitmapFactory.decodeStream(inputStream);
                        }
                        Log.d(TAG, "反馈其它:" + respCode);
                        return null;
                    }
                })
                .map(new Function<Bitmap, Bitmap>() {
                    @Override
                    public Bitmap apply(Bitmap bitmap) throws Throwable {
                        Log.d(TAG, "-----apply---2--------");
                        return waterMarkCover(bitmap, "rxjava入门");
                    }
                })
                .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Throwable {
                        return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                            @Override
                            public ObservableSource<?> apply(Throwable throwable) throws Throwable {
                                Log.d(TAG, "发生异常:" + throwable);
                                if (throwable instanceof NullPointerException) {
                                    Log.d(TAG, "获取内容失败");
                                } else if (throwable instanceof IOException) {
                                    Log.d(TAG, "请求失败");
                                    tryCount++;
                                    if (tryCount < 3) {
                                        Log.d(TAG, "未满次数,再次请求" + tryCount);
                                        return Observable.just(1).delay(3, TimeUnit.SECONDS);
                                    }
                                }
                                Log.d(TAG, "失败了");
                                return null;
                            }
                        });
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d(TAG, "-----onSubscribe-----------");
                        showProgressDialog();
                    }

                    @Override
                    public void onNext(@NonNull Bitmap bitmap) {
                        Log.d(TAG, "-----onNext-----------");
                        if (bitmap == null) {
                            Log.e(TAG, "onNext反馈null");
                            return;
                        }
                        ((ImageView) MainActivity.this.findViewById(R.id.imageView1)).setImageBitmap(bitmap);
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d(TAG, "------onError----------" + e);
                        dismissProgressDialog();

                    }

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

    private Bitmap waterMarkCover(Bitmap bitmap, String text) {
        if (bitmap == null) return null;
        Bitmap newImage = bitmap.copy(bitmap.getConfig(), true);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Canvas canvas = new Canvas(newImage);
        paint.setColor(Color.RED);
        //paint.setTextSize(100);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        canvas.drawText(text, 0, bounds.height(), paint);//bounds.height()是文字高度,你把它换成0试试就知道为什么要用文字高度了
        bitmap.recycle();
        return newImage;
    }

    private ProgressDialog progressDialog;

    public void showProgressDialog() {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(this);
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(false);
        }
        progressDialog.setMessage("your message");
        progressDialog.show();
    }

    public void dismissProgressDialog() {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
    }

    public void doTest1(View view) {
        testNetIo();
    }

    public void doTest2(View view) {
        //Observable.fromArray()
    }
}

rxjava的知识点太多了,边学边用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值