Android 如何在毕加索中使用磁盘缓存?
我正在使用毕加索在我的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
/**
* 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不可用,则不会加载图像
问题:
- 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
}