【问题标题】:Using Glide to load bitmap into ImageView使用 Glide 将位图加载到 ImageView
【发布时间】:2015-10-30 06:49:10
【问题描述】:

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

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

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;
}

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

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

【问题讨论】:

    标签: java android bitmap android-bitmap android-glide


    【解决方案1】:

    你可以试试 下面的代码在 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);
    

    结果如下图:

    【讨论】:

      【解决方案2】:

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

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

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

      然后这样使用glide:

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

      在你的情况下:

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

      【讨论】:

        【解决方案3】:

        @rookiedev is right, there's no load(Bitmap) in Glide,原因是:获取Bitmap 通常需要时间,有时还会阻塞 I/O。因此,在 UI 线程上调用 imageWithText 并不是一个好习惯。 更新:话虽如此,我不久前提出了this feature;虽然黑客更容易做到,但您可以在下面找到我强烈推荐的“滑翔方式”。

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

        代码还包括以编程方式生成的 UI,因此您只需将以下所有代码复制粘贴到 GlideGeneratedImageListFragment.java 并运行它;唯一的外部依赖是支持库的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;
        

        这是它的样子(真正的滚动要流畅得多,GIF 的 FPS 真的很低):

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

        【讨论】:

        • Glide.clearDiskCache() 和 Glide.clearMemory() 应该被称为: Glide.get(context).clearDiskCache() 和 Glide.get(context).clearMemory() 在后台线程
        • 是的,它们总是被这样调用,否则它不会编译......我只是列出了签名,比如Class.method(args),以表明按钮的作用并不神奇。 clearMemory 应该在 UI 线程上调用,otherwise you may get surprises
        【解决方案4】:

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

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

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

        【讨论】:

        • 是的,但是我有一个包含很多图像的 Listview,所以我想使用 Glide 进行快速滚动
        • load(Bitmap): #122 有一个未解决的问题,但是位图生成可能需要很长时间,导致 UI 线程阻塞。
        猜你喜欢
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多