0

私はリモートサーバに画像のURLのリストを持っています。私は、非同期的にをグリッドビューにロードする必要があります。サードパーティライブラリを使用しません。私は、次のタスク構築しています:第三者のライブラリを使わずにnetからgridに画像をロード

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


    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) { 
     if (isCancelled()) { 
      return null; 
     } 
     try { 
      URL url = new URL(params[0]); 
      return BitmapFactory.decodeStream(url.openConnection().getInputStream()); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      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); 
      } 
     } 
    } 

}` 

をそして私は、次のようにonBindViewHolderを呼び出している:私は私が対処する方法を見つけることができないいくつかの問題に直面しています

@Override 
public void onBindViewHolder(GridHolder holder, int position) { 
    final AnimalModel animal = list.get(position); 
    holder.image.setTag(holder); 
    holder.text.setText(animal.getName()); 
    new BitmapWorkerTask(holder.image).execute(animal.getImagePath()); 
} 

を: 1)スクロールイメージがほぼ毎回ポジションを失う 2)configurationChangedに画像をロードするのに時間がかかる場合、いくつかのタスクが停止せず、OSがそれらを待っていると仮定します。助けてください。

答えて

1

プロジェクトにこれらの4つのクラスを追加します

import android.content.Context; 

import java.io.File; 

public class FileCache { 

private File cacheDir; 

public FileCache(Context context){ 

    //Find the dir at SDCARD to save cached images 

    if (android.os.Environment.getExternalStorageState().equals(
      android.os.Environment.MEDIA_MOUNTED)) 
    { 
     //if SDCARD is mounted (SDCARD is present on device and mounted) 
     cacheDir = new File(
       android.os.Environment.getExternalStorageDirectory(),"LazyList"); 
    } 
    else 
    { 
     // if checking on simulator the create cache dir in your application context 
     cacheDir=context.getCacheDir(); 
    } 

    if(!cacheDir.exists()){ 
     // create cache dir in your application context 
     cacheDir.mkdirs(); 
    } 
} 

public File getFile(String url){ 
    //Identify images by hashcode or encode by URLEncoder.encode. 
    String filename=String.valueOf(url.hashCode()); 

    File f = new File(cacheDir, filename); 
    return f; 

} 

public void clear(){ 
    // list all files inside cache directory 
    File[] files=cacheDir.listFiles(); 
    if(files==null) 
     return; 
    //delete all cache directory files 
    for(File f:files) 
     f.delete(); 
} 

} 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.Handler; 
import android.widget.ImageView; 

import com.example.smartlaw.R; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.Collections; 
import java.util.Map; 
import java.util.WeakHashMap; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class ImageLoader { 

    // Initialize MemoryCache 
    MemoryCache memoryCache = new MemoryCache(); 

    FileCache fileCache; 

    //Create Map (collection) to store image and image url in key value pair 
    private Map<ImageView, String> imageViews = Collections.synchronizedMap(
      new WeakHashMap<ImageView, String>()); 
    ExecutorService executorService; 

    //handler to display images in UI thread 
    Handler handler = new Handler(); 

    public ImageLoader(Context context){ 

     fileCache = new FileCache(context); 

     // Creates a thread pool that reuses a fixed number of 
     // threads operating off a shared unbounded queue. 
     executorService=Executors.newFixedThreadPool(5); 

    } 

    // default image show in list (Before online image download) 
    final int stub_id= R.drawable.book_background; 

    public void DisplayImage(String url, ImageView imageView) 
    { 
     //Store image and url in Map 
     imageViews.put(imageView, url); 

     //Check image is stored in MemoryCache Map or not (see MemoryCache.java) 
     Bitmap bitmap = memoryCache.get(url); 

     if(bitmap!=null){ 
      // if image is stored in MemoryCache Map then 
      // Show image in listview row 
      imageView.setImageBitmap(bitmap); 
     } 
     else 
     { 
      //queue Photo to download from url 
      queuePhoto(url, imageView); 

      //Before downloading image show default image 
      imageView.setImageResource(stub_id); 
     } 
    } 

    private void queuePhoto(String url, ImageView imageView) 
    { 
     // Store image and url in PhotoToLoad object 
     PhotoToLoad p = new PhotoToLoad(url, imageView); 

     // pass PhotoToLoad object to PhotosLoader runnable class 
     // and submit PhotosLoader runnable to executers to run runnable 
     // Submits a PhotosLoader runnable task for execution 

     executorService.submit(new PhotosLoader(p)); 
    } 

    //Task for the queue 
    private class PhotoToLoad 
    { 
     public String url; 
     public ImageView imageView; 
     public PhotoToLoad(String u, ImageView i){ 
      url=u; 
      imageView=i; 
     } 
    } 

    class PhotosLoader implements Runnable { 
     PhotoToLoad photoToLoad; 

     PhotosLoader(PhotoToLoad photoToLoad){ 
      this.photoToLoad=photoToLoad; 
     } 

     @Override 
     public void run() { 
      try{ 
       //Check if image already downloaded 
       if(imageViewReused(photoToLoad)) 
        return; 
       // download image from web url 
       Bitmap bmp = getBitmap(photoToLoad.url); 

       // set image data in Memory Cache 
       memoryCache.put(photoToLoad.url, bmp); 

       if(imageViewReused(photoToLoad)) 
        return; 

       // Get bitmap to display 
       BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); 

       // Causes the Runnable bd (BitmapDisplayer) to be added to the message queue. 
       // The runnable will be run on the thread to which this handler is attached. 
       // BitmapDisplayer run method will call 
       handler.post(bd); 

     }catch(Throwable th){ 
      th.printStackTrace(); 
     } 
    } 
} 

private Bitmap getBitmap(String url) 
{ 
    File f=fileCache.getFile(url); 

    //from SD cache 
    //CHECK : if trying to decode file which not exist in cache return null 
    Bitmap b = decodeFile(f); 
    if(b!=null) 
     return b; 

    // Download image file from web 
    try { 

     Bitmap bitmap=null; 
     URL imageUrl = new URL(url); 
     HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); 
     conn.setConnectTimeout(30000); 
     conn.setReadTimeout(30000); 
     conn.setInstanceFollowRedirects(true); 
     InputStream is=conn.getInputStream(); 

     // Constructs a new FileOutputStream that writes to file 
     // if file not exist then it will create file 
     OutputStream os = new FileOutputStream(f); 

     // See Utils class CopyStream method 
     // It will each pixel from input stream and 
     // write pixels to output stream (file) 
     Utils.CopyStream(is, os); 

     os.close(); 
     conn.disconnect(); 

     //Now file created and going to resize file with defined height 
     // Decodes image and scales it to reduce memory consumption 
     bitmap = decodeFile(f); 

     return bitmap; 

    } catch (Throwable ex){ 
     ex.printStackTrace(); 
     if(ex instanceof OutOfMemoryError) 
      memoryCache.clear(); 
     return null; 
    } 
} 

//Decodes image and scales it to reduce memory consumption 
private Bitmap decodeFile(File f){ 

    try { 

     //Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     FileInputStream stream1=new FileInputStream(f); 
     BitmapFactory.decodeStream(stream1,null,o); 
     stream1.close(); 

     //Find the correct scale value. It should be the power of 2. 

     // Set width/height of recreated image 
     final int REQUIRED_SIZE=85; 

     int width_tmp=o.outWidth, height_tmp=o.outHeight; 
     int scale=1; 
     while(true){ 
      if(width_tmp/2 < REQUIRED_SIZE || height_tmp/2 < REQUIRED_SIZE) 
       break; 
      width_tmp/=2; 
      height_tmp/=2; 
      scale*=2; 
     } 

     //decode with current scale values 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize=scale; 
     FileInputStream stream2=new FileInputStream(f); 
     Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2); 
     stream2.close(); 
     return bitmap; 

    } catch (FileNotFoundException e) { 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

boolean imageViewReused(PhotoToLoad photoToLoad){ 

    String tag=imageViews.get(photoToLoad.imageView); 
    //Check url is already exist in imageViews MAP 
    if(tag==null || !tag.equals(photoToLoad.url)) 
     return true; 
    return false; 
} 

//Used to display bitmap in the UI thread 
class BitmapDisplayer implements Runnable 
{ 
    Bitmap bitmap; 
    PhotoToLoad photoToLoad; 
    public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} 
    public void run() 
    { 
     if(imageViewReused(photoToLoad)) 
      return; 

     // Show bitmap on UI 
     if(bitmap!=null) 
      photoToLoad.imageView.setImageBitmap(bitmap); 
     else 
      photoToLoad.imageView.setImageResource(stub_id); 
    } 
} 

public void clearCache() { 
    //Clear cache directory downloaded images and stored data in maps 
    memoryCache.clear(); 
    fileCache.clear(); 
} 

} 
import android.graphics.Bitmap; 
import android.util.Log; 

import java.util.Collections; 
import java.util.Iterator; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.Map.Entry; 

public class MemoryCache { 

    private static final String TAG = "MemoryCache"; 

    //Last argument true for LRU ordering 
    private Map<String, Bitmap> cache = Collections.synchronizedMap(
      new LinkedHashMap<String, Bitmap>(10,1.5f,true)); 

    //current allocated size 
    private long size=0; 

    //max memory cache folder used to download images in bytes 
    private long limit=1000000; 

    public MemoryCache(){ 

     //use 25% of available heap size 
     setLimit(Runtime.getRuntime().maxMemory()/4); 
    } 

    public void setLimit(long new_limit){ 

     limit=new_limit; 
     Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB"); 
    } 

    public Bitmap get(String id){ 
     try{ 
      if(!cache.containsKey(id)) 
       return null; 

      return cache.get(id); 

     }catch(NullPointerException ex){ 
      ex.printStackTrace(); 
      return null; 
     } 
    } 

    public void put(String id, Bitmap bitmap){ 
     try{ 
      if(cache.containsKey(id)) 
       size-=getSizeInBytes(cache.get(id)); 
      cache.put(id, bitmap); 
      size+=getSizeInBytes(bitmap); 
      checkSize(); 
     }catch(Throwable th){ 
      th.printStackTrace(); 
     } 
    } 

    private void checkSize() { 
     Log.i(TAG, "cache size="+size+" length="+cache.size()); 
     if(size>limit){ 

      //least recently accessed item will be the first one iterated 
      Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator(); 

      while(iter.hasNext()){ 
       Entry<String, Bitmap> entry=iter.next(); 
       size-=getSizeInBytes(entry.getValue()); 
       iter.remove(); 
       if(size<=limit) 
        break; 
      } 
      Log.i(TAG, "Clean cache. New size "+cache.size()); 
     } 
    } 

    public void clear() { 
     try{ 
      // Clear cache 
      cache.clear(); 
      size=0; 
     }catch(NullPointerException ex){ 
      ex.printStackTrace(); 
     } 
    } 

    long getSizeInBytes(Bitmap bitmap) { 
     if(bitmap==null) 
      return 0; 
     return bitmap.getRowBytes() * bitmap.getHeight(); 
    } 
} 
import java.io.InputStream; 
import java.io.OutputStream; 

public class Utils { 
    public static void CopyStream(InputStream is, OutputStream os) 
    { 
     final int buffer_size=1024; 
     try 
     { 

      byte[] bytes=new byte[buffer_size]; 
      for(;;) 
      { 
       //Read byte from input stream 

       int count=is.read(bytes, 0, buffer_size); 
       if(count==-1) 
        break; 

       //Write byte from output stream 
       os.write(bytes, 0, count); 
      } 
     } 
     catch(Exception ex){} 
    } 
} 

そして、ちょうど何のスクロール問題は起こりませんし、それがキャッシュにイメージを保持するように、これは、バックグラウンドの各位置に画像をロードするアダプタgetViewメソッド()メソッド

public View getView(final int position, View convertVie, ViewGroup parent) { 
     if (convertView == null) { 

      inflater = (LayoutInflater) mContext 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = inflater.inflate(R.layout.book_item_to_download, parent, false); 

      holder = new Holder(); 

      holder.BookImage = (ImageView) convertView.findViewById(R.id.bookBackground); 


      convertView.setTag(holder); 
     } else { 
      holder = (Holder) convertView.getTag(); 
     } 



     ImageView image = holder.BookImage; 

     //DisplayImage function from ImageLoader Class 
     imageLoader.DisplayImage(url, image); 

     //Then do whatever you want here 

     return convertView; 
    } 

でこのようにそれを使用しますだから、携帯電話向けのものであれば何でも私は紀元前にロードしません

+0

それは例外を与えます - ファイルが見つかりません –

+0

ありがとう! Nexus5にはSDカードがないため、FileCacheを除外してメモリキャッシュのみを使用するように管理しました。もう一度ありがとう、私の友人! –

+0

あなたは私の友人を歓迎しており、コンストラクタでファイルキャッシュクラスで 場合(android.os.Environment.getExternalStorageState()。等号( android.os.Environment.MEDIA_MOUNTED)) { /これなステートメントがあります/ SDCARDがマウントされている場合(SDCARDがデバイス上に存在し、マウントされている場合) cacheDir = new File( android.os.Environment.getExternalStorageDirectory()、 "LazyList"); } 外部ストレージの代わりに取得されるストレージのタイプを変更するだけです –

関連する問題