2015-08-06 16 views
9

Come posso utilizzare la libreria Glide per caricare Bitmap nel mio ImageView? Voglio creare un'immagine personalizzata con il testo e caricarla in imageview usando Glide.Utilizzo di Glide per caricare bitmap in ImageView

Questo è il mio metodo per creare bitmap personalizzata con testo

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

Ma quando provo a caricare questo bitmap utilizzando glide sto ottenendo errore

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

risposta

19

@rookiedev is right, there's no load(Bitmap) in Glide, per un motivo: l'acquisizione di una Bitmap di solito richiede tempo e, a volte il blocco di I/O. Quindi non è una buona pratica chiamare imageWithText sul thread dell'interfaccia utente. Aggiornamento: Detto questo, ho proposto il this feature qualche tempo fa; e mentre gli hack sono più facili da fare, puoi trovare il "Glide way" in basso, che consiglio vivamente.

Glide è progettato per essere flessibile e questo problema dimostra che la caratteristica è estremamente buona. La seguente implementazione può sembrare lunga, ma tutti i pezzi hanno la loro ragione di esistere. Dato il guadagno in termini di prestazioni, questa quantità di codice adatta al tuo generatore nel mondo di Glide non è molto. Ho provato a formattarlo in modo che fosse breve, comprimendo parti non pertinenti e utilizzando le importazioni statiche per essere più brevi (vedere la fine per le importazioni).

Il codice include anche l'interfaccia utente generata a livello di codice in modo che sia possibile copiare e incollare tutto il codice riportato di seguito in GlideGeneratedImageListFragment.java ed eseguirlo; l'unica dipendenza esterna è il supporto di 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; 

Ecco come sembra (reale scorrimento è molto più regolare, GIF è davvero basso FPS):

enter image description here

Notate come carica i primi elementi e quindi carica a poco a poco tutto il resto. Ci vuole un po 'che la memoria cache e il pool si riscaldino, ma puoi usare un preloader se vuoi una visualizzazione ancora più fluida. Dopo che si è scaldato, scorre perfettamente. Il pulsante Elimina sulla barra delle azioni chiama Glide.clearDiskCache() e Glide.clearMemory(), quindi ricomincia a rigenerare gli elementi.

+0

Glide.clearDiskCache() e Glide.clearMemory() dovrebbero essere chiamati come: Glide.get (context) .clearDiskCache() e Glide.get (context) .clearMemory() in un thread in background –

+1

Sì, vengono sempre chiamati in quel modo, non si compila altrimenti ... Stavo solo elencando le firme, come 'Class.method (args)' per mostrare che non è magico ciò che fa il pulsante. 'clearMemory' dovrebbe essere chiamato sul thread dell'interfaccia utente, [altrimenti potresti avere delle sorprese] (https://github.com/bumptech/glide/pull/717/files). – TWiStErRob

1

Secondo la documentazione, io don Penso che il metodo load() possa prendere una bitmap come parametro. L'origine dell'immagine (ad esempio, il parametro) potrebbe essere un URL, una risorsa disegnabile e un file.

Tuttavia, se si desidera caricare una bitmap in un ImageView, non è necessario utilizzare la libreria Glide. Basta usare la dichiarazione seguente

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

Yea h, ma ho una Listview con molte immagini quindi voglio usare Glide per scroll veloce – user3296088

+1

C'è un problema aperto per ['load (Bitmap)': # 122] (https://github.com/bumptech/glide/issues/122), ma la generazione di bitmap potrebbe richiedere molto tempo, con conseguente blocco del thread dell'interfaccia utente. – TWiStErRob

3

Non so prestazioni, ma si può provare questo:

Prima di tutto trasformare il vostro bitmap come byte [] array:

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

Quindi utilizzare glide in questo modo:

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

Nel tuo caso:

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