Android 将具有多个参数的AsyncTask转换为RxJava

Android 将具有多个参数的AsyncTask转换为RxJava,android,android-asynctask,rx-java,rx-android,Android,Android Asynctask,Rx Java,Rx Android,我有多个对AsyncTask的调用,我想将其转换为RxJava。AsyncTask代码可以工作,但我只想探索如何在RxJava中实现这一点 顺便说一句,我知道这个标题很烂 它的作用是: 循环使用MyImageButton,它只是一个POJO,而不是扩展ImageButton列表 在每个MyImageButton上,通过getDrawable获取其当前位图 从URL获取图标。 在合并两个图像BitmapUtils.combine。。。; 将此新组合的位图指定给ImageButton 如何将其转换为

我有多个对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的缓存中。 在subscribe回调中,我希望同时引用这个新位图和MyImageButton,这样我就可以执行一个简单的MyImageButton.setImageBitmapnewBitmap。 我不想要的是:

在MyImageButton类中有一个位图引用,因为我以后必须序列化它。 第一条路。使用助手类数据 创建class Data.java:

使用类数据处理您的按钮:

第二条路。更具反应性。。。 创建可观察的DST位图:

创建可观察的SRC位图:

使用运算符zip:

附言

我没有测试这个例子,但它们应该是有效的。如果您有任何问题,请告诉我。

第一条路。使用助手类数据 创建class Data.java:

使用类数据处理您的按钮:

第二条路。更具反应性。。。 创建可观察的DST位图:

创建可观察的SRC位图:

使用运算符zip:

附言


我没有测试这个例子,但它们应该是有效的。如果您有任何问题,请告诉我。

太棒了,谢谢!您的第一个解决方案就是我试图实现的。第二种解决方案对我来说是非常新的,但我会尝试一下,只是为了得到更多的RxJava实践。接受答案太棒了,谢谢!您的第一个解决方案就是我试图实现的。第二种解决方案对我来说是非常新的,但我会尝试一下,只是为了得到更多的RxJava实践。接受答案
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;
    }
}
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 http://stackoverflow.com/a/19512974/1796309
                        //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();
                    }
                }
        );
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 http://stackoverflow.com/a/19512974/1796309
                    //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();
                }
        );
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));
                }
            });
}
public Observable<Bitmap> getDstIconsFromImageButtonsByIconUrls(){
    return Observable.from(myImageButtons)
            .map(myImageButton -> myImageButton.getIconUrl())
            .map(s -> ImageLoader.getInstance().loadImageSync(url, new ImageSize(60, 60)));
}
public Observable<Bitmap> getSrcIcons(){
    return Observable.from(myImageButtons)
            .map(new Func1<MyImageButton, Bitmap>() {
                @Override
                public Bitmap call(MyImageButton myImageButton) {
                    return ((BitmapDrawable) myImageButton.getDrawable()).getBitmap();
                }
            });
}
public Observable<Bitmap> getSrcIcons(){
    return Observable.from(myImageButtons)
            .map(myImageButton -> ((BitmapDrawable) myImageButton.getDrawable()).getBitmap());
}
    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();
                }
            });
    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());