Java 使用 Glide 将位图加载到 ImageView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31867322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:42:23  来源:igfitidea点击:

Using Glide to load bitmap into ImageView

javaandroidbitmapandroid-bitmapandroid-glide

提问by user3296088

How can i use Glide library to load Bitmap into my ImageView? I want to create a custom image with textand load it into imageview using Glide.

如何使用 Glide 库将 Bitmap 加载到我的 ImageView 中?我想创建一个带有文本的自定义图像,并使用 Glide 将其加载到 imageview 中。

This is my method to create custom bitmap with text

这是我用文本创建自定义位图的方法

public Bitmap imageWithText(String text) {
    TextView tv = new TextView(context);
    tv.setText(text);
    tv.setTextColor(Color.WHITE);
    tv.setBackgroundColor(Color.BLACK);
    tv.setTypeface(null, Typeface.BOLD);
    tv.setGravity(Gravity.CENTER);
    tv.setTextSize(20);
    tv.setPadding(0, 25, 0, 0);
    Bitmap testB = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(testB);
    tv.layout(0, 0, 100, 100);
    tv.draw(c);
    return testB;
}

But when i try to load this bitmap using glide i'm getting error

但是当我尝试使用 glide 加载这个位图时,我收到错误

Glide.with(getContext()).load(imageWithText("Random text")).into(holder.imgPhoto);

采纳答案by TWiStErRob

@rookiedev is right, there's no load(Bitmap)in Glide, for a reason: acquiring a Bitmapusually takes time and sometimes blocking I/O. So it's not good practice to call imageWithTexton the UI thread. Update: That being said I proposed this featurea while back; and while the hacks are easier to do you can find the "Glide way" below, which I highly recommend.

@rookiedev 是对的,load(Bitmap)在 Glide 中没有,原因是:获取 aBitmap通常需要时间,有时会阻塞 I/O。所以调用imageWithTextUI 线程不是一个好习惯。更新:话虽如此,我不久前提出了这个功能;虽然黑客更容易做到,但您可以在下面找到我强烈推荐的“滑行方式”。

Glide is designed to be flexible and this problem demonstrates that trait extremely well. The following implementation may seem long, but all pieces have their reason for existence. Given the performance gain, this amount of code to fit your generator into Glide's world is not much. I tried to format it to be short, collapsing irrelevant parts and using static imports to be shorter (see the end for imports).

Glide 被设计为灵活的,这个问题非常好地展示了这个特性。下面的实现可能看起来很长,但所有的部分都有存在的理由。考虑到性能提升,让您的生成器适应 Glide 世界的代码量并不多。我试图将其格式化为较短的格式,折叠不相关的部分并使用静态导入来缩短(请参阅导入的结尾)。

The code also includes programmatically generated UI so you can just copy-paste all the below code into GlideGeneratedImageListFragment.javaand run it; the only external dependency is support lib's RecyclerView.

该代码还包括以编程方式生成的 UI,因此您只需将以下所有代码复制粘贴到其中GlideGeneratedImageListFragment.java并运行即可;唯一的外部依赖是支持 lib 的RecyclerView.

class GeneratingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // See https://docs.google.com/drawings/d/1KyOJkNd5Dlm8_awZpftzW7KtqgNR6GURvuF6RfB210g/edit?usp=sharing
    //                                  ModelType/A,    DataType/T,     ResourceType/Z, TranscodeType/R
    private final GenericRequestBuilder<GenerateParams, GenerateParams, Bitmap,         GlideDrawable> generator;

    public GeneratingAdapter(final Context context) {
        generator = Glide // this part should be cleaner in Glide 4.0, but that's not released yet
        .with(context)
        .using(new GenerateParamsPassthroughModelLoader(), GenerateParams.class)          // custom class
        .from(GenerateParams.class)
        .as(Bitmap.class)
        .transcode(new BitmapToGlideDrawableTranscoder(context), GlideDrawable.class)     // builtin
        .decoder(new GenerateParamsBitmapResourceDecoder(context))                        // custom class
        .encoder(new BitmapEncoder(Bitmap.CompressFormat.PNG, 0/*ignored for lossless*/)) // builtin
        .cacheDecoder(new FileToStreamDecoder<Bitmap>(new StreamBitmapDecoder(context)))  // builtin
        //.placeholder(new ColorDrawable(Color.YELLOW)) // you can pre-set placeholder and error
        .error(new ColorDrawable(Color.RED))            // so it's easier when binding
        //.diskCacheStrategy(DiskCacheStrategy.NONE)    // only for debugging to always regenerate
        //.skipMemoryCache(true)                        // only for debugging to always regenerate
        ;
    }
    @Override public int getItemCount() { return 1000; }

    private final float[] colorCache = new float[] {0, 1.0f, 0.5f};
    private final float[] bgCache = new float[] {0, 0.5f, 1.0f};
    @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        colorCache[0] = bgCache[0] = (position * 15) % 360; // just to have a fancy example :)
        GenerateParams params = new GenerateParams(
                // omit position to see Glide caching in action (every 24th item / 12th row is the same)
                "android text"/* + " #" + position*/,
                Color.HSVToColor(colorCache),
                Color.HSVToColor(bgCache)
        );
        generator/*.clone() in case you see weird behavior*/.load(params).into((ImageView)holder.itemView);
    }

    @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        int height = parent.getContext().getResources().getDisplayMetrics().heightPixels / 3;
        ImageView view = new ImageView(parent.getContext());
        view.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, height));
        view.setScaleType(ImageView.ScaleType.FIT_CENTER);
        return new RecyclerView.ViewHolder(view) {}; // anon class for brevity
    }
}

public class GlideGeneratedImageListFragment extends Fragment {
    @Override public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        RecyclerView view = new RecyclerView(container.getContext());
        view.setLayoutParams(new MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        view.setLayoutManager(new GridLayoutManager(container.getContext(), 2 /*columns*/));
        view.setAdapter(new GeneratingAdapter(view.getContext()));
        return view;
    }
}

/** Extracted params from imageWithText, but left some hardcoded values like 20sp/bold/center in {@link Generators}. */
class GenerateParams {
    final String text;
    final int color;
    final int background;

    public GenerateParams(String text, int color, int bg) {
        this.text = text;
        this.color = color;
        this.background = bg;
    }

    public String getId() {
        // TODO make sure it's unique for every possible instance of GenerateParams
        // because it will affect how the resulting bitmap is cached
        // the below is correct correct for the current fields, if those change this has to change
        return String.format(Locale.ROOT, "%s-%08x-%08x", text, color, background);
    }
}

/** Boilerplate because of the degeneration in ModelType == DataType, but important for caching.
 *  @see GeneratingAdapter#generator */
class GenerateParamsPassthroughModelLoader implements ModelLoader<GenerateParams, GenerateParams> {
    @Override public DataFetcher<GenerateParams> getResourceFetcher(final GenerateParams model, int width, int height) {
        return new DataFetcher<GenerateParams>() {
            @Override public GenerateParams loadData(Priority priority) throws Exception { return model; }
            @Override public void cleanup() { }
            @Override public String getId() { return model.getId(); }
            @Override public void cancel() { }
        };
    }
}

/** Handles pooling to reduce/prevent GC lagging from too many {@link Bitmap#createBitmap}s */
class GenerateParamsBitmapResourceDecoder implements ResourceDecoder<GenerateParams, Bitmap> {
    private final Context context;
    public GenerateParamsBitmapResourceDecoder(Context context) { this.context = context; }
    @Override public Resource<Bitmap> decode(GenerateParams source, int width, int height) throws IOException {
        BitmapPool pool = Glide.get(context).getBitmapPool();
        Bitmap bitmap = pool.getDirty(width, height, Bitmap.Config.ARGB_8888);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }
        Generators.imageWithTextNoLayout(context, bitmap, source);
        return BitmapResource.obtain(bitmap, pool);
    }
    @Override public String getId() {
        // be careful if you change the Generator implementation you have to change this
        // otherwise the users may see a cached image; or clear cache on app update
        return "com.example.MyImageGenerator";
    }
}

class Generators {
    /** OP's original implementation fixed for real centering */
    public static Bitmap imageWithText(Context context, Bitmap bitmap, GenerateParams params) {
        TextView view = new TextView(context);
        view.setText(params.text);
        view.setTextColor(params.color);
        view.setBackgroundColor(params.background);
        view.setTypeface(null, Typeface.BOLD);
        view.setGravity(Gravity.CENTER);
        view.setTextSize(20 /*sp*/);
        Canvas canvas = new Canvas(bitmap);
        view.measure(makeMeasureSpec(canvas.getWidth(), EXACTLY), makeMeasureSpec(canvas.getHeight(), EXACTLY));
        view.layout(0, 0, canvas.getWidth(), canvas.getHeight());
        view.draw(canvas);
        return bitmap;
    }

    /** Generate centered text without creating a View, more lightweight.
     * Consider https://stackoverflow.com/a/8369690/253468 for multiline support. */
    public static Bitmap imageWithTextNoLayout(Context context, Bitmap bitmap, GenerateParams params) {
        Paint paint = new Paint();
        paint.setColor(params.color);
        paint.setTextAlign(Paint.Align.CENTER); // text's anchor for the x given in drawText
        paint.setTextSize(applyDimension(COMPLEX_UNIT_SP, 20, context.getResources().getDisplayMetrics()));
        paint.setTypeface(Typeface.DEFAULT_BOLD);

        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(params.background);
        canvas.drawText(params.text, canvas.getWidth() / 2, canvas.getHeight() / 2, paint);
        return bitmap;
    }
}

// Here are the imports in case you need it;
// didn't want to put it in the beginning to keep the relevant code first.

import java.io.IOException;
import java.util.Locale;

import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.*;
import android.view.*;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.*;

import static android.util.TypedValue.*;
import static android.view.View.MeasureSpec.*;
import static android.view.ViewGroup.LayoutParams.*;

import com.bumptech.glide.*;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.resource.bitmap.*;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
import com.bumptech.glide.load.resource.transcode.BitmapToGlideDrawableTranscoder;

Here's how it looks like (real scrolling is much smoother, GIF is really low FPS):

这是它的样子(真正的滚动要平滑得多,GIF 的 FPS 非常低):

enter image description here

在此处输入图片说明

Notice how it loads the first few items and then gradually loads the rest. It takes a little that the memory cache and pool warms up, but you can use a preloader if you want even smoother display. After it's warmed up it scrolls nicely. The delete button on the action bar calls Glide.clearDiskCache()and Glide.clearMemory()so it starts regenating the items again.

注意它是如何加载前几个项目然后逐渐加载其余项目的。内存缓存和池预热需要一点时间,但如果您想要更流畅的显示,您可以使用预加载器。加热后,它滚动得很好。操作栏上的删除按钮会调用Glide.clearDiskCache()Glide.clearMemory()因此它会再次开始重新生成项目。

回答by rookiedev

According to the documentation, I don't think the load()method can take a Bitmap as parameter. The image source (i.e., the parameter) could be a URL, drawable resource, and file.

根据文档,我认为load()方法不能将 Bitmap 作为参数。图像源(即参数)可以是 URL、可绘制资源和文件。

However, if you want to load a Bitmap into an ImageView, you don't need to use the Glide library. Just use the below statement

但是,如果要将 Bitmap 加载到 ImageView 中,则不需要使用 Glide 库。只需使用以下语句

holder.imgPhoto.setImageBitmap(imageWithText("Random text"));

回答by Rapture Engineering

I don't know performance, but you can try this:

我不知道性能,但你可以试试这个:

First of all transform your bitmap as byte[] array:

首先将您的位图转换为 byte[] 数组:

private byte[] bitmapToByte(Bitmap bitmap){
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    return byteArray;
}

Then use glide in this way:

然后以这种方式使用glide:

Glide.with(holder.imagePhoto.getContext()).load(bitmapToByte(yourBitmap)).asBitmap().override(300, 300).fitCenter().into(holder.imagePhoto);

In your case:

在你的情况下:

Glide.with(holder.imagePhoto.getContext()).load(bitmapToByte(yourBitmap)).asBitmap().into(holder.imagePhoto); //>>not tested

回答by Doan Bui

You can try, The code below adds an ImageView and a TextView to FrameLayout :

你可以试试,下面的代码向 FrameLayout 添加一个 ImageView 和一个 TextView :

FrameLayout frameLayout = new FrameLayout(mContext);
            TextView textView = new TextView(mContext);
            textView.setText("+" + (listImage.size() - countImage));
            textView.setBackground(
                    mContext.getResources().getDrawable(R.drawable.bg_border_tv));
            textView.setTextColor(Color.parseColor("#ffffffff"));
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(18);
            Glide.with(mContext)
                    .load(listImage.get(i))
                    .apply(new RequestOptions().override(size, size)
                            .transform(new RoundedCorners(20)))
                    .into(imageView);
            frameLayout.addView(imageView);
            frameLayout.addView(textView);
            holder.mItemListLnListImage.addView(frameLayout);

The result will be as shown below : enter image description here

结果如下所示: 在此处输入图片说明