将具有多个参数的 AsyncTask 转换为 RxJava
Convert AsyncTask With Multiple Parameters to RxJava
我对 AsyncTask 进行了多次调用,我想将其转换为 RxJava。 AsyncTask 代码有效,但我只想探索如何在 RxJava 中执行此操作?
(顺便说一句,我知道标题很烂)
它的作用:
- 遍历 MyImageButton(这只是一个 POJO,没有扩展 ImageButton)列表
- 在每个 MyImageButton 上,获取其当前位图(通过 getDrawable())
- 从 URL 获取图标。
- 合并两个图像 BitmapUtils.combine(...);
- 将这个新组合的位图分配给 ImageButton
如何将其转换为 RxJava:
for (MyImageButton myImageButton: myImageButtons) {
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getImageButtonResId()); //getImageButtonResId holds a reference to some ImageButton
final Bitmap bitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
new BindImageTask(imageButton, bitmap, myImageButton.getIconUrl()).execute();
}
这是 BindImageTask:
private class BindImageTask extends AsyncTask<Void, Void, Bitmap> {
private WeakReference<Bitmap> srcBitmapWeakReference;
private WeakReference<ImageButton> imageButtonWeakReference;
private String dstIconUrl;
BindImageTask(ImageButton imageButton, Bitmap srcBitmap, String dstIconUrl) {
srcBitmapWeakReference = new WeakReference<>(srcBitmap);
imageButtonWeakReference = new WeakReference<>(imageButton);
this.dstIconUrl = dstIconUrl;
}
@Override
protected Bitmap doInBackground(Void... params) {
Bitmap srcBitmap = srcBitmapWeakReference.get();
if (srcBitmap == null) return null;
Bitmap dstBitmap = ImageLoader.getInstance().loadImageSync(dstIconUrl, new ImageSize(60, 60));
if (dstBitmap == null) {
return null;
}
return BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER);
}
@Override
protected void onPostExecute(Bitmap resultBitmap) {
super.onPostExecute(resultBitmap);
ImageButton imageButton = imageButtonWeakReference.get();
if (imageButton != null && resultBitmap != null) {
imageButton.setImageBitmap(resultBitmap);
}
}
}
现在我尝试在这上面使用 RxJava,但我产生了对 RxJava 的错误使用(它有效,但我知道有更好的方法):
Observable<MyImageButton> myImageButtonObservable = Observable.from(myImageButtons);
myImageButtonObservable
.map(new Func1<MyImageButton, MyImageButton>() {
@Override
public MyImageButton call(MyImageButton myImageButton) {
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getDialButtonResId());
final Bitmap srcBitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
final Bitmap dstBitmap = ImageLoader.getInstance().loadImageSync(myImageButton.getIcon(), new ImageSize(60, 60));
final Bitmap newBitmap = BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER);
ImageLoader.getInstance().getMemoryCache().put(myImageButton.getIconUrl() + "_compound", newBitmap);
return myImageButton;
}
})
.onErrorReturn(new Func1<Throwable, MyImageButton>() {
@Override
public MyImageButton call(Throwable throwable) {
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<MyImageButton>() {
@Override
public void call(MyImageButton myImageButton) {
if(myImageButton == null) {
return;
}
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getDialButtonResId());
imageButton.setImageBitmap(ImageLoader.getInstance().getMemoryCache().get(myImageButton.getIconUrl() + "_compound"));
}
});
我想要发生的是:
- 不必将新组合的图像保存到 ImageLoader 的缓存中。
- 在订阅回调中,我想引用这个 新位图 和 对 MyImageButton 的引用,这样我就可以做一个简单 myImageButton.setImageBitmap(newBitmap).
我不想要的:
- 要在 MyImageButton 中引用位图 class(因为我必须稍后对其进行序列化)。
第一种方式。使用助手 class Data
创建 class Data.java
:
public static class Data{
private ImageButton imageButton;
private Bitmap srcBitmap;
private Bitmap dstBitmap;
private Bitmap combinedBitmap;
private String dstIconUrl;
public Data(ImageButton imageButton, String iconUrl) {
this.imageButton = imageButton;
srcBitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
dstIconUrl = iconUrl;
}
public ImageButton getImageButton() {
return imageButton;
}
public Bitmap getSrcBitmap() {
return srcBitmap;
}
public Bitmap getDstBitmap(){
return dstBitmap;
}
public String getDstIconUrl() {
return dstIconUrl;
}
public Bitmap getCombinedBitmap(){
return combinedBitmap;
}
public Data withImageButton(ImageButton btn){
this.imageButton = btn;
return this;
}
public Data withSrcBitmap(Bitmap bitmap){
this.srcBitmap = bitmap;
return this;
}
public Data withIconUrl(String url){
this.dstIconUrl = url;
return this;
}
public Data withDstBitmap(Bitmap bitmap){
this.dstBitmap = bitmap;
return this;
}
public Data withCombinedBitmap(Bitmap bitmap){
this.combinedBitmap = bitmap;
return this;
}
}
使用 class Data
:
处理您的按钮
Observable.from(myImageButtons)
.map(new Func1<MyImageButton, Data>() {
@Override
public Data call(MyImageButton myImageButton) {
return new Data(myImageButton, myImageButton.getIconUrl());
}
})
.map(new Func1<Data, Data>() {
@Override
public Data call(Data data) {
return data.withDstBitmap(ImageLoader.getInstance().loadImageSync(data.getDstIconUrl(), new ImageSize(60, 60)));
}
})
.filter(new Func1<Data, Boolean>() {
@Override
public Boolean call(Data data) {
return data.getDstBitmap() != null;
}
})
.map(new Func1<Data, Data>() {
@Override
public Data call(Data data) {
return data.withCombinedBitmap(BitmapUtils.combineImage(data.getSrcBitmap(), data.getDstBitmap(), PorterDuff.Mode.DST_OVER));
}
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<Data>() {
@Override
public void call(Data data) { //onNext
data.getImageButton().setImageBitmap(data.getCombinedBitmap());
//I recomend you to recycle old bitmaps if they no needed
data.getSrcBitmap().recycle();
data.getDstBitmap().recycle();
data.withSrcBitmap(null).withDstBitmap(null);
//Complex way to remove this bitmaps from cache
//See
//MemoryCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getMemoryCache());
//DiscCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getDiscCache());
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) { //onError
throwable.printStackTrace();
}
},
new Action0() {
@Override
public void call() {
//Simple way to clear ImageLoaderCache
ImageLoader.getInstance().clearMemoryCache();
}
}
);
或使用 Lambda 表达式:
Observable.from(myImageButtons)
.map(myImageButton -> new Data(myImageButton, myImageButton.getIconUrl()))
.map(data -> data.withDstBitmap(ImageLoader.getInstance().loadImageSync(data.getDstIconUrl(), new ImageSize(60, 60))))
.filter(data -> data.getDstBitmap() != null)
.map(data -> data.withCombinedBitmap(BitmapUtils.combineImage(data.getSrcBitmap(), data.getDstBitmap(), PorterDuff.Mode.DST_OVER)))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
data -> { //onNext
data.getImageButton().setImageBitmap(data.getCombinedBitmap());
//I recomend you to recycle old bitmaps if they no needed
data.getSrcBitmap().recycle();
data.getDstBitmap().recycle();
data.withSrcBitmap(null).withDstBitmap(null);
//Complex way to remove this bitmaps from cache
//See
//MemoryCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getMemoryCache());
//DiscCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getDiscCache());
},
throwable -> { //onError
throwable.printStackTrace();
},
() -> {
//Simple way to clear ImageLoaderCache
ImageLoader.getInstance().clearMemoryCache();
}
);
第二种方式。更具反应性...
创建 DST 位图 Observable
:
public Observable<Bitmap> getDstIconsFromImageButtonsByIconUrls(){
return Observable.from(myImageButtons)
.map(new Func1<MyImageButton, String>() {
@Override
public String call(MyImageButton myImageButton) {
return myImageButton.getIconUrl();
}
})
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String s) {
return ImageLoader.getInstance().loadImageSync(url, new ImageSize(60, 60));
}
});
}
或 Lambdas
:
public Observable<Bitmap> getDstIconsFromImageButtonsByIconUrls(){
return Observable.from(myImageButtons)
.map(myImageButton -> myImageButton.getIconUrl())
.map(s -> ImageLoader.getInstance().loadImageSync(url, new ImageSize(60, 60)));
}
创建 SRC 位图 Observable
:
public Observable<Bitmap> getSrcIcons(){
return Observable.from(myImageButtons)
.map(new Func1<MyImageButton, Bitmap>() {
@Override
public Bitmap call(MyImageButton myImageButton) {
return ((BitmapDrawable) myImageButton.getDrawable()).getBitmap();
}
});
}
或 Lambdas
:
public Observable<Bitmap> getSrcIcons(){
return Observable.from(myImageButtons)
.map(myImageButton -> ((BitmapDrawable) myImageButton.getDrawable()).getBitmap());
}
使用运算符zip( )
link:
Observable
.zip(
Observable.from(myImageButtons),
getDstIconsFromImageButtonsByIconUrls(),
getSrcIcons(),
new Func3<MyImageButton, Bitmap, Bitmap, MyImageButton>() {
@Override
public MyImageButton call(MyImageButton btn, Bitmap dstBitmap, Bitmap srcBitmap) {
if(dstBitmap != null){
btn.setImageBitmap(BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER));
//recycle bitmaps if you don't need them
dstBitmap.recycle();
srcBitmap.recycle();
}
return btn;
}
})
.subscribe(
new Action1<MyImageButton>() {
@Override
public void call(MyImageButton myImageButton) {
//do nothing
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
},
new Action0() {
@Override
public void call() {
ImageLoader.getInstance().clearMemoryCache();
}
});
或使用Lambdas
:
Observable
.zip(
Observable.from(myImageButtons),
getDstIconsFromImageButtonsByIconUrls(),
getSrcIcons(),
(btn, dstBitmap, srcBitmap) -> {
if(dstBitmap != null){
btn.setImageBitmap(BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER));
//recycle bitmaps if you don't need them
dstBitmap.recycle();
srcBitmap.recycle();
}
return btn;
})
.subscribe(
myImageButton -> {
//do nothing
},
throwable -> throwable.printStackTrace(),
() -> ImageLoader.getInstance().clearMemoryCache());
P.S.
我没有测试这个示例,但它们应该可以工作。如果您有任何问题,请告诉我。
我对 AsyncTask 进行了多次调用,我想将其转换为 RxJava。 AsyncTask 代码有效,但我只想探索如何在 RxJava 中执行此操作?
(顺便说一句,我知道标题很烂)
它的作用:
- 遍历 MyImageButton(这只是一个 POJO,没有扩展 ImageButton)列表
- 在每个 MyImageButton 上,获取其当前位图(通过 getDrawable())
- 从 URL 获取图标。
- 合并两个图像 BitmapUtils.combine(...);
- 将这个新组合的位图分配给 ImageButton
如何将其转换为 RxJava:
for (MyImageButton myImageButton: myImageButtons) {
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getImageButtonResId()); //getImageButtonResId holds a reference to some ImageButton
final Bitmap bitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
new BindImageTask(imageButton, bitmap, myImageButton.getIconUrl()).execute();
}
这是 BindImageTask:
private class BindImageTask extends AsyncTask<Void, Void, Bitmap> {
private WeakReference<Bitmap> srcBitmapWeakReference;
private WeakReference<ImageButton> imageButtonWeakReference;
private String dstIconUrl;
BindImageTask(ImageButton imageButton, Bitmap srcBitmap, String dstIconUrl) {
srcBitmapWeakReference = new WeakReference<>(srcBitmap);
imageButtonWeakReference = new WeakReference<>(imageButton);
this.dstIconUrl = dstIconUrl;
}
@Override
protected Bitmap doInBackground(Void... params) {
Bitmap srcBitmap = srcBitmapWeakReference.get();
if (srcBitmap == null) return null;
Bitmap dstBitmap = ImageLoader.getInstance().loadImageSync(dstIconUrl, new ImageSize(60, 60));
if (dstBitmap == null) {
return null;
}
return BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER);
}
@Override
protected void onPostExecute(Bitmap resultBitmap) {
super.onPostExecute(resultBitmap);
ImageButton imageButton = imageButtonWeakReference.get();
if (imageButton != null && resultBitmap != null) {
imageButton.setImageBitmap(resultBitmap);
}
}
}
现在我尝试在这上面使用 RxJava,但我产生了对 RxJava 的错误使用(它有效,但我知道有更好的方法):
Observable<MyImageButton> myImageButtonObservable = Observable.from(myImageButtons);
myImageButtonObservable
.map(new Func1<MyImageButton, MyImageButton>() {
@Override
public MyImageButton call(MyImageButton myImageButton) {
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getDialButtonResId());
final Bitmap srcBitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
final Bitmap dstBitmap = ImageLoader.getInstance().loadImageSync(myImageButton.getIcon(), new ImageSize(60, 60));
final Bitmap newBitmap = BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER);
ImageLoader.getInstance().getMemoryCache().put(myImageButton.getIconUrl() + "_compound", newBitmap);
return myImageButton;
}
})
.onErrorReturn(new Func1<Throwable, MyImageButton>() {
@Override
public MyImageButton call(Throwable throwable) {
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<MyImageButton>() {
@Override
public void call(MyImageButton myImageButton) {
if(myImageButton == null) {
return;
}
final ImageButton imageButton = (ImageButton) findViewById(myImageButton.getDialButtonResId());
imageButton.setImageBitmap(ImageLoader.getInstance().getMemoryCache().get(myImageButton.getIconUrl() + "_compound"));
}
});
我想要发生的是:
- 不必将新组合的图像保存到 ImageLoader 的缓存中。
- 在订阅回调中,我想引用这个 新位图 和 对 MyImageButton 的引用,这样我就可以做一个简单 myImageButton.setImageBitmap(newBitmap).
我不想要的:
- 要在 MyImageButton 中引用位图 class(因为我必须稍后对其进行序列化)。
第一种方式。使用助手 class Data
创建 class Data.java
:
public static class Data{
private ImageButton imageButton;
private Bitmap srcBitmap;
private Bitmap dstBitmap;
private Bitmap combinedBitmap;
private String dstIconUrl;
public Data(ImageButton imageButton, String iconUrl) {
this.imageButton = imageButton;
srcBitmap = ((BitmapDrawable) imageButton.getDrawable()).getBitmap();
dstIconUrl = iconUrl;
}
public ImageButton getImageButton() {
return imageButton;
}
public Bitmap getSrcBitmap() {
return srcBitmap;
}
public Bitmap getDstBitmap(){
return dstBitmap;
}
public String getDstIconUrl() {
return dstIconUrl;
}
public Bitmap getCombinedBitmap(){
return combinedBitmap;
}
public Data withImageButton(ImageButton btn){
this.imageButton = btn;
return this;
}
public Data withSrcBitmap(Bitmap bitmap){
this.srcBitmap = bitmap;
return this;
}
public Data withIconUrl(String url){
this.dstIconUrl = url;
return this;
}
public Data withDstBitmap(Bitmap bitmap){
this.dstBitmap = bitmap;
return this;
}
public Data withCombinedBitmap(Bitmap bitmap){
this.combinedBitmap = bitmap;
return this;
}
}
使用 class Data
:
Observable.from(myImageButtons)
.map(new Func1<MyImageButton, Data>() {
@Override
public Data call(MyImageButton myImageButton) {
return new Data(myImageButton, myImageButton.getIconUrl());
}
})
.map(new Func1<Data, Data>() {
@Override
public Data call(Data data) {
return data.withDstBitmap(ImageLoader.getInstance().loadImageSync(data.getDstIconUrl(), new ImageSize(60, 60)));
}
})
.filter(new Func1<Data, Boolean>() {
@Override
public Boolean call(Data data) {
return data.getDstBitmap() != null;
}
})
.map(new Func1<Data, Data>() {
@Override
public Data call(Data data) {
return data.withCombinedBitmap(BitmapUtils.combineImage(data.getSrcBitmap(), data.getDstBitmap(), PorterDuff.Mode.DST_OVER));
}
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<Data>() {
@Override
public void call(Data data) { //onNext
data.getImageButton().setImageBitmap(data.getCombinedBitmap());
//I recomend you to recycle old bitmaps if they no needed
data.getSrcBitmap().recycle();
data.getDstBitmap().recycle();
data.withSrcBitmap(null).withDstBitmap(null);
//Complex way to remove this bitmaps from cache
//See
//MemoryCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getMemoryCache());
//DiscCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getDiscCache());
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) { //onError
throwable.printStackTrace();
}
},
new Action0() {
@Override
public void call() {
//Simple way to clear ImageLoaderCache
ImageLoader.getInstance().clearMemoryCache();
}
}
);
或使用 Lambda 表达式:
Observable.from(myImageButtons)
.map(myImageButton -> new Data(myImageButton, myImageButton.getIconUrl()))
.map(data -> data.withDstBitmap(ImageLoader.getInstance().loadImageSync(data.getDstIconUrl(), new ImageSize(60, 60))))
.filter(data -> data.getDstBitmap() != null)
.map(data -> data.withCombinedBitmap(BitmapUtils.combineImage(data.getSrcBitmap(), data.getDstBitmap(), PorterDuff.Mode.DST_OVER)))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
data -> { //onNext
data.getImageButton().setImageBitmap(data.getCombinedBitmap());
//I recomend you to recycle old bitmaps if they no needed
data.getSrcBitmap().recycle();
data.getDstBitmap().recycle();
data.withSrcBitmap(null).withDstBitmap(null);
//Complex way to remove this bitmaps from cache
//See
//MemoryCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getMemoryCache());
//DiscCacheUtils.removeFromCache(data.getDstBitmap(), ImageLoader.getInstance().getDiscCache());
},
throwable -> { //onError
throwable.printStackTrace();
},
() -> {
//Simple way to clear ImageLoaderCache
ImageLoader.getInstance().clearMemoryCache();
}
);
第二种方式。更具反应性...
创建 DST 位图 Observable
:
public Observable<Bitmap> getDstIconsFromImageButtonsByIconUrls(){
return Observable.from(myImageButtons)
.map(new Func1<MyImageButton, String>() {
@Override
public String call(MyImageButton myImageButton) {
return myImageButton.getIconUrl();
}
})
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String s) {
return ImageLoader.getInstance().loadImageSync(url, new ImageSize(60, 60));
}
});
}
或 Lambdas
:
public Observable<Bitmap> getDstIconsFromImageButtonsByIconUrls(){
return Observable.from(myImageButtons)
.map(myImageButton -> myImageButton.getIconUrl())
.map(s -> ImageLoader.getInstance().loadImageSync(url, new ImageSize(60, 60)));
}
创建 SRC 位图 Observable
:
public Observable<Bitmap> getSrcIcons(){
return Observable.from(myImageButtons)
.map(new Func1<MyImageButton, Bitmap>() {
@Override
public Bitmap call(MyImageButton myImageButton) {
return ((BitmapDrawable) myImageButton.getDrawable()).getBitmap();
}
});
}
或 Lambdas
:
public Observable<Bitmap> getSrcIcons(){
return Observable.from(myImageButtons)
.map(myImageButton -> ((BitmapDrawable) myImageButton.getDrawable()).getBitmap());
}
使用运算符zip( )
link:
Observable
.zip(
Observable.from(myImageButtons),
getDstIconsFromImageButtonsByIconUrls(),
getSrcIcons(),
new Func3<MyImageButton, Bitmap, Bitmap, MyImageButton>() {
@Override
public MyImageButton call(MyImageButton btn, Bitmap dstBitmap, Bitmap srcBitmap) {
if(dstBitmap != null){
btn.setImageBitmap(BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER));
//recycle bitmaps if you don't need them
dstBitmap.recycle();
srcBitmap.recycle();
}
return btn;
}
})
.subscribe(
new Action1<MyImageButton>() {
@Override
public void call(MyImageButton myImageButton) {
//do nothing
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
},
new Action0() {
@Override
public void call() {
ImageLoader.getInstance().clearMemoryCache();
}
});
或使用Lambdas
:
Observable
.zip(
Observable.from(myImageButtons),
getDstIconsFromImageButtonsByIconUrls(),
getSrcIcons(),
(btn, dstBitmap, srcBitmap) -> {
if(dstBitmap != null){
btn.setImageBitmap(BitmapUtils.combineImage(srcBitmap, dstBitmap, PorterDuff.Mode.DST_OVER));
//recycle bitmaps if you don't need them
dstBitmap.recycle();
srcBitmap.recycle();
}
return btn;
})
.subscribe(
myImageButton -> {
//do nothing
},
throwable -> throwable.printStackTrace(),
() -> ImageLoader.getInstance().clearMemoryCache());
P.S.
我没有测试这个示例,但它们应该可以工作。如果您有任何问题,请告诉我。