2016-02-02 33 views
0

我在我的項目中使用Recycler View。我生成pinterestlike多列網格。一切正常。我的應用程序從外部存儲裝載數據(也是圖像)。當在UI線程中加載時,滾動性能非常差。所以我決定創建AsyncTask來加載來自路徑的圖像,而這正在向下滾動的同時搖動。當我再次滾動時,我遇到了問題,因爲重新創建單元格與網格佈局有關。它正在重新整理,對用戶來說可能很差。在內存中緩存圖像(其中很多)不好想法,我認爲,也許這是一個選項來存儲有關每個單元格ImageView大小的信息,並保持它的重用?Android將緩存的圖像加載到RecyclerView中重新排列網格

我RecyclerView佈局適配器看起來是這樣的:

public class MainGridAdapter extends RecyclerView.Adapter<ArticleViewHolder> { 
private List<Article> articleList; 
private Context context; 

public MainGridAdapter(Context context, List<Article> articleList) { 
    this.articleList = articleList; 
    this.context = context; 
} 

@Override 
public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.article_cell, null); 
    ArticleViewHolder avc = new ArticleViewHolder(layoutView); 
    return avc; 
} 

@Override 
public void onBindViewHolder(ArticleViewHolder holder, final int position) { 
    Typeface StagMedium = Typeface.createFromAsset(context.getAssets(), "fonts/Stag-Medium.otf"); 
    holder.articleTitle.setText(articleList.get(position).getTitle()); 
    holder.articleTitle.setTypeface(StagMedium); 
    //Wczytuję obrazek 
    Log.v("DDD", articleList.get(position).getTitle()); 
    Log.v("DDD", String.valueOf(articleList.get(position).getId())); 


    //TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, articleList.get(position).getCover_height()); 
    //holder.container.setLayoutParams(params); 
    BitmapWorkerTask task = new BitmapWorkerTask(holder.articleImage); 
    task.execute(articleList.get(position).getCover_local_path()); 
    /* 
    File file = new File(articleList.get(position).getCover_local_path()); 
    if(file.exists()) { 
     BitmapFactory.Options bmOptions = new BitmapFactory.Options(); 
     Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), bmOptions); 
     holder.articleImage.setImageBitmap(bitmap); 
    } 
    */ 

    //Jeżeli materiał to video to pokazuję ikonkę 
    Log.v("DDD", "Type: " + articleList.get(position).getType()); 
    if(articleList.get(position).getType().equals("article")) { 
     Log.v("DDD", "Article"); 
     holder.articleVideoIcon.setImageResource(android.R.color.transparent); 
    } else { 
     Log.v("DDD", "Video"); 
     holder.articleVideoIcon.setImageResource(R.drawable.play); 
    } 


    holder.container.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Log.v("DDD", "Klikłem sobie na pozycję: " + String.valueOf(position)); 
      Intent intent= new Intent(context,SingleArticle.class); 
      Log.v("DDD", String.valueOf(articleList.get(position).getId())); 
      intent.putExtra("articleId", articleList.get(position).getId()); 
      context.startActivity(intent); 
     } 
    }); 


} 

@Override 
public int getItemCount() { 
    return articleList.size(); 
} 

class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { 
    private final WeakReference<ImageView> imageViewReference; 
    private String path = ""; 

    public BitmapWorkerTask(ImageView imageView) { 
     // Use a WeakReference to ensure the ImageView can be garbage collected 
     imageViewReference = new WeakReference<ImageView>(imageView); 
    } 

    // Decode image in background. 
    @Override 
    protected Bitmap doInBackground(String... params) { 
     path = params[0]; 
     File file = new File(path); 
     if (file.exists()) { 
      BitmapFactory.Options bmOptions = new BitmapFactory.Options(); 
      Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(),bmOptions); 
      int width = bitmap.getWidth(); 
      int height = bitmap.getHeight(); 

      //Bitmap resized_bitmap = Bitmap.createScaledBitmap(bitmap, Math.round(width/2), Math.round(height/2), false); 
      //return resized_bitmap; 
      return bitmap; 
     } else { 
      return null; 
     } 
    } 

    // Once complete, see if ImageView is still around and set bitmap. 
    @Override 
    protected void onPostExecute(Bitmap bitmap) { 
     if (imageViewReference != null && bitmap != null) { 
      final ImageView imageView = imageViewReference.get(); 
      if (imageView != null) { 
       imageView.setImageBitmap(bitmap); 

      } 
     } 
    } 
} 
} 
+0

您可以更好地使用圖像緩存庫,如畢加索,Glide。我認爲這裏的問題是使用Recyclerview,因爲它每次滾動時都會加載數據。您現在編寫的代碼會每次加載數據。但是,如果使用圖像緩存庫,它將加載緩存的圖像,而不是從路徑(本地或遠程)再次加載它。緩存圖像是最好的情況..希望它有幫助。 – HourGlass

+0

我已經想過了,但是當我將使用畢加索異步時,它不一樣嗎?從緩存中加載也需要一些時間,所以快速滾動時不會立即處理它。另一方面,在UI線程中使用picasso會在滾動時降低性能。或者我錯了?我必須從本地路徑加載圖像,因爲客戶端需要應用程序加載離線(在初始化在線和下載數據後)。 – skrystos

+0

當你使用畢加索時,不是確切的情況,畢加索會立即停止緩存圖像,當recyclerview子項失去它的知名度(當滾動)..再加上你也可以指定畢加索有關圖像緩存大小應該是..所以我認爲你應該嘗試這..這將避免你的異步任務以及..當圖像加載時,你可以使用持有人顯示默認圖像/ drawable用戶.. – HourGlass

回答

0

好,我解決我的問題。關鍵是API和數據結構也是我的代碼,所以我開始用SQLite thimbs大小存儲。通過這種方式,我可以在「OnBindViewHolder」這樣的設置單元格大小:

TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT,   articleList.get(position).getCover_height()); 
holder.container.setLayoutParams(params); 

您也可以下載位圖,並存儲高度列表或數組,做同樣的。容器的正常高度應該轉換爲dp,但它的功能就像是一種魅力。浮動項目的問題已解決。 Thx尋求幫助:)