第一次写博客,如果写的不好希望大家理解。
在了解rxjava的多线程的,我们先来一个单线程下载网络图片并显示progress的。
先贴出代码:
@Override public void onClick(View v) { final ProgressDialog pd = new ProgressDialog(this); Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("http://img1.imgtn.bdimg.com/it/u=1225257463,1229468910&fm=21&gp=0.jpg"); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) .doOnSubscribe(new Action0() { @Override public void call() { pd.show(); } }) .subscribeOn(AndroidSchedulers.mainThread()) .map(new Func1<String, Bitmap>() { @Override public Bitmap call(String s) { return getImageBitmap(s); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Bitmap>() { @Override public void onCompleted() { if (pd.isShowing()) { pd.dismiss(); } } @Override public void onError(Throwable e) { if (pd.isShowing()) { pd.dismiss(); } } @Override public void onNext(Bitmap bitmap) { iv1.setImageBitmap(bitmap); } }); } private Bitmap getImageBitmap(String url){ URL imgUrl = null; Bitmap bitmap = null; try { imgUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imgUrl.openConnection(); conn.setDoInput(true); conn.connect(); InputStream is = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(is); is.close(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } return bitmap; }
上面代码其实不难理解,下面简单解释一下:
rxjava主要需要理解两个概念:观察者(Observer
)和被观察者(Observable
),RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。观察者和被观察者通过订阅(Subscribe)关系建立联系的。
我们看看以上的代码的异步是怎么实现的。答案是通过subscribeOn(Schedulers.io())这句话实现的。
Schedulers.io();是rxjava自己提供的线程调度器,用来读写文件、读写数据库、网络信息交互等。rxjava还
有
Schedulers.immediate();
Schedulers.newThread();
Schedulers.computation();等。对此我就不做过多的解释了。这里我
AndroidSchedulers.mainThread()这个是rxandroid提供的android的ui线程。特别提一下
也许有人会问为什么会有2个subscribeOn();其中第二是作用在doOnSubscribe()方法上的,让doOnSubscribe运
行在ui线程上。
Observable.doOnSubscribe()是在Subscribe发生后而且在事件发送前执行的,所以他是可以指定线程
的。
最后使用observeOn(AndroidSchelers.mainThread())指定观察者运行ui线程,所以我可以在onNext()中设置
ImageView的图片,在onError和onCompleted中隐藏progress。
好了,上面简单讲了一下一个线程下载图片,并在主线程设置图片了,我们来谈论下多线程并行运行下载图片,
并且将它在imageview显示出来。而且在图片都下载完了之后弹出一个土司告知用户。
先贴一种实现方式的代码:
private void moreThread() { final ProgressDialog pd = new ProgressDialog(this); Observable .just("http://img1.imgtn.bdimg.com/it/u=1225257463,1229468910&fm=21&gp=0.jpg") .map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(1, getImageBitmap(s)); return map; } }) .subscribeOn(Schedulers.io()) .mergeWith(Observable.just("http://pic1a.nipic.com/2008-11-26/200811268173650_2.jpg") .map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(2, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io())) .mergeWith(Observable .just("http://pic13.nipic.com/20110415/1347158_132411659346_2.jpg") .map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(3, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io())) .mergeWith(Observable .just("http://img4.3lian.com/sucai/img6/230/29.jpg") .map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(4, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io())) .mergeWith(Observable .just("http://img1.imgtn.bdimg.com/it/u=2493205512,407054761&fm=21&gp=0.jpg") .map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(5, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io())) .doOnSubscribe(new Action0() { @Override public void call() { pd.show(); } }) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Map<Integer, Bitmap>>() { @Override public void onCompleted() { if (pd.isShowing()) { pd.dismiss(); } Toast.makeText(SiyActivity.this,"5张图片下载完毕",0).show(); } @Override public void onError(Throwable e) { if (pd.isShowing()) { pd.dismiss(); } } @Override public void onNext(Map<Integer, Bitmap> integerBitmapMap) { Set<Integer> set = integerBitmapMap.keySet(); for (Integer key : set) { switch (key) { case 1: iv1.setImageBitmap(integerBitmapMap.get(1)); break; case 2: iv2.setImageBitmap(integerBitmapMap.get(2)); break; case 3: iv3.setImageBitmap(integerBitmapMap.get(3)); break; case 4: iv4.setImageBitmap(integerBitmapMap.get(4)); break; case 5: iv5.setImageBitmap(integerBitmapMap.get(5)); break; } } } }); }
代码比较长但是逻辑并不复杂。
下面我们慢慢看并解释。首先我们得搞明白同步下载5张图片需要5个observable,因为当使用了多个
subscribeOn()
的时候,只有第一个 subscribeOn()
起作用,所以我们不能在同一observable上多次指定被观察者的线
程。还有就是我们使用了3个操作符。just()可以简化我们observable的创建,map()
方法将参数中的 String
对象转换成一个 Bitmap
对象后回,mergeWith()
操作符,两个或更多同类型的 Observable 可以合并到一起去创建一个 Observable,最后指定合并后的Observable
的观察者在ui线程设置图片,弹出土司。
再给一种实现方式:
private void moreThread_2(){ final ProgressDialog pd = new ProgressDialog(SiyActivity.this); Single.merge(Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { singleSubscriber.onSuccess("http://img1.imgtn.bdimg.com/it/u=1225257463,1229468910&fm=21&gp=0.jpg"); } }).map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(1, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io()), Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { singleSubscriber.onSuccess("http://pic1a.nipic.com/2008-11-26/200811268173650_2.jpg"); } }).map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(2, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io()), Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { singleSubscriber.onSuccess("http://pic13.nipic.com/20110415/1347158_132411659346_2.jpg"); } }).map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(3, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io()), Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { singleSubscriber.onSuccess("http://img4.3lian.com/sucai/img6/230/29.jpg"); } }).map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(4, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io()), Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { singleSubscriber.onSuccess("http://img1.imgtn.bdimg.com/it/u=1225257463,1229468910&fm=21&gp=0.jpg"); } }).map(new Func1<String, Map<Integer, Bitmap>>() { @Override public Map<Integer, Bitmap> call(String s) { Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>(); map.put(5, getImageBitmap(s)); return map; } }).subscribeOn(Schedulers.io())) .doOnSubscribe(new Action0() { @Override public void call() { pd.show(); } }) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Map<Integer, Bitmap>>() { @Override public void onCompleted() { if (pd.isShowing()) { pd.dismiss(); } Toast.makeText(SiyActivity.this,"5张图片下载完毕",Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { if (pd.isShowing()) { pd.dismiss(); } } @Override public void onNext(Map<Integer, Bitmap> integerBitmapMap) { Set<Integer> set = integerBitmapMap.keySet(); for (Integer key : set) { switch (key) { case 1: iv1.setImageBitmap(integerBitmapMap.get(1)); break; case 2: iv2.setImageBitmap(integerBitmapMap.get(2)); break; case 3: iv3.setImageBitmap(integerBitmapMap.get(3)); break; case 4: iv4.setImageBitmap(integerBitmapMap.get(4)); break; case 5: iv5.setImageBitmap(integerBitmapMap.get(5)); break; } } } }); }
这种方法使用的是RxJava的Single 类实现的。主要思想和知识与上述方法相同,就不做解释了。
第一次写博客,水平有限,有不足之处,欢迎指出。