Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何在毕加索中使用磁盘缓存?_Android_Image_Caching_Picasso - Fatal编程技术网

Android 如何在毕加索中使用磁盘缓存?

Android 如何在毕加索中使用磁盘缓存?,android,image,caching,picasso,Android,Image,Caching,Picasso,我正在使用毕加索在我的android应用程序中显示图像: /** * load image.This is within a activity so this context is activity */ public void loadImage (){ Picasso picasso = Picasso.with(this); picasso.setDebugging(true); picasso.load(quiz.getImageUrl()).into(quiz

我正在使用毕加索在我的android应用程序中显示图像:

/**
* load image.This is within a activity so this context is activity
*/
public void loadImage (){
    Picasso picasso = Picasso.with(this); 
    picasso.setDebugging(true);
    picasso.load(quiz.getImageUrl()).into(quizImage);
}
我启用了调试,它总是显示红色和绿色,但从不显示黄色

现在,如果我下次加载相同的图像,而internet不可用,则不会加载图像

问题:

  • 它没有本地磁盘缓存吗
  • 如何启用磁盘缓存,因为我将多次使用同一映像
  • 我需要向android清单文件添加一些磁盘权限吗
  • 1)第一个问题的答案: 据

    with()返回的全局默认毕加索实例将使用适用于大多数实现的默认值自动初始化

    • LRU内存缓存为可用应用程序RAM的15%
    • 2%存储空间的磁盘缓存,最高50MB,但不低于5MB
    但是
    磁盘缓存
    全局默认毕加索操作仅在API 14上可用+

    2)第二个问题的答案:
    Picasso
    使用
    HTTP
    客户端请求
    Disk Cache
    操作,这样您就可以使用
    max age
    创建自己的
    HTTP请求头
    具有属性
    缓存控制
    并使用创建自己的静态毕加索实例,而不是默认的毕加索实例

    1] (注:仅适用于API 13+)
    2] (适用于所有API)

    使用
    OkHttpClient
    创建自己的静态毕加索类的示例

    • 首先创建一个新类来获取您自己的singleton
      picasso
      对象

      import android.content.Context;
      import com.squareup.picasso.Downloader;
      import com.squareup.picasso.OkHttpDownloader;
      import com.squareup.picasso.Picasso;
      
      public class PicassoCache {
      
          /**
           * Static Picasso Instance
           */
          private static Picasso picassoInstance = null;
      
          /**
           * PicassoCache Constructor
           *
           * @param context application Context
           */
          private PicassoCache (Context context) {
      
              Downloader downloader   = new OkHttpDownloader(context, Integer.MAX_VALUE);
              Picasso.Builder builder = new Picasso.Builder(context);
                  builder.downloader(downloader);
      
              picassoInstance = builder.build();
          }
      
          /**
           * Get Singleton Picasso Instance
           *
           * @param context application Context
           * @return Picasso instance
           */
          public static Picasso getPicassoInstance (Context context) {
      
              if (picassoInstance == null) {
      
                  new PicassoCache(context);
                  return picassoInstance;
              }
      
              return picassoInstance;
          }
      
      } 
      
    • 使用您自己的singleton
      picasso
      对象,而不是
      picasso.With()

    Picassoche.getPicassoInstance(getContext()).load(imagePath).into(imageView)

    3)回答第三个问题:磁盘缓存操作不需要任何磁盘权限


    参考资料:,两个问题已由->和回答,这就是我所做的。效果很好

    首先将OkHttp添加到应用程序模块的gradle构建文件中:

    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.10.0'
    compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
    
    然后创建一个扩展
    应用程序的类

    import android.app.Application;
    
    import com.jakewharton.picasso.OkHttp3Downloader;
    import com.squareup.picasso.Picasso;
    
    public class Global extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
    
            Picasso.Builder builder = new Picasso.Builder(this);
            builder.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE));
            Picasso built = builder.build();
            built.setIndicatorsEnabled(true);
            built.setLoggingEnabled(true);
            Picasso.setSingletonInstance(built);
    
        }
    }
    
    将其添加到清单文件,如下所示:

    <application
            android:name=".Global"
            .. >
    
    </application>
    
    编辑#2

    上面代码的问题是,如果清除缓存,毕加索将继续在缓存中脱机查找它并失败,下面的代码示例将查看本地缓存,如果未脱机查找,它将联机并补充缓存

    Picasso.with(getActivity())
    .load(imageUrl)
    .networkPolicy(NetworkPolicy.OFFLINE)
    .into(imageView, new Callback() {
        @Override
        public void onSuccess() {
    
        }
    
        @Override
        public void onError() {
            //Try again online if cache failed
            Picasso.with(getActivity())
                    .load(posts.get(position).getImageUrl())
                    .error(R.drawable.header)
                    .into(imageView, new Callback() {
                @Override
                public void onSuccess() {
    
                }
    
                @Override
                public void onError() {
                    Log.v("Picasso","Could not fetch image");
                }
            });
        }
    });
    

    对于缓存,我将使用OkHttp拦截器来控制缓存策略。查看OkHttp库中包含的此示例

    下面是我如何使用它与毕加索-

    OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.networkInterceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response originalResponse = chain.proceed(chain.request());
                return originalResponse.newBuilder().header("Cache-Control", "max-age=" + (60 * 60 * 24 * 365)).build();
            }
        });
    
        okHttpClient.setCache(new Cache(mainActivity.getCacheDir(), Integer.MAX_VALUE));
        OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
        Picasso picasso = new Picasso.Builder(mainActivity).downloader(okHttpDownloader).build();
        picasso.load(imageURL).into(viewHolder.image);
    
    1) 默认情况下,毕加索有缓存(参见ahmed hamdy答案)

    2) 如果您确实必须从磁盘缓存和网络中获取映像,我建议您编写自己的下载程序:

    public class OkHttpDownloaderDiskCacheFirst extends OkHttpDownloader {
        public OkHttpDownloaderDiskCacheFirst(OkHttpClient client) {
            super(client);
        }
    
        @Override
        public Response load(Uri uri, int networkPolicy) throws IOException {
            Response responseDiskCache = null;
            try {
                responseDiskCache = super.load(uri, 1 << 2); //NetworkPolicy.OFFLINE
            } catch (Exception ignored){} // ignore, handle null later
    
            if (responseDiskCache == null || responseDiskCache.getContentLength()<=0){
                return  super.load(uri, networkPolicy); //user normal policy
            } else {
                return responseDiskCache;
            }
    
        }
    }
    

    3) defalut应用程序缓存文件夹不需要任何权限

    我使用此代码并工作,可能对您有用:

    public static void makeImageRequest(final View parentView,final int id, final String imageUrl) {
    
        final int defaultImageResId = R.mipmap.user;
        final ImageView imageView = (ImageView) parentView.findViewById(id);
        Picasso.with(context)
                .load(imageUrl)
                .networkPolicy(NetworkPolicy.OFFLINE)
                .into(imageView, new Callback() {
                    @Override
                    public void onSuccess() {
                    Log.v("Picasso","fetch image success in first time.");
                    }
    
                    @Override
                    public void onError() {
                        //Try again online if cache failed
                        Log.v("Picasso","Could not fetch image in first time...");
                        Picasso.with(context).load(imageUrl).networkPolicy(NetworkPolicy.NO_CACHE)
                                .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).error(defaultImageResId)
                                .into(imageView, new Callback() {
    
                                    @Override
                                    public void onSuccess() {
                                        Log.v("Picasso","fetch image success in try again.");
                                    }
    
                                    @Override
                                    public void onError() {
                                      Log.v("Picasso","Could not fetch image again...");
                                    }
    
                                });
                    }
                });
    
    }
    

    应用程序中添加以下代码。一旦创建
    则正常使用

        Picasso picasso = new Picasso.Builder(context)
                .downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
                .build();
        picasso.setIndicatorsEnabled(true);
        picasso.setLoggingEnabled(true);
        Picasso.setSingletonInstance(picasso);
    
    如果先缓存图像,请在
    ProductImageDownloader.doBackground

    final Callback callback = new Callback() {
                @Override
                public void onSuccess() {
                    downLatch.countDown();
                    updateProgress();
                }
    
                @Override
                public void onError() {
                    errorCount++;
                    downLatch.countDown();
                    updateProgress();
                }
            };
            Picasso.with(context).load(Constants.imagesUrl+productModel.getGalleryImage())
                    .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
            Picasso.with(context).load(Constants.imagesUrl+productModel.getLeftImage())
                    .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
            Picasso.with(context).load(Constants.imagesUrl+productModel.getRightImage())
                    .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
    
            try {
                downLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            if(errorCount == 0){
                products.remove(productModel);
                productModel.isDownloaded = true;
                productsDatasource.updateElseInsert(productModel);
            }else {
                //error occurred while downloading images for this product
                //ignore error for now
                // FIXME: 9/27/2017 handle error
                products.remove(productModel);
    
            }
            errorCount = 0;
            downLatch = new CountDownLatch(3);
    
            if(!products.isEmpty() /*&& testCount++ < 30*/){
                startDownloading(products.get(0));
            }else {
                //all products with images are downloaded
                publishProgress(100);
            }
    
    注:

    红色颜色表示图像是从网络获取的

    绿色颜色表示图像是从缓存中获取的

    蓝色表示图像是从磁盘存储器中获取的


    在发布应用程序之前,请删除或将其设置为
    false
    picasso.setLoggingEnabled(true)
    picasso.SetIndicatorEnabled(真)如果不需要。Thankx

    我也遇到了同样的问题,于是改用Glide库。缓存是开箱即用的。

    获取最新版本2.71828 这是你的答案

    Q1:它没有本地磁盘缓存吗

    A1:毕加索内部有默认缓存,请求流如下所示

    App -> Memory -> Disk -> Server
    
    无论他们在哪里首先遇到他们的映像,他们都会使用该映像,然后停止请求流。 那么响应流呢?别担心,在这儿

    Server -> Disk -> Memory -> App
    
    默认情况下,它们将首先存储到本地磁盘中,用于扩展保留缓存。然后是内存,用于缓存的实例使用

    Picasso.with(getActivity())
    .load(imageUrl)
    .networkPolicy(NetworkPolicy.OFFLINE)
    .into(imageView, new Callback() {
        @Override
        public void onSuccess() {
    
        }
    
        @Override
        public void onError() {
            //Try again online if cache failed
            Picasso.with(getActivity())
                    .load(posts.get(position).getImageUrl())
                    .error(R.drawable.header)
                    .into(imageView, new Callback() {
                @Override
                public void onSuccess() {
    
                }
    
                @Override
                public void onError() {
                    Log.v("Picasso","Could not fetch image");
                }
            });
        }
    });
    
    通过启用此功能,可以使用毕加索的内置指示器查看图像的形成位置

    Picasso.get().setIndicatorEnabled(true);
    
    它将在您的图片左上角显示一面旗帜

    • 红色标志表示图像来自服务器。(首次加载时没有缓存)
    • 蓝色标志表示照片来自本地磁盘。(缓存)
    • 绿色标志表示图像来自内存。(实例缓存)
    Q2:我将多次使用同一映像,如何启用磁盘缓存

    A2:您不必启用它。这是默认值

    当您希望图像始终保持新鲜时,您需要做的是禁用它。有两种禁用缓存的方式

  • .memoryPolicy()
    设置为无缓存和/或无存储,流将如下所示
  • 没有缓存会跳过从内存中查找图像

    App -> Disk -> Server
    
    首次加载图像时,NO_STORE将跳过内存中的图像存储

    Server -> Disk -> App
    
    Server -> Memory -> App
    
  • .networkPolicy()
    设置为“无缓存”和/或“无存储”,流将如下所示
  • 没有缓存会跳过从磁盘查找图像

    App -> Memory -> Server
    
    首次加载图像时,NO_STORE将跳过磁盘中的存储图像

    Server -> Disk -> App
    
    Server -> Memory -> App
    
    对于完全不缓存图像,您可以禁用这两种功能。这里有一个例子

    Picasso.get().load(imageUrl)
                 .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
                 .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
                 .fit().into(banner);
    
    完全无缓存和无存储的流程如下所示

    App -> Server //Request
    
    Server -> App //Response
    
    因此,您可能还需要此功能来减少应用程序存储使用量

    Q3:我需要向android manifes添加一些磁盘权限吗
    public void loadImage (){
    Picasso picasso = Picasso.get(); 
    picasso.setIndicatorsEnabled(true);
    picasso.load(quiz.getImageUrl()).into(quizImage);
    }
    
    Bitmap bitmap = Picasso.get().load(quiz.getImageUrl()).get();
    
    Thread thread = new Thread() {
     public void run() {
     File file = new File(getCacheDir() + "/" +member.getMemberId() + ".jpg");
    
    try {
          Bitmap bitmap = Picasso.get().load(uri).get();
          FileOutputStream fOut = new FileOutputStream(file);                                        
          bitmap.compress(Bitmap.CompressFormat.JPEG, 100,new FileOutputStream(file));
    fOut.flush();
    fOut.close();
        }
    catch (Exception e) {
      e.printStackTrace();
        }
       }
    };
         thread.start();
      })
    
    
    List<File> files = new LinkedList<>(Arrays.asList(context.getExternalCacheDir().listFiles()));
    
    for(File file : files){
                    if(file.getName().equals("fileyouarelookingfor" + ".jpg")){ // you need the name of the file, for example you are storing user image and the his image name is same as his id , you can call getId() on user to get the file name
                        Picasso.get() // if file found then load it
                                .load(file)
                                .into(mThumbnailImage);
                        return; // return 
                    }
            // fetch it over the internet here because the file is not found
           }