2012-07-11 8 views
9

समस्या का विवरण: मैं थंबनेल कि मेरी SQLite डेटाबेस की आबादी के साथ लेख की एक स्क्रॉल करने योग्य सूची बना रहा हूं। आम तौर पर, यह धीमा होने के अलावा "काम कर रहा है":छवियाँ स्थानीय रूप से कैश नहीं किया जा रहा (यूनिवर्सल छवि लोडर का प्रयोग करके) - धीमी छवि लोड समय

छवियां बहुत धीमी गति से लोड होती हैं ... मैंने सोचा था कि "Universal Image Loader" डिवाइस पर छवियों को कैश किया गया है, और इससे उन्हें केवल दृश्य में दिखाई देने लगेगा आप उन्हें पहले ही देख चुके होंगे (या कम से कम उस के करीब)। लेकिन - जब आप ऊपर/नीचे खींचते हैं, तो कोई भी छवियां वहां नहीं होती हैं, फिर 3-5 सेकंड बाद, छवियां पॉप-इन शुरू होती हैं (जैसे कि यह उन्हें फिर से डाउनलोड कर रही है)

मैं थंबनेल की दृश्यता बदल रहा हूं फ्लाई पर बक्से, लेकिन वह बेकार ढंग से काम कर रहा है - वे बदलने के लिए प्रकट नहीं होते हैं - वे बस देखने या नहीं, कोई चमकती या कुछ भी नहीं स्क्रॉल करते हैं। (लेकिन तब छवियां कुछ और सेकंड के लिए प्रकट नहीं होती हैं)।

मैंने स्क्रॉल करने के बाद अपनी PHP स्क्रिप्ट को हटाकर परीक्षण किया है ... जब मैं पिछली जगह पर वापस स्क्रॉल करता हूं, तो छवियां दिखाई नहीं देती हैं - मुझे लगता है कि यह हर बार मेरी PHP स्क्रिप्ट से लोड हो रहा है।

लेकिन the docs के अनुसार: -:

मेरी ArticleEntryAdapter.js मेरे पास में

विवरण "UsingFreqLimitedMemoryCache (जब कैश आकार सीमा को पार कर जाता है कम से कम अक्सर इस्तेमाल किया बिटमैप हटा दी जाती है) डिफ़ॉल्ट रूप से प्रयोग किया जाता है" :

@Override 
public View getView(final int position, final View convertView, final ViewGroup parent) { 

    // We need to get the best view (re-used if possible) and then 
    // retrieve its corresponding ViewHolder, which optimizes lookup efficiency 
    final View view = getWorkingView(convertView); 
    final ViewHolder viewHolder = getViewHolder(view); 
    final Article article = getItem(position); 

    // Set the title 
    viewHolder.titleView.setText(article.title); 

    //Set the subtitle (subhead) or description 
    if(article.subtitle != null) 
    { 
     viewHolder.subTitleView.setText(article.subtitle); 
    } 
    else if(article.description != null) 
    { 
     viewHolder.subTitleView.setText(article.description); 
    } 

    ImageLoader imageLoader = ImageLoader.getInstance(); 

    imageLoader.displayImage("", viewHolder.thumbView); //clears previous one 
    if(article.filepath != null && article.filepath.length() != 0) { 
     imageLoader.displayImage(
      "http://img.sltdb.com/processes/resize.php?image=" + article.filepath + "&size=100&quality=70", 
      viewHolder.thumbView 
      ); 
     viewHolder.thumbView.setVisibility(View.VISIBLE); 
    } else { 
     viewHolder.thumbView.setVisibility(View.GONE); 
    } 

    return view; 
} 

जहां तक ​​छवियां गलत हैं - यह अक्सर नहीं होती है, लेकिन कभी-कभी स्क्रॉलिंग, मैं एक ही छवि के 2 देखूंगा, और जब मैं लेखों को देखता हूं, तो वे सभी संबंधित नहीं होते हैं (यानी वास्तव में एक ही छवि होने का कोई मौका नहीं) तो - मैं इससे दूर स्क्रॉल करता हूं, और पीछे, और यह अब गलत छवि नहीं है।

नोट: मैं जावा/एंड्रॉइड में नया हूं - शायद आपने पहले ही यह देखा है। प्रति टिप्पणी अनुरोध

अधिक कोड:

private View getWorkingView(final View convertView) { 
    // The workingView is basically just the convertView re-used if possible 
    // or inflated new if not possible 
    View workingView = null; 

    if(null == convertView) { 
     final Context context = getContext(); 
     final LayoutInflater inflater = (LayoutInflater)context.getSystemService 
      (Context.LAYOUT_INFLATER_SERVICE); 

     workingView = inflater.inflate(articleItemLayoutResource, null); 
    } else { 
     workingView = convertView; 
    } 

    return workingView; 
} 

अद्यतन: मेरे मैनिफ़ेस्ट फ़ाइल है:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

लेकिन कैश फ़ोल्डर मैंने पाया पूरी तरह से खाली है:

mnt 
    -sdcard 
    -Android 
     -data 
     -com.mysite.news 
      -cache 
      -uil-images 
+0

'getWorkingView (convertView) क्या है,'? –

+0

@ शेरिफ elKhatib - जोड़ा – Dave

उत्तर

19

मैं सूची दृश्य में छवियों के साथ समान मुद्दों का सामना कर रहा था। संभवतः this answer आपकी गलत छवि समस्या को सही करेगा।

मैंने अभी सार्वभौमिक छवि लोडर के साथ नमूना प्रोजेक्ट डाउनलोड किया है और यह वही व्यवहार प्रदर्शित करता है जिसका आप वर्णन कर रहे हैं।

स्रोत कोड को देखने से अब तक कुछ नोट्स।

public static final int DEFAULT_THREAD_POOL_SIZE = 3; 
public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 1; 
public static final int DEFAULT_MEMORY_CACHE_SIZE = 2 * 1024 * 1024; // bytes 

यह कहा गया है कि किसी भी समय वहाँ तीन धागे को डाउनलोड करने और छवियों के 2 एमबी की अधिकतम हो जाएगा। आप कितनी बड़ी छवियां डाउनलोड कर रहे हैं? क्या आप डिस्क पर कैशिंग भी कर रहे हैं?यदि हां, तो यह धीमा हो जाएगा।

ImageLoader में बुनियादी विकल्पों में से कुछ को कॉन्फ़िगर करने के आप displayImage करने के लिए पारित करने के लिए की आवश्यकता होगी: मेरी परीक्षण के साथ

ImageLoaderConfiguration imageLoaderConfiguration = new ImageLoaderConfiguration.Builder(this) 
    .enableLogging() 
    .memoryCacheSize(41943040) 
    .discCacheSize(104857600) 
    .threadPoolSize(10) 
    .build(); 

imageLoader = ImageLoader.getInstance(); 
imageLoader.init(imageLoaderConfiguration); 

:

DisplayImageOptions options = new DisplayImageOptions.Builder() 
    .showStubImage(R.drawable.stub_image) 
    .cacheInMemory() 
    .cacheOnDisc() 
    .build(); 

मैं आप इन विकल्पों की कोशिश करने का भी चाहते हैं , छवि डिस्क पर हैं, लेकिन लोडिंग अभी भी धीमी है।

व्यापक परीक्षण के बाद, मैंने निर्धारित किया कि प्राथमिक मुद्दा यह है कि UniversalImageLoader बस धीमा है। विशेष रूप से, ImageLoader और LoadAndDisplayImageTask काम को पकड़ रहे हैं। मैं (बहुत तेज़ी से) एक AsyncTask के रूप में LoadAndDisplayImageTask को फिर से लिखता हूं और यह तुरंत बेहतर प्रदर्शन करता है। आप गिटहब पर कोड का फोर्क संस्करण डाउनलोड कर सकते हैं।

Universal Image Loader with AsyncTasks

+0

गलत छवि चीज अक्सर नहीं होती है - बड़ी समस्या छवियों को लोड करने की धीमी गति है। यदि वे कैश किए गए हैं, तो क्या वे कई सेकंड से देरी होने के विरोध में स्लाइड में दिखाई नहीं दे सकते हैं? हालांकि मैं नोट की सराहना करता हूं और अन्य सवालों के जवाबों को देखता हूं। – Dave

+0

उस पंक्ति के बिना, उस पुनर्नवीनीकरण दृश्य में पिछली छवि तब तक दिखाई देती है जब तक कि नई छवि लोड नहीं हो जाती। मैंने इसे बाहर निकाला, और अभी भी देरी हुई है। यह डिवाइस पर कुछ भी कैशिंग नहीं लग रहा है - अगर मैं ऐप लोड करता हूं, नीचे स्क्रॉल करता हूं, अपना PHP कोड हटा देता हूं, फिर बैक अप लेता हूं, छवियां दिखाई नहीं देती हैं। – Dave

+0

छवियों को डिस्क पर कैश नहीं किया जा रहा है (हालांकि मैं उन्हें पसंद करता हूं)।मैं आपके सुझावों का प्रयास करूंगा, और मुझे उम्मीद है, लेकिन दस्तावेज़ों के मुताबिक, DEFAULT को डिस्क पर कैश करना चाहिए। मेरी छवियां छोटी हैं - 100x100px – Dave

1

मुझे लगता है resize.php धीमी है, खासकर अगर यह बड़े पृष्ठों आकार बदलने के लिए है, और कई अनुरोध प्राप्त कर रहे हैं। और किसी भी तरह imageLoader में कैशिंग नहीं किया जाता है।

सबसे पहले मैं छवि लोडिंग के बाद बाकी करता हूं: उपशीर्षक, वर्णन और सब कुछ। क्योंकि अगर छवि लोडिंग बहुत अधिक समय लेती है, तो विवरण और बाकी सभी एक साथ दिखाई देने पर एक और तात्कालिक प्रभाव होता है। आम तौर पर बयान के आपके आदेश ठीक है।

@CameronLowellPallmer का उत्तर स्विच छवियों और कैशिंग का ख्याल रखता है।

+0

resize.php फ़ाइलों को कैश किया जाता है और जब आप किसी ब्राउज़र में यूआरएल दबाते हैं तो तुरंत लोड होते हैं (क्योंकि वे TINY फ़ाइलें हैं)। मुझे यकीन नहीं है कि "छवि लोड होने के बाद बाकी ..." (याद रखें मैं एक नोब हूं :) – Dave

+0

मैंने शीर्षक से पहले छवि सामग्री को स्थानांतरित किया ... आदि सामान - कोई बदलाव नहीं। – Dave

+0

(और सबसे महत्वपूर्ण बात यह है कि छवियों को डिवाइस पर कैश किया जाना चाहिए - यदि यह हर बार मेरी PHP स्क्रिप्ट मार रहा है, तो यह स्वयं के लिए एक मुद्दा है!) – Dave

3

इग्निशन ओपन सोर्स प्रोजेक्ट से एक वैकल्पिक समाधान "रिमोट इमेज व्यू" है।

http://kaeppler.github.com/ignition-docs/ignition-core/apidocs/com/github/ignition/core/widgets/RemoteImageView.html

प्रभावी ढंग से, RemoteImageView imageView प्रदान करता है और पर्दे के पीछे आप के लिए सभी प्राप्त कर रहा है/कैशिंग करता है।

हालांकि यह आपके द्वारा सूचीबद्ध आपकी समस्या को जरूरी नहीं हल करता है, यह एक वैकल्पिक समाधान के रूप में जांच के लायक हो सकता है।

संपादित करें: यदि आपको अभी भी रिमोट छवि समाधान की आवश्यकता है तो मैं पिकासो की अत्यधिक अनुशंसा करता हूं। मैं पिकासो के साथ अपने अनुप्रयोगों में RemoteImageView बदल दिया है: http://square.github.io/picasso/

+0

क्या इसके लिए कोई निर्देश/ट्यूटोरियल साइटें हैं? – Dave

+0

इग्निशन प्रोजेक्ट में उदाहरण गतिविधि का एक बहुत ही सरल उपयोग है: https://github.com/kaeppler/ignition/blob/master/ignition-core/ignition-core-samples/src/com/github/ignition/samples /core/RemoteImageViewActivity.java – theelfismike

0

इस वर्ग मेरे लिए काम किया: उपयोग की

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.lang.ref.WeakReference; 
import java.util.HashMap; 
import java.util.Map; 

import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse; 
import org.apache.http.HttpStatus; 
import org.apache.http.HttpVersion; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.params.BasicHttpParams; 
import org.apache.http.params.CoreProtocolPNames; 
import org.apache.http.params.HttpParams; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Color; 
import android.graphics.drawable.ColorDrawable; 
import android.graphics.drawable.Drawable; 
import android.os.AsyncTask; 
import android.util.Log; 
import android.widget.ImageView; 

public class ImageDownloader { 

    Map<String,Bitmap> imageCache; 

    public ImageDownloader(){ 
     imageCache = new HashMap<String, Bitmap>(); 

    } 

    //download function 
    public void download(String url, ImageView imageView) { 
     if (cancelPotentialDownload(url, imageView)&&url!=null) { 

      //Caching code right here 
      String filename = String.valueOf(url.hashCode()); 
      File f = new File(getCacheDirectory(imageView.getContext()), filename); 

       // Is the bitmap in our memory cache? 
      Bitmap bitmap = null; 

       bitmap = (Bitmap)imageCache.get(f.getPath()); 
       BitmapFactory.Options bfOptions=new BitmapFactory.Options(); 
       bfOptions.inDither=false;      //Disable Dithering mode 
       bfOptions.inPurgeable=true;     //Tell to gc that whether it needs free memory, the Bitmap can be cleared 
       bfOptions.inInputShareable=true;    //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future 
       bfOptions.inTempStorage=new byte[32 * 1024]; 
       FileInputStream fs=null; 

       if(bitmap == null){ 

        //bitmap = BitmapFactory.decodeFile(f.getPath(),options); 
        try { 
         fs = new FileInputStream(f); 
         if(fs!=null) bitmap=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions); 
        } catch (IOException e) { 
         //TODO do something intelligent 
         e.printStackTrace(); 
        } finally{ 
         if(fs!=null) { 
          try { 
           fs.close(); 
          } catch (IOException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
          } 
         } 
        } 

        if(bitmap != null){ 
         imageCache.put(f.getPath(), bitmap); 
        } 

       } 
       //No? download it 
       if(bitmap == null){ 
        BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); 
        DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task); 
        imageView.setImageDrawable(downloadedDrawable); 
        task.execute(url); 
       }else{ 
        //Yes? set the image 
        imageView.setImageBitmap(bitmap); 
       } 
     } 
    } 

    //cancel a download (internal only) 
    private static boolean cancelPotentialDownload(String url, ImageView imageView) { 
     BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); 

     if (bitmapDownloaderTask != null) { 
      String bitmapUrl = bitmapDownloaderTask.url; 
      if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { 
       bitmapDownloaderTask.cancel(true); 
      } else { 
       // The same URL is already being downloaded. 
       return false; 
      } 
     } 
     return true; 
    } 

    //gets an existing download if one exists for the imageview 
    private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) { 
     if (imageView != null) { 
      Drawable drawable = imageView.getDrawable(); 
      if (drawable instanceof DownloadedDrawable) { 
       DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable; 
       return downloadedDrawable.getBitmapDownloaderTask(); 
      } 
     } 
     return null; 
    } 

    //our caching functions 
    // Find the dir to save cached images 
    public static File getCacheDirectory(Context context){ 
     String sdState = android.os.Environment.getExternalStorageState(); 
     File cacheDir; 

     if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) { 
      File sdDir = android.os.Environment.getExternalStorageDirectory(); 

      //TODO : Change your diretcory here 
      cacheDir = new File(sdDir,"data/tac/images"); 
     } 
     else 
      cacheDir = context.getCacheDir(); 

     if(!cacheDir.exists()) 
      cacheDir.mkdirs(); 
      return cacheDir; 
    } 

    private void writeFile(Bitmap bmp, File f) { 
      FileOutputStream out = null; 

      try { 
      out = new FileOutputStream(f); 
      bmp.compress(Bitmap.CompressFormat.PNG, 80, out); 
      } catch (Exception e) { 
      e.printStackTrace(); 
      } 
      finally { 
      try { if (out != null) out.close(); } 
      catch(Exception ex) {} 
      } 
    } 
    /////////////////////// 

    //download asynctask 
    public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { 
     private String url; 
     private final WeakReference<ImageView> imageViewReference; 

     public BitmapDownloaderTask(ImageView imageView) { 
      imageViewReference = new WeakReference<ImageView>(imageView); 
     } 

     @Override 
     // Actual download method, run in the task thread 
     protected Bitmap doInBackground(String... params) { 
      // params comes from the execute() call: params[0] is the url. 
      url = (String)params[0]; 
      return downloadBitmap(params[0]); 
     } 

     @Override 
     // Once the image is downloaded, associates it to the imageView 
     protected void onPostExecute(Bitmap bitmap) { 
      if (isCancelled()) { 
       bitmap = null; 
      } 

      if (imageViewReference != null) { 
       ImageView imageView = imageViewReference.get(); 
       BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); 
       // Change bitmap only if this process is still associated with it 
       if (this == bitmapDownloaderTask) { 
        imageView.setImageBitmap(bitmap); 

        //cache the image 


        String filename = String.valueOf(url.hashCode()); 
        File f = new File(getCacheDirectory(imageView.getContext()), filename); 

        imageCache.put(f.getPath(), bitmap); 

        writeFile(bitmap, f); 
       } 
      } 
     } 


    } 

    static class DownloadedDrawable extends ColorDrawable { 
     private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference; 

     public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { 
      super(Color.BLACK); 
      bitmapDownloaderTaskReference = 
       new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask); 
     } 

     public BitmapDownloaderTask getBitmapDownloaderTask() { 
      return bitmapDownloaderTaskReference.get(); 
     } 
    } 

    //the actual download code 
    static Bitmap downloadBitmap(String url) { 
     HttpParams params = new BasicHttpParams(); 
     params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     HttpClient client = new DefaultHttpClient(params); 
     final HttpGet getRequest = new HttpGet(url); 

     try { 
      HttpResponse response = client.execute(getRequest); 
      final int statusCode = response.getStatusLine().getStatusCode(); 
      if (statusCode != HttpStatus.SC_OK) { 
       Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); 
       return null; 
      } 

      final HttpEntity entity = response.getEntity(); 
      if (entity != null) { 
       InputStream inputStream = null; 
       try { 
        inputStream = entity.getContent(); 
        final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); 
        return bitmap; 
       } finally { 
        if (inputStream != null) { 
         inputStream.close(); 
        } 
        entity.consumeContent(); 
       } 
      } 
     } catch (Exception e) { 
      // Could provide a more explicit error message for IOException or IllegalStateException 
      getRequest.abort(); 
      Log.w("ImageDownloader", "Error while retrieving bitmap from " + url + e.toString()); 
     } finally { 
      if (client != null) { 
       //client.close(); 
      } 
     } 
     return null; 
    } 
} 

उदाहरण:

downloader = new ImageDownloader(); 
ImageView image_profile =(ImageView) row.findViewById(R.id.image_profile); 
downloader.download(url, image_profile); 
संबंधित मुद्दे