【问题标题】:What's the fastest way to pass an image between two activities?在两个活动之间传递图像的最快方法是什么?
【发布时间】:2016-05-14 12:25:31
【问题描述】:

说我有:

Activityactivity1 包含ImageViewimageView1

Activityactivity2 包含ImageViewimageView2,

我有一个字符串 url 指向一个图像(由 Picasso 缓存),我已经将它加载到 imageView1 中。 如何以最快的方式启动 Activitiy2 并将相同的图像加载到 ImageView2 中?

目前,我会在活动启动后立即在网址上调用Picasso.load().into()。这很快,但我正在寻找更快的东西。

Picasso.with(mContext)
        .load(myUrl)
        .into(imageView2);

任何建议都将不胜感激。

【问题讨论】:

    标签: android android-imageview picasso


    【解决方案1】:

    毕加索下载完整图像并将原始图像保存在磁盘/内存中。假设原始图像尺寸为 800x800,并且您尝试将此图像加载到尺寸为:100x100 的视图中,那么 Picasso 将需要一些时间来重新调整大小。 您可能想尝试一下 Glide[1]。 Glide 可以选择缓存调整大小的图像和原始图像。 (检查 Glide#diskCachingStratedgy)

    此外,对于 Picasso,如果您使用 .noFade() 选项,则图像加载速度可能会更快。

    [1]https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

    【讨论】:

    • 发现 .noFade() 方法正是我想要的,谢谢!
    【解决方案2】:

    我认为它已经足够快了。 Picasso 只是从共享内存缓存中获取它,它被存储为准备使用的位图。它比使用 intent.putExtra("image".bitmapByteArray) 或使用带有解码或编码位图的文件更快。

    【讨论】:

      【解决方案3】:

      您需要创建三个类来将图像存储在缓存中,并且加载图像的速度非常快。 1.ImageLoader.java 2. FileCache.java 3. MemoryCache.java

      ImageLoader.java

      package com.thefinal3.Camera;
      
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.FileOutputStream;
      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;
      
      import android.app.Activity;
      import android.content.Context;
      import android.graphics.Bitmap;
      import android.graphics.BitmapFactory;
      import android.widget.ImageView;
      
      import com.thefinal3.R;
      import com.thefinal3.Utils.Utils;
      
      /**
       * Created by Akash patel on 03-05-2016.
       */
      public class ImageLoader {
      
          MemoryCache memoryCache=new MemoryCache();
          FileCache fileCache;
          private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
          ExecutorService executorService;
      
          public ImageLoader(Context context){
              fileCache=new FileCache(context);
              executorService=Executors.newFixedThreadPool(5);
          }
      
          final int stub_id= R.drawable.ic_no_image;
          public void DisplayImage(String url, ImageView imageView)
          {
              imageViews.put(imageView, url);
              Bitmap bitmap=memoryCache.get(url);
              if(bitmap!=null)
                  imageView.setImageBitmap(bitmap);
              else
              {
                  queuePhoto(url, imageView);
                  imageView.setImageResource(stub_id);
              }
          }
      
          private void queuePhoto(String url, ImageView imageView)
          {
              PhotoToLoad p=new PhotoToLoad(url, imageView);
              executorService.submit(new PhotosLoader(p));
          }
      
          private Bitmap getBitmap(String url)
          {
              File f=fileCache.getFile(url);
      
              //from SD cache
              Bitmap b = decodeFile(f);
              if(b!=null)
                  return b;
      
              //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();
                  OutputStream os = new FileOutputStream(f);
                  Utils.CopyStream(is, os);
                  os.close();
                  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;
                  BitmapFactory.decodeStream(new FileInputStream(f),null,o);
      
                  //Find the correct scale value. It should be the power of 2.
                  final int REQUIRED_SIZE=70;
                  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 inSampleSize
                  BitmapFactory.Options o2 = new BitmapFactory.Options();
                  o2.inSampleSize=scale;
                  return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
              } catch (FileNotFoundException e) {}
              return null;
          }
      
          //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() {
                  if(imageViewReused(photoToLoad))
                      return;
                  Bitmap bmp=getBitmap(photoToLoad.url);
                  memoryCache.put(photoToLoad.url, bmp);
                  if(imageViewReused(photoToLoad))
                      return;
                  BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
                  Activity a=(Activity)photoToLoad.imageView.getContext();
                  a.runOnUiThread(bd);
              }
          }
      
          boolean imageViewReused(PhotoToLoad photoToLoad){
              String tag=imageViews.get(photoToLoad.imageView);
              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;
                  if(bitmap!=null)
                      photoToLoad.imageView.setImageBitmap(bitmap);
                  else
                      photoToLoad.imageView.setImageResource(stub_id);
              }
          }
      
          public void clearCache() {
              memoryCache.clear();
              fileCache.clear();
          }
      
      }
      

      FileCache.java

      package com.thefinal3.Camera;
      
      import android.content.Context;
      
      import java.io.File;
      
      /**
       * Created by Akash patel on 03-05-2016.
       */
      public class FileCache {
      
          private File cacheDir;
      
          public FileCache(Context context){
              //Find the dir to save cached images
              if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
                  cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"TTImages_cache");
              else
                  cacheDir=context.getCacheDir();
              if(!cacheDir.exists())
                  cacheDir.mkdirs();
          }
      
          public File getFile(String url){
              //I identify images by hashcode. Not a perfect solution, good for the demo.
              String filename=String.valueOf(url.hashCode());
              //Another possible solution (thanks to grantland)
              //String filename = URLEncoder.encode(url);
              File f = new File(cacheDir, filename);
              return f;
      
          }
      
          public void clear(){
              File[] files=cacheDir.listFiles();
              if(files==null)
                  return;
              for(File f:files)
                  f.delete();
          }
      
      }
      

      MemoryCache.java

          package com.thefinal3.Camera;
          import java.util.Collections;
          import java.util.Iterator;
          import java.util.LinkedHashMap;
          import java.util.Map;
          import java.util.Map.Entry;
          import android.graphics.Bitmap;
          import android.util.Log;
      
          public class MemoryCache {
      
              private static final String TAG = "MemoryCache";
              private Map<String, Bitmap> cache= Collections.synchronizedMap(
                      new LinkedHashMap<String, Bitmap>(10, 1.5f, true));//Last argument true for LRU ordering
              private long size=0;//current allocated size
              private long limit=1000000;//max memory in bytes
      
              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;
                      //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
                      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){
                      Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
                      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{
                      //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
                      cache.clear();
                      size=0;
                  }catch(NullPointerException ex){
                      ex.printStackTrace();
                  }
              }
      
              long getSizeInBytes(Bitmap bitmap) {
                  if(bitmap==null)
                      return 0;
                  return bitmap.getRowBytes() * bitmap.getHeight();
              }
          }
      

      创建以上三个类后,您只需要像这样在 imageview 中加载图像:

      ImageLoader imageLoader = new ImageLoader(activity);
                  imageLoader.DisplayImage(bean.getPhotoURL(),holder.imgSelectedPhoto);
      

      【讨论】:

      • 感谢您的回答,我会尽快关注的
      • 加载和缓存图像是一个低级操作。一般来说,在应用程序中嵌入低级代码是非常错误的。
      【解决方案4】:

      您能否提供“快速”(如 0.1 秒)的定量测​​量?你可以很容易地做到这一点 -

      Intent intent = new Intent(this, NewActivity.class);
      intent.putExtra("BitmapImage", bitmap);
      

      并将其检索为 -

      Intent intent = getIntent();
      Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
      

      【讨论】:

      • 正确。问题是我有大量照片,转换为位图是一个昂贵的过程。我应该尝试转换 onClick 但这可能会失去我正在寻找的“速度”。目前我的加载大约需要 2 秒,我希望保持在 0.5 以内
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-30
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多