有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

未在本地缓存java映像(使用通用映像加载程序)会降低映像加载时间

问题描述: 我正在创建一个带有缩略图的可滚动文章列表,该列表由我的SQLite数据库填充。一般来说,除了速度慢之外,它是“起作用的”:

图像加载非常慢。。。我认为使用“Universal Image Loader”将图像缓存在设备上,如果您已经查看了它们(或者至少已经接近了),那么这会使它们看起来像是滚动到视图中。但是-当你向上/向下拖动时,图像都不存在,然后3-5秒后,图像开始弹出(好像正在下载它们)

我正在动态地改变缩略图框的可见性,但这是完美的——它们看起来没有变化——它们只是滚动到视图中,没有闪烁或任何东西。(但接下来的几秒钟内图像都不会出现)

我已经通过在滚动后删除我的php脚本进行了测试。。。当我滚动回到prev spot时,图像不会显示——这让我假设每次都是从我的PHP脚本加载的

但根据the docs“使用FreqLimitedMemoryCache(超过缓存大小限制时删除最不常用的位图)-默认情况下使用”

详细信息:

在我的ArticleEntryAdapter.js中,我有:

@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个相同的图片,当我看文章时,它们根本没有关联(即不可能实际拥有相同的图片),所以-我从它滚动,然后再滚动,它不再是不正确的图片

注意:我是Java/Android新手——你可能已经注意到了

每个评论请求的更多代码:

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 安卓:name="安卓.permission.WRITE_EXTERNAL_STORAGE"/>

但我找到的缓存文件夹完全为空:

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

共 (4) 个答案

  1. # 1 楼答案

    我在列表视图中遇到了类似的图像问题。可能this answer会纠正错误的图像问题

    我刚刚下载了带有UniversalImageLoader的示例项目,它显示了与您描述的相同的行为

    到目前为止,还有一些注释没有通读源代码

    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
    

    这意味着,在任何时候都会有三个线程下载和最大2MB的图像。你下载的图像有多大?你也在缓存到磁盘吗?如果是这样,那将是缓慢的

    要在ImageLoader中配置一些基本选项,您需要传入displayImage:

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

    我还希望您尝试以下选项:

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

    在我的测试中,映像在磁盘上,但加载速度仍然很慢

    经过广泛的测试,我确定主要的问题是UniversalImageLoader速度太慢。具体地说,ImageLoader和LoadAndDisplayImageTask阻碍了工作。我(很快)将LoadAndDisplayImageTask重写为异步任务,它立即表现得更好。您可以在GitHub上下载代码的分叉版本

    Universal Image Loader with AsyncTasks

  2. # 2 楼答案

    我怀疑会调整大小。php的速度很慢,尤其是当它必须调整大页面的大小并且接收到多个请求时。不知何故,imageLoader中的缓存没有完成

    首先,在图像加载之后,我将执行其余的:字幕、描述和所有内容因为如果图像加载时间过长,如果描述和所有其他内容同时出现,则会产生更即时的效果。通常你的陈述顺序是好的

    @CameronLowellPallmer的答案负责交换图像和缓存

  3. # 3 楼答案

    另一种解决方案是来自ignition开源项目的“RemoteImageView”

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

    RemoteImageView有效地扩展了ImageView,并在幕后为您执行所有抓取/缓存操作

    虽然它不一定能解决您列出的问题,但作为替代解决方案,它可能值得研究

    编辑:如果你仍然需要远程图像解决方案,我强烈推荐毕加索。我已将应用程序中的RemoteImageView替换为毕加索:http://square.github.io/picasso/

  4. # 4 楼答案

    这门课对我很有用:

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